118334Speter/* Convert RTL to assembler code and output it, for GNU compiler.
290087Sobrien   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
3169699Skan   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
4169699Skan   Free Software Foundation, Inc.
518334Speter
690087SobrienThis file is part of GCC.
718334Speter
890087SobrienGCC is free software; you can redistribute it and/or modify it under
990087Sobrienthe terms of the GNU General Public License as published by the Free
1090087SobrienSoftware Foundation; either version 2, or (at your option) any later
1190087Sobrienversion.
1218334Speter
1390087SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1490087SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1590087SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1690087Sobrienfor more details.
1718334Speter
1818334SpeterYou should have received a copy of the GNU General Public License
1990087Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
20169699SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
21169699Skan02110-1301, USA.  */
2218334Speter
2318334Speter/* This is the final pass of the compiler.
2418334Speter   It looks at the rtl code for a function and outputs assembler code.
2518334Speter
2618334Speter   Call `final_start_function' to output the assembler code for function entry,
2718334Speter   `final' to output assembler code for some RTL code,
2818334Speter   `final_end_function' to output assembler code for function exit.
2918334Speter   If a function is compiled in several pieces, each piece is
3018334Speter   output separately with `final'.
3118334Speter
3218334Speter   Some optimizations are also done at this level.
3318334Speter   Move instructions that were made unnecessary by good register allocation
3418334Speter   are detected and omitted from the output.  (Though most of these
3518334Speter   are removed by the last jump pass.)
3618334Speter
3718334Speter   Instructions to set the condition codes are omitted when it can be
3818334Speter   seen that the condition codes already had the desired values.
3918334Speter
4018334Speter   In some cases it is sufficient if the inherited condition codes
4118334Speter   have related values, but this may require the following insn
4218334Speter   (the one that tests the condition codes) to be modified.
4318334Speter
4418334Speter   The code for the function prologue and epilogue are generated
4590087Sobrien   directly in assembler by the target functions function_prologue and
4690087Sobrien   function_epilogue.  Those instructions never exist as rtl.  */
4718334Speter
4818334Speter#include "config.h"
4950503Sobrien#include "system.h"
50132727Skan#include "coretypes.h"
51132727Skan#include "tm.h"
5218334Speter
5318334Speter#include "tree.h"
5418334Speter#include "rtl.h"
5590087Sobrien#include "tm_p.h"
5618334Speter#include "regs.h"
5718334Speter#include "insn-config.h"
5818334Speter#include "insn-attr.h"
5918334Speter#include "recog.h"
6018334Speter#include "conditions.h"
6118334Speter#include "flags.h"
6218334Speter#include "real.h"
6318334Speter#include "hard-reg-set.h"
6418334Speter#include "output.h"
6550503Sobrien#include "except.h"
6690087Sobrien#include "function.h"
6750503Sobrien#include "toplev.h"
6850503Sobrien#include "reload.h"
6952515Sobrien#include "intl.h"
7090087Sobrien#include "basic-block.h"
7190087Sobrien#include "target.h"
7290087Sobrien#include "debug.h"
7390087Sobrien#include "expr.h"
74117404Skan#include "cfglayout.h"
75169699Skan#include "tree-pass.h"
76169699Skan#include "timevar.h"
77169699Skan#include "cgraph.h"
78169699Skan#include "coverage.h"
7918334Speter
8018334Speter#ifdef XCOFF_DEBUGGING_INFO
8190087Sobrien#include "xcoffout.h"		/* Needed for external data
8290087Sobrien				   declarations for e.g. AIX 4.x.  */
8318334Speter#endif
8418334Speter
8550503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
8650503Sobrien#include "dwarf2out.h"
8750503Sobrien#endif
8850503Sobrien
89132727Skan#ifdef DBX_DEBUGGING_INFO
90132727Skan#include "dbxout.h"
91132727Skan#endif
92132727Skan
93169699Skan#ifdef SDB_DEBUGGING_INFO
94169699Skan#include "sdbout.h"
95169699Skan#endif
96169699Skan
9718334Speter/* If we aren't using cc0, CC_STATUS_INIT shouldn't exist.  So define a
9818334Speter   null default for it to save conditionalization later.  */
9918334Speter#ifndef CC_STATUS_INIT
10018334Speter#define CC_STATUS_INIT
10118334Speter#endif
10218334Speter
10318334Speter/* How to start an assembler comment.  */
10418334Speter#ifndef ASM_COMMENT_START
10518334Speter#define ASM_COMMENT_START ";#"
10618334Speter#endif
10718334Speter
10818334Speter/* Is the given character a logical line separator for the assembler?  */
10918334Speter#ifndef IS_ASM_LOGICAL_LINE_SEPARATOR
11018334Speter#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';')
11118334Speter#endif
11218334Speter
11350503Sobrien#ifndef JUMP_TABLES_IN_TEXT_SECTION
11450503Sobrien#define JUMP_TABLES_IN_TEXT_SECTION 0
11550503Sobrien#endif
11650503Sobrien
117132727Skan/* Bitflags used by final_scan_insn.  */
118132727Skan#define SEEN_BB		1
119132727Skan#define SEEN_NOTE	2
120132727Skan#define SEEN_EMITTED	4
121132727Skan
12218334Speter/* Last insn processed by final_scan_insn.  */
12390087Sobrienstatic rtx debug_insn;
12490087Sobrienrtx current_output_insn;
12518334Speter
12618334Speter/* Line number of last NOTE.  */
12718334Speterstatic int last_linenum;
12818334Speter
12918334Speter/* Highest line number in current block.  */
13018334Speterstatic int high_block_linenum;
13118334Speter
13218334Speter/* Likewise for function.  */
13318334Speterstatic int high_function_linenum;
13418334Speter
13518334Speter/* Filename of last NOTE.  */
13690087Sobrienstatic const char *last_filename;
13718334Speter
138169699Skan/* Whether to force emission of a line note before the next insn.  */
139169699Skanstatic bool force_source_line = false;
14050503Sobrien
141169699Skanextern const int length_unit_log; /* This is defined in insn-attrtab.c.  */
142169699Skan
14318334Speter/* Nonzero while outputting an `asm' with operands.
144169699Skan   This means that inconsistencies are the user's fault, so don't die.
14518334Speter   The precise value is the insn being output, to pass to error_for_asm.  */
146117404Skanrtx this_is_asm_operands;
14718334Speter
14818334Speter/* Number of operands of this insn, for an `asm' with operands.  */
14950503Sobrienstatic unsigned int insn_noperands;
15018334Speter
15118334Speter/* Compare optimization flag.  */
15218334Speter
15318334Speterstatic rtx last_ignored_compare = 0;
15418334Speter
15518334Speter/* Assign a unique number to each insn that is output.
15618334Speter   This can be used to generate unique local labels.  */
15718334Speter
15818334Speterstatic int insn_counter = 0;
15918334Speter
16018334Speter#ifdef HAVE_cc0
16118334Speter/* This variable contains machine-dependent flags (defined in tm.h)
16218334Speter   set and examined by output routines
16318334Speter   that describe how to interpret the condition codes properly.  */
16418334Speter
16518334SpeterCC_STATUS cc_status;
16618334Speter
16718334Speter/* During output of an insn, this contains a copy of cc_status
16818334Speter   from before the insn.  */
16918334Speter
17018334SpeterCC_STATUS cc_prev_status;
17118334Speter#endif
17218334Speter
17318334Speter/* Indexed by hardware reg number, is 1 if that register is ever
17418334Speter   used in the current function.
17518334Speter
17618334Speter   In life_analysis, or in stupid_life_analysis, this is set
17718334Speter   up to record the hard regs used explicitly.  Reload adds
17818334Speter   in the hard regs used for holding pseudo regs.  Final uses
17918334Speter   it to generate the code in the function prologue and epilogue
18018334Speter   to save and restore registers as needed.  */
18118334Speter
18218334Speterchar regs_ever_live[FIRST_PSEUDO_REGISTER];
18318334Speter
184132727Skan/* Like regs_ever_live, but 1 if a reg is set or clobbered from an asm.
185132727Skan   Unlike regs_ever_live, elements of this array corresponding to
186132727Skan   eliminable regs like the frame pointer are set if an asm sets them.  */
187132727Skan
188132727Skanchar regs_asm_clobbered[FIRST_PSEUDO_REGISTER];
189132727Skan
19018334Speter/* Nonzero means current function must be given a frame pointer.
191132727Skan   Initialized in function.c to 0.  Set only in reload1.c as per
192132727Skan   the needs of the function.  */
19318334Speter
19418334Speterint frame_pointer_needed;
19518334Speter
19690087Sobrien/* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen.  */
19718334Speter
19818334Speterstatic int block_depth;
19918334Speter
20018334Speter/* Nonzero if have enabled APP processing of our assembler output.  */
20118334Speter
20218334Speterstatic int app_on;
20318334Speter
20418334Speter/* If we are outputting an insn sequence, this contains the sequence rtx.
20518334Speter   Zero otherwise.  */
20618334Speter
20718334Speterrtx final_sequence;
20818334Speter
20918334Speter#ifdef ASSEMBLER_DIALECT
21018334Speter
21118334Speter/* Number of the assembler dialect to use, starting at 0.  */
21218334Speterstatic int dialect_number;
21318334Speter#endif
21418334Speter
21590087Sobrien#ifdef HAVE_conditional_execution
21690087Sobrien/* Nonnull if the insn currently being emitted was a COND_EXEC pattern.  */
21790087Sobrienrtx current_insn_predicate;
21890087Sobrien#endif
21918334Speter
22050503Sobrien#ifdef HAVE_ATTR_length
221132727Skanstatic int asm_insn_count (rtx);
22250503Sobrien#endif
223132727Skanstatic void profile_function (FILE *);
224132727Skanstatic void profile_after_prologue (FILE *);
225132727Skanstatic bool notice_source_line (rtx);
226132727Skanstatic rtx walk_alter_subreg (rtx *);
227132727Skanstatic void output_asm_name (void);
228132727Skanstatic void output_alternate_entry_point (FILE *, rtx);
229132727Skanstatic tree get_mem_expr_from_op (rtx, int *);
230132727Skanstatic void output_asm_operand_names (rtx *, int *, int);
231132727Skanstatic void output_operand (rtx, int);
23250503Sobrien#ifdef LEAF_REGISTERS
233132727Skanstatic void leaf_renumber_regs (rtx);
23450503Sobrien#endif
23550503Sobrien#ifdef HAVE_cc0
236132727Skanstatic int alter_cond (rtx);
23750503Sobrien#endif
23890087Sobrien#ifndef ADDR_VEC_ALIGN
239132727Skanstatic int final_addr_vec_align (rtx);
24090087Sobrien#endif
24190087Sobrien#ifdef HAVE_ATTR_length
242132727Skanstatic int align_fuzz (rtx, rtx, int, unsigned);
24390087Sobrien#endif
24418334Speter
24518334Speter/* Initialize data in final at the beginning of a compilation.  */
24618334Speter
24718334Spetervoid
248132727Skaninit_final (const char *filename ATTRIBUTE_UNUSED)
24918334Speter{
25018334Speter  app_on = 0;
25118334Speter  final_sequence = 0;
25218334Speter
25318334Speter#ifdef ASSEMBLER_DIALECT
25418334Speter  dialect_number = ASSEMBLER_DIALECT;
25518334Speter#endif
25618334Speter}
25718334Speter
25890087Sobrien/* Default target function prologue and epilogue assembler output.
25918334Speter
26090087Sobrien   If not overridden for epilogue code, then the function body itself
26190087Sobrien   contains return instructions wherever needed.  */
26290087Sobrienvoid
263132727Skandefault_function_pro_epilogue (FILE *file ATTRIBUTE_UNUSED,
264132727Skan			       HOST_WIDE_INT size ATTRIBUTE_UNUSED)
26590087Sobrien{
26690087Sobrien}
26718334Speter
26890087Sobrien/* Default target hook that outputs nothing to a stream.  */
26990087Sobrienvoid
270132727Skanno_asm_to_stream (FILE *file ATTRIBUTE_UNUSED)
27190087Sobrien{
27218334Speter}
27318334Speter
27418334Speter/* Enable APP processing of subsequent output.
27518334Speter   Used before the output from an `asm' statement.  */
27618334Speter
27718334Spetervoid
278132727Skanapp_enable (void)
27918334Speter{
28018334Speter  if (! app_on)
28118334Speter    {
28250503Sobrien      fputs (ASM_APP_ON, asm_out_file);
28318334Speter      app_on = 1;
28418334Speter    }
28518334Speter}
28618334Speter
28718334Speter/* Disable APP processing of subsequent output.
28818334Speter   Called from varasm.c before most kinds of output.  */
28918334Speter
29018334Spetervoid
291132727Skanapp_disable (void)
29218334Speter{
29318334Speter  if (app_on)
29418334Speter    {
29550503Sobrien      fputs (ASM_APP_OFF, asm_out_file);
29618334Speter      app_on = 0;
29718334Speter    }
29818334Speter}
29918334Speter
30090087Sobrien/* Return the number of slots filled in the current
30118334Speter   delayed branch sequence (we don't count the insn needing the
30218334Speter   delay slot).   Zero if not in a delayed branch sequence.  */
30318334Speter
30418334Speter#ifdef DELAY_SLOTS
30518334Speterint
306132727Skandbr_sequence_length (void)
30718334Speter{
30818334Speter  if (final_sequence != 0)
30918334Speter    return XVECLEN (final_sequence, 0) - 1;
31018334Speter  else
31118334Speter    return 0;
31218334Speter}
31318334Speter#endif
31418334Speter
31518334Speter/* The next two pages contain routines used to compute the length of an insn
31618334Speter   and to shorten branches.  */
31718334Speter
31818334Speter/* Arrays for insn lengths, and addresses.  The latter is referenced by
31918334Speter   `insn_current_length'.  */
32018334Speter
32190087Sobrienstatic int *insn_lengths;
32218334Speter
32390087Sobrienvarray_type insn_addresses_;
32490087Sobrien
32552515Sobrien/* Max uid for which the above arrays are valid.  */
32652515Sobrienstatic int insn_lengths_max_uid;
32752515Sobrien
32818334Speter/* Address of insn being processed.  Used by `insn_current_length'.  */
32918334Speterint insn_current_address;
33018334Speter
33150503Sobrien/* Address of insn being processed in previous iteration.  */
33250503Sobrienint insn_last_address;
33350503Sobrien
33490087Sobrien/* known invariant alignment of insn being processed.  */
33550503Sobrienint insn_current_align;
33650503Sobrien
33750503Sobrien/* After shorten_branches, for any insn, uid_align[INSN_UID (insn)]
33850503Sobrien   gives the next following alignment insn that increases the known
33950503Sobrien   alignment, or NULL_RTX if there is no such insn.
34050503Sobrien   For any alignment obtained this way, we can again index uid_align with
34150503Sobrien   its uid to obtain the next following align that in turn increases the
34250503Sobrien   alignment, till we reach NULL_RTX; the sequence obtained this way
34350503Sobrien   for each insn we'll call the alignment chain of this insn in the following
34450503Sobrien   comments.  */
34550503Sobrien
346260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
347260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
34850503Sobrienstatic rtx *uid_align;
34950503Sobrienstatic int *uid_shuid;
350260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
35150503Sobrien
352260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
353260919Spfg
35418334Speter/* Indicate that branch shortening hasn't yet been done.  */
35518334Speter
35618334Spetervoid
357132727Skaninit_insn_lengths (void)
35818334Speter{
35950503Sobrien  if (uid_shuid)
36050503Sobrien    {
36150503Sobrien      free (uid_shuid);
36250503Sobrien      uid_shuid = 0;
36350503Sobrien    }
36450503Sobrien  if (insn_lengths)
36550503Sobrien    {
36650503Sobrien      free (insn_lengths);
36750503Sobrien      insn_lengths = 0;
36852515Sobrien      insn_lengths_max_uid = 0;
36950503Sobrien    }
37090087Sobrien#ifdef HAVE_ATTR_length
37190087Sobrien  INSN_ADDRESSES_FREE ();
37290087Sobrien#endif
37350503Sobrien  if (uid_align)
37450503Sobrien    {
37550503Sobrien      free (uid_align);
37650503Sobrien      uid_align = 0;
37750503Sobrien    }
37818334Speter}
37918334Speter
38018334Speter/* Obtain the current length of an insn.  If branch shortening has been done,
381169699Skan   get its actual length.  Otherwise, use FALLBACK_FN to calculate the
382169699Skan   length.  */
383169699Skanstatic inline int
384169699Skanget_attr_length_1 (rtx insn ATTRIBUTE_UNUSED,
385169699Skan		   int (*fallback_fn) (rtx) ATTRIBUTE_UNUSED)
38618334Speter{
38718334Speter#ifdef HAVE_ATTR_length
38818334Speter  rtx body;
38918334Speter  int i;
39018334Speter  int length = 0;
39118334Speter
39252515Sobrien  if (insn_lengths_max_uid > INSN_UID (insn))
39318334Speter    return insn_lengths[INSN_UID (insn)];
39418334Speter  else
39518334Speter    switch (GET_CODE (insn))
39618334Speter      {
39718334Speter      case NOTE:
39818334Speter      case BARRIER:
39918334Speter      case CODE_LABEL:
40018334Speter	return 0;
40118334Speter
40218334Speter      case CALL_INSN:
403169699Skan	length = fallback_fn (insn);
40418334Speter	break;
40518334Speter
40618334Speter      case JUMP_INSN:
40718334Speter	body = PATTERN (insn);
408117404Skan	if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
40918334Speter	  {
41050503Sobrien	    /* Alignment is machine-dependent and should be handled by
41150503Sobrien	       ADDR_VEC_ALIGN.  */
41218334Speter	  }
41318334Speter	else
414169699Skan	  length = fallback_fn (insn);
41518334Speter	break;
41618334Speter
41718334Speter      case INSN:
41818334Speter	body = PATTERN (insn);
41918334Speter	if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER)
42018334Speter	  return 0;
42118334Speter
42218334Speter	else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
423169699Skan	  length = asm_insn_count (body) * fallback_fn (insn);
42418334Speter	else if (GET_CODE (body) == SEQUENCE)
42518334Speter	  for (i = 0; i < XVECLEN (body, 0); i++)
42618334Speter	    length += get_attr_length (XVECEXP (body, 0, i));
42718334Speter	else
428169699Skan	  length = fallback_fn (insn);
42950503Sobrien	break;
43050503Sobrien
43150503Sobrien      default:
43250503Sobrien	break;
43318334Speter      }
43418334Speter
43518334Speter#ifdef ADJUST_INSN_LENGTH
43618334Speter  ADJUST_INSN_LENGTH (insn, length);
43718334Speter#endif
43818334Speter  return length;
43918334Speter#else /* not HAVE_ATTR_length */
44018334Speter  return 0;
441169699Skan#define insn_default_length 0
442169699Skan#define insn_min_length 0
44318334Speter#endif /* not HAVE_ATTR_length */
44418334Speter}
445169699Skan
446169699Skan/* Obtain the current length of an insn.  If branch shortening has been done,
447169699Skan   get its actual length.  Otherwise, get its maximum length.  */
448169699Skanint
449169699Skanget_attr_length (rtx insn)
450169699Skan{
451169699Skan  return get_attr_length_1 (insn, insn_default_length);
452169699Skan}
453169699Skan
454169699Skan/* Obtain the current length of an insn.  If branch shortening has been done,
455169699Skan   get its actual length.  Otherwise, get its minimum length.  */
456169699Skanint
457169699Skanget_attr_min_length (rtx insn)
458169699Skan{
459169699Skan  return get_attr_length_1 (insn, insn_min_length);
460169699Skan}
46118334Speter
46250503Sobrien/* Code to handle alignment inside shorten_branches.  */
46350503Sobrien
46450503Sobrien/* Here is an explanation how the algorithm in align_fuzz can give
46550503Sobrien   proper results:
46650503Sobrien
46750503Sobrien   Call a sequence of instructions beginning with alignment point X
46850503Sobrien   and continuing until the next alignment point `block X'.  When `X'
46990087Sobrien   is used in an expression, it means the alignment value of the
47050503Sobrien   alignment point.
47190087Sobrien
47250503Sobrien   Call the distance between the start of the first insn of block X, and
47350503Sobrien   the end of the last insn of block X `IX', for the `inner size of X'.
47450503Sobrien   This is clearly the sum of the instruction lengths.
47590087Sobrien
47650503Sobrien   Likewise with the next alignment-delimited block following X, which we
47750503Sobrien   shall call block Y.
47890087Sobrien
47950503Sobrien   Call the distance between the start of the first insn of block X, and
48050503Sobrien   the start of the first insn of block Y `OX', for the `outer size of X'.
48190087Sobrien
48250503Sobrien   The estimated padding is then OX - IX.
48390087Sobrien
48450503Sobrien   OX can be safely estimated as
48590087Sobrien
48650503Sobrien           if (X >= Y)
48750503Sobrien                   OX = round_up(IX, Y)
48850503Sobrien           else
48950503Sobrien                   OX = round_up(IX, X) + Y - X
49090087Sobrien
49150503Sobrien   Clearly est(IX) >= real(IX), because that only depends on the
49250503Sobrien   instruction lengths, and those being overestimated is a given.
49390087Sobrien
49450503Sobrien   Clearly round_up(foo, Z) >= round_up(bar, Z) if foo >= bar, so
49550503Sobrien   we needn't worry about that when thinking about OX.
49690087Sobrien
49750503Sobrien   When X >= Y, the alignment provided by Y adds no uncertainty factor
49850503Sobrien   for branch ranges starting before X, so we can just round what we have.
49950503Sobrien   But when X < Y, we don't know anything about the, so to speak,
50050503Sobrien   `middle bits', so we have to assume the worst when aligning up from an
50150503Sobrien   address mod X to one mod Y, which is Y - X.  */
50250503Sobrien
50350503Sobrien#ifndef LABEL_ALIGN
50490087Sobrien#define LABEL_ALIGN(LABEL) align_labels_log
50550503Sobrien#endif
50650503Sobrien
50750503Sobrien#ifndef LABEL_ALIGN_MAX_SKIP
50890087Sobrien#define LABEL_ALIGN_MAX_SKIP align_labels_max_skip
50950503Sobrien#endif
51050503Sobrien
51150503Sobrien#ifndef LOOP_ALIGN
51290087Sobrien#define LOOP_ALIGN(LABEL) align_loops_log
51350503Sobrien#endif
51450503Sobrien
51550503Sobrien#ifndef LOOP_ALIGN_MAX_SKIP
51690087Sobrien#define LOOP_ALIGN_MAX_SKIP align_loops_max_skip
51750503Sobrien#endif
51850503Sobrien
51950503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER
52050503Sobrien#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0
52150503Sobrien#endif
52250503Sobrien
52350503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP
52450503Sobrien#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0
52550503Sobrien#endif
52650503Sobrien
52790087Sobrien#ifndef JUMP_ALIGN
52890087Sobrien#define JUMP_ALIGN(LABEL) align_jumps_log
52990087Sobrien#endif
53090087Sobrien
53190087Sobrien#ifndef JUMP_ALIGN_MAX_SKIP
53290087Sobrien#define JUMP_ALIGN_MAX_SKIP align_jumps_max_skip
53390087Sobrien#endif
53490087Sobrien
53550503Sobrien#ifndef ADDR_VEC_ALIGN
53690087Sobrienstatic int
537132727Skanfinal_addr_vec_align (rtx addr_vec)
53850503Sobrien{
53990087Sobrien  int align = GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec)));
54050503Sobrien
54150503Sobrien  if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
54250503Sobrien    align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
54390087Sobrien  return exact_log2 (align);
54450503Sobrien
54550503Sobrien}
54690087Sobrien
54750503Sobrien#define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC)
54850503Sobrien#endif
54950503Sobrien
55050503Sobrien#ifndef INSN_LENGTH_ALIGNMENT
55150503Sobrien#define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log
55250503Sobrien#endif
55350503Sobrien
55450503Sobrien#define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)])
55550503Sobrien
556260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
557260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
55850503Sobrien/* For the benefit of port specific code do this also as a function.  */
55990087Sobrien
56050503Sobrienint
561132727Skanlabel_to_alignment (rtx label)
56250503Sobrien{
563260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
564260919Spfg  return LABEL_ALIGN_LOG (label);
565260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
56650503Sobrien}
56750503Sobrien
56850503Sobrien#ifdef HAVE_ATTR_length
56950503Sobrien/* The differences in addresses
57050503Sobrien   between a branch and its target might grow or shrink depending on
57150503Sobrien   the alignment the start insn of the range (the branch for a forward
57250503Sobrien   branch or the label for a backward branch) starts out on; if these
57350503Sobrien   differences are used naively, they can even oscillate infinitely.
57450503Sobrien   We therefore want to compute a 'worst case' address difference that
57550503Sobrien   is independent of the alignment the start insn of the range end
57650503Sobrien   up on, and that is at least as large as the actual difference.
57750503Sobrien   The function align_fuzz calculates the amount we have to add to the
57850503Sobrien   naively computed difference, by traversing the part of the alignment
57950503Sobrien   chain of the start insn of the range that is in front of the end insn
58050503Sobrien   of the range, and considering for each alignment the maximum amount
58150503Sobrien   that it might contribute to a size increase.
58250503Sobrien
58350503Sobrien   For casesi tables, we also want to know worst case minimum amounts of
58450503Sobrien   address difference, in case a machine description wants to introduce
58550503Sobrien   some common offset that is added to all offsets in a table.
58690087Sobrien   For this purpose, align_fuzz with a growth argument of 0 computes the
58750503Sobrien   appropriate adjustment.  */
58850503Sobrien
58950503Sobrien/* Compute the maximum delta by which the difference of the addresses of
59050503Sobrien   START and END might grow / shrink due to a different address for start
59150503Sobrien   which changes the size of alignment insns between START and END.
59250503Sobrien   KNOWN_ALIGN_LOG is the alignment known for START.
59350503Sobrien   GROWTH should be ~0 if the objective is to compute potential code size
59450503Sobrien   increase, and 0 if the objective is to compute potential shrink.
59550503Sobrien   The return value is undefined for any other value of GROWTH.  */
59690087Sobrien
59790087Sobrienstatic int
598132727Skanalign_fuzz (rtx start, rtx end, int known_align_log, unsigned int growth)
59950503Sobrien{
60050503Sobrien  int uid = INSN_UID (start);
60150503Sobrien  rtx align_label;
60250503Sobrien  int known_align = 1 << known_align_log;
60350503Sobrien  int end_shuid = INSN_SHUID (end);
60450503Sobrien  int fuzz = 0;
60550503Sobrien
60650503Sobrien  for (align_label = uid_align[uid]; align_label; align_label = uid_align[uid])
60750503Sobrien    {
60850503Sobrien      int align_addr, new_align;
60950503Sobrien
61050503Sobrien      uid = INSN_UID (align_label);
61190087Sobrien      align_addr = INSN_ADDRESSES (uid) - insn_lengths[uid];
61250503Sobrien      if (uid_shuid[uid] > end_shuid)
61350503Sobrien	break;
614260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
615260919Spfg      known_align_log = LABEL_ALIGN_LOG (align_label);
616260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
61750503Sobrien      new_align = 1 << known_align_log;
61850503Sobrien      if (new_align < known_align)
61950503Sobrien	continue;
62050503Sobrien      fuzz += (-align_addr ^ growth) & (new_align - known_align);
62150503Sobrien      known_align = new_align;
62250503Sobrien    }
62350503Sobrien  return fuzz;
62450503Sobrien}
62550503Sobrien
62650503Sobrien/* Compute a worst-case reference address of a branch so that it
62750503Sobrien   can be safely used in the presence of aligned labels.  Since the
62850503Sobrien   size of the branch itself is unknown, the size of the branch is
62950503Sobrien   not included in the range.  I.e. for a forward branch, the reference
63050503Sobrien   address is the end address of the branch as known from the previous
63150503Sobrien   branch shortening pass, minus a value to account for possible size
63250503Sobrien   increase due to alignment.  For a backward branch, it is the start
63350503Sobrien   address of the branch as known from the current pass, plus a value
63450503Sobrien   to account for possible size increase due to alignment.
63550503Sobrien   NB.: Therefore, the maximum offset allowed for backward branches needs
63650503Sobrien   to exclude the branch size.  */
63790087Sobrien
63850503Sobrienint
639132727Skaninsn_current_reference_address (rtx branch)
64050503Sobrien{
64190087Sobrien  rtx dest, seq;
64290087Sobrien  int seq_uid;
64390087Sobrien
64490087Sobrien  if (! INSN_ADDRESSES_SET_P ())
64590087Sobrien    return 0;
64690087Sobrien
64790087Sobrien  seq = NEXT_INSN (PREV_INSN (branch));
64890087Sobrien  seq_uid = INSN_UID (seq);
649169699Skan  if (!JUMP_P (branch))
65050503Sobrien    /* This can happen for example on the PA; the objective is to know the
65150503Sobrien       offset to address something in front of the start of the function.
65250503Sobrien       Thus, we can treat it like a backward branch.
65350503Sobrien       We assume here that FUNCTION_BOUNDARY / BITS_PER_UNIT is larger than
65450503Sobrien       any alignment we'd encounter, so we skip the call to align_fuzz.  */
65550503Sobrien    return insn_current_address;
65650503Sobrien  dest = JUMP_LABEL (branch);
65790087Sobrien
65890087Sobrien  /* BRANCH has no proper alignment chain set, so use SEQ.
65990087Sobrien     BRANCH also has no INSN_SHUID.  */
66090087Sobrien  if (INSN_SHUID (seq) < INSN_SHUID (dest))
66150503Sobrien    {
66290087Sobrien      /* Forward branch.  */
66350503Sobrien      return (insn_last_address + insn_lengths[seq_uid]
66450503Sobrien	      - align_fuzz (seq, dest, length_unit_log, ~0));
66550503Sobrien    }
66650503Sobrien  else
66750503Sobrien    {
66890087Sobrien      /* Backward branch.  */
66950503Sobrien      return (insn_current_address
67050503Sobrien	      + align_fuzz (dest, seq, length_unit_log, ~0));
67150503Sobrien    }
67250503Sobrien}
67350503Sobrien#endif /* HAVE_ATTR_length */
67450503Sobrien
675169699Skan/* Compute branch alignments based on frequency information in the
676169699Skan   CFG.  */
677169699Skan
678169699Skanstatic unsigned int
679132727Skancompute_alignments (void)
68090087Sobrien{
681260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
682260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
683117404Skan  basic_block bb;
68490087Sobrien
685260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
686260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
68790087Sobrien
68890087Sobrien  /* If not optimizing or optimizing for size, don't assign any alignments.  */
68990087Sobrien  if (! optimize || optimize_size)
690169699Skan    return 0;
69190087Sobrien
692117404Skan  FOR_EACH_BB (bb)
69390087Sobrien    {
694132727Skan      rtx label = BB_HEAD (bb);
69590087Sobrien      int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0;
69690087Sobrien      edge e;
697169699Skan      edge_iterator ei;
698260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
699260919Spfg      int log, max_skip, max_log;
70090087Sobrien
701260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
702169699Skan      if (!LABEL_P (label)
703132727Skan	  || probably_never_executed_bb_p (bb))
70490087Sobrien	continue;
705260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
706260919Spfg      /* If user has specified an alignment, honour it.  */
707260919Spfg      if (LABEL_ALIGN_LOG (label) > 0)
708260919Spfg	continue;
709260919Spfg
710260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
71190087Sobrien      max_log = LABEL_ALIGN (label);
71290087Sobrien      max_skip = LABEL_ALIGN_MAX_SKIP;
71390087Sobrien
714169699Skan      FOR_EACH_EDGE (e, ei, bb->preds)
71590087Sobrien	{
71690087Sobrien	  if (e->flags & EDGE_FALLTHRU)
71790087Sobrien	    has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e);
71890087Sobrien	  else
71990087Sobrien	    branch_frequency += EDGE_FREQUENCY (e);
72090087Sobrien	}
72190087Sobrien
72290087Sobrien      /* There are two purposes to align block with no fallthru incoming edge:
72390087Sobrien	 1) to avoid fetch stalls when branch destination is near cache boundary
72490087Sobrien	 2) to improve cache efficiency in case the previous block is not executed
72590087Sobrien	    (so it does not need to be in the cache).
72690087Sobrien
72790087Sobrien	 We to catch first case, we align frequently executed blocks.
72890087Sobrien	 To catch the second, we align blocks that are executed more frequently
72990087Sobrien	 than the predecessor and the predecessor is likely to not be executed
73090087Sobrien	 when function is called.  */
73190087Sobrien
73290087Sobrien      if (!has_fallthru
73390087Sobrien	  && (branch_frequency > BB_FREQ_MAX / 10
734117404Skan	      || (bb->frequency > bb->prev_bb->frequency * 10
735117404Skan		  && (bb->prev_bb->frequency
73690087Sobrien		      <= ENTRY_BLOCK_PTR->frequency / 2))))
73790087Sobrien	{
73890087Sobrien	  log = JUMP_ALIGN (label);
73990087Sobrien	  if (max_log < log)
74090087Sobrien	    {
74190087Sobrien	      max_log = log;
74290087Sobrien	      max_skip = JUMP_ALIGN_MAX_SKIP;
74390087Sobrien	    }
74490087Sobrien	}
74590087Sobrien      /* In case block is frequent and reached mostly by non-fallthru edge,
746117404Skan	 align it.  It is most likely a first block of loop.  */
74790087Sobrien      if (has_fallthru
748132727Skan	  && maybe_hot_bb_p (bb)
74990087Sobrien	  && branch_frequency + fallthru_frequency > BB_FREQ_MAX / 10
750117404Skan	  && branch_frequency > fallthru_frequency * 2)
75190087Sobrien	{
75290087Sobrien	  log = LOOP_ALIGN (label);
75390087Sobrien	  if (max_log < log)
75490087Sobrien	    {
75590087Sobrien	      max_log = log;
75690087Sobrien	      max_skip = LOOP_ALIGN_MAX_SKIP;
75790087Sobrien	    }
75890087Sobrien	}
759260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
760260919Spfg      SET_LABEL_ALIGN (label, max_log, max_skip);
761260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
76290087Sobrien    }
763169699Skan  return 0;
76490087Sobrien}
765169699Skan
766169699Skanstruct tree_opt_pass pass_compute_alignments =
767169699Skan{
768169699Skan  NULL,                                 /* name */
769169699Skan  NULL,                                 /* gate */
770169699Skan  compute_alignments,                   /* execute */
771169699Skan  NULL,                                 /* sub */
772169699Skan  NULL,                                 /* next */
773169699Skan  0,                                    /* static_pass_number */
774169699Skan  0,                                    /* tv_id */
775169699Skan  0,                                    /* properties_required */
776169699Skan  0,                                    /* properties_provided */
777169699Skan  0,                                    /* properties_destroyed */
778169699Skan  0,                                    /* todo_flags_start */
779169699Skan  0,                                    /* todo_flags_finish */
780169699Skan  0                                     /* letter */
781169699Skan};
782169699Skan
78390087Sobrien
78418334Speter/* Make a pass over all insns and compute their actual lengths by shortening
78518334Speter   any branches of variable length if possible.  */
78618334Speter
78750503Sobrien/* shorten_branches might be called multiple times:  for example, the SH
78850503Sobrien   port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG.
78950503Sobrien   In order to do this, it needs proper length information, which it obtains
79050503Sobrien   by calling shorten_branches.  This cannot be collapsed with
79190087Sobrien   shorten_branches itself into a single pass unless we also want to integrate
79250503Sobrien   reorg.c, since the branch splitting exposes new instructions with delay
79350503Sobrien   slots.  */
79450503Sobrien
79518334Spetervoid
796132727Skanshorten_branches (rtx first ATTRIBUTE_UNUSED)
79718334Speter{
79850503Sobrien  rtx insn;
79950503Sobrien  int max_uid;
80050503Sobrien  int i;
80150503Sobrien  int max_log;
80250503Sobrien  int max_skip;
80318334Speter#ifdef HAVE_ATTR_length
80450503Sobrien#define MAX_CODE_ALIGN 16
80550503Sobrien  rtx seq;
80618334Speter  int something_changed = 1;
80718334Speter  char *varying_length;
80818334Speter  rtx body;
80918334Speter  int uid;
81050503Sobrien  rtx align_tab[MAX_CODE_ALIGN];
81118334Speter
81250503Sobrien#endif
81318334Speter
814260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
815260919Spfg  /* Compute maximum UID and allocate uid_shuid.  */
816260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
81750503Sobrien  max_uid = get_max_uid ();
81850503Sobrien
819169699Skan  /* Free uid_shuid before reallocating it.  */
820169699Skan  free (uid_shuid);
82150503Sobrien
822169699Skan  uid_shuid = XNEWVEC (int, max_uid);
823169699Skan
824260919Spfg  /* APPLE LOCAL for-fsf-4_4 3274130 5295549 */ \
825260919Spfg  /* Initialize set up uid_shuid to be strictly
82650503Sobrien     monotonically rising with insn order.  */
82750503Sobrien  /* We use max_log here to keep track of the maximum alignment we want to
82850503Sobrien     impose on the next CODE_LABEL (or the current one if we are processing
82950503Sobrien     the CODE_LABEL itself).  */
83090087Sobrien
83150503Sobrien  max_log = 0;
83250503Sobrien  max_skip = 0;
83350503Sobrien
83450503Sobrien  for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn))
83550503Sobrien    {
83650503Sobrien      int log;
83750503Sobrien
83850503Sobrien      INSN_SHUID (insn) = i++;
83990087Sobrien      if (INSN_P (insn))
840169699Skan	continue;
841169699Skan
842169699Skan      if (LABEL_P (insn))
84350503Sobrien	{
84450503Sobrien	  rtx next;
84550503Sobrien
84690087Sobrien	  /* Merge in alignments computed by compute_alignments.  */
847260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
848260919Spfg	  log = LABEL_ALIGN_LOG (insn);
849260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
85090087Sobrien	  if (max_log < log)
85190087Sobrien	    {
85290087Sobrien	      max_log = log;
853260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
854260919Spfg	      max_skip = LABEL_MAX_SKIP (insn);
855260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
85690087Sobrien	    }
85790087Sobrien
85850503Sobrien	  log = LABEL_ALIGN (insn);
85950503Sobrien	  if (max_log < log)
86050503Sobrien	    {
86150503Sobrien	      max_log = log;
86250503Sobrien	      max_skip = LABEL_ALIGN_MAX_SKIP;
86350503Sobrien	    }
864169699Skan	  next = next_nonnote_insn (insn);
86550503Sobrien	  /* ADDR_VECs only take room if read-only data goes into the text
86650503Sobrien	     section.  */
867169699Skan	  if (JUMP_TABLES_IN_TEXT_SECTION
868169699Skan	      || readonly_data_section == text_section)
869169699Skan	    if (next && JUMP_P (next))
87050503Sobrien	      {
87150503Sobrien		rtx nextbody = PATTERN (next);
87250503Sobrien		if (GET_CODE (nextbody) == ADDR_VEC
87350503Sobrien		    || GET_CODE (nextbody) == ADDR_DIFF_VEC)
87450503Sobrien		  {
87550503Sobrien		    log = ADDR_VEC_ALIGN (next);
87650503Sobrien		    if (max_log < log)
87750503Sobrien		      {
87850503Sobrien			max_log = log;
87950503Sobrien			max_skip = LABEL_ALIGN_MAX_SKIP;
88050503Sobrien		      }
88150503Sobrien		  }
88250503Sobrien	      }
883260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
884260919Spfg	  SET_LABEL_ALIGN (insn, max_log, max_skip);
885260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
88650503Sobrien	  max_log = 0;
88750503Sobrien	  max_skip = 0;
88850503Sobrien	}
889169699Skan      else if (BARRIER_P (insn))
89050503Sobrien	{
89150503Sobrien	  rtx label;
89250503Sobrien
89390087Sobrien	  for (label = insn; label && ! INSN_P (label);
89450503Sobrien	       label = NEXT_INSN (label))
895169699Skan	    if (LABEL_P (label))
89650503Sobrien	      {
89750503Sobrien		log = LABEL_ALIGN_AFTER_BARRIER (insn);
89850503Sobrien		if (max_log < log)
89950503Sobrien		  {
90050503Sobrien		    max_log = log;
90150503Sobrien		    max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP;
90250503Sobrien		  }
90350503Sobrien		break;
90450503Sobrien	      }
90550503Sobrien	}
90650503Sobrien    }
90750503Sobrien#ifdef HAVE_ATTR_length
90850503Sobrien
90950503Sobrien  /* Allocate the rest of the arrays.  */
910169699Skan  insn_lengths = XNEWVEC (int, max_uid);
91152515Sobrien  insn_lengths_max_uid = max_uid;
91250503Sobrien  /* Syntax errors can lead to labels being outside of the main insn stream.
91350503Sobrien     Initialize insn_addresses, so that we get reproducible results.  */
91490087Sobrien  INSN_ADDRESSES_ALLOC (max_uid);
91550503Sobrien
916169699Skan  varying_length = XCNEWVEC (char, max_uid);
91750503Sobrien
91850503Sobrien  /* Initialize uid_align.  We scan instructions
91950503Sobrien     from end to start, and keep in align_tab[n] the last seen insn
92050503Sobrien     that does an alignment of at least n+1, i.e. the successor
92150503Sobrien     in the alignment chain for an insn that does / has a known
92250503Sobrien     alignment of n.  */
923169699Skan  uid_align = XCNEWVEC (rtx, max_uid);
92450503Sobrien
92590087Sobrien  for (i = MAX_CODE_ALIGN; --i >= 0;)
92650503Sobrien    align_tab[i] = NULL_RTX;
92750503Sobrien  seq = get_last_insn ();
92850503Sobrien  for (; seq; seq = PREV_INSN (seq))
92950503Sobrien    {
93050503Sobrien      int uid = INSN_UID (seq);
93150503Sobrien      int log;
932260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
933260919Spfg      log = (LABEL_P (seq) ? LABEL_ALIGN_LOG (seq) : 0);
934260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
93550503Sobrien      uid_align[uid] = align_tab[0];
93650503Sobrien      if (log)
93750503Sobrien	{
93850503Sobrien	  /* Found an alignment label.  */
93950503Sobrien	  uid_align[uid] = align_tab[log];
94050503Sobrien	  for (i = log - 1; i >= 0; i--)
94150503Sobrien	    align_tab[i] = seq;
94250503Sobrien	}
94350503Sobrien    }
94450503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE
94550503Sobrien  if (optimize)
94650503Sobrien    {
94750503Sobrien      /* Look for ADDR_DIFF_VECs, and initialize their minimum and maximum
94850503Sobrien         label fields.  */
94950503Sobrien
95050503Sobrien      int min_shuid = INSN_SHUID (get_insns ()) - 1;
95150503Sobrien      int max_shuid = INSN_SHUID (get_last_insn ()) + 1;
95250503Sobrien      int rel;
95350503Sobrien
95450503Sobrien      for (insn = first; insn != 0; insn = NEXT_INSN (insn))
95550503Sobrien	{
95650503Sobrien	  rtx min_lab = NULL_RTX, max_lab = NULL_RTX, pat;
95750503Sobrien	  int len, i, min, max, insn_shuid;
95850503Sobrien	  int min_align;
95950503Sobrien	  addr_diff_vec_flags flags;
96050503Sobrien
961169699Skan	  if (!JUMP_P (insn)
96250503Sobrien	      || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
96350503Sobrien	    continue;
96450503Sobrien	  pat = PATTERN (insn);
96550503Sobrien	  len = XVECLEN (pat, 1);
966169699Skan	  gcc_assert (len > 0);
96750503Sobrien	  min_align = MAX_CODE_ALIGN;
96850503Sobrien	  for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--)
96950503Sobrien	    {
97050503Sobrien	      rtx lab = XEXP (XVECEXP (pat, 1, i), 0);
97150503Sobrien	      int shuid = INSN_SHUID (lab);
97250503Sobrien	      if (shuid < min)
97350503Sobrien		{
97450503Sobrien		  min = shuid;
97550503Sobrien		  min_lab = lab;
97650503Sobrien		}
97750503Sobrien	      if (shuid > max)
97850503Sobrien		{
97950503Sobrien		  max = shuid;
98050503Sobrien		  max_lab = lab;
98150503Sobrien		}
982260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
983260919Spfg	      if (min_align > (int) LABEL_ALIGN_LOG (lab))
984260919Spfg		min_align = LABEL_ALIGN_LOG (lab);
985260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
98650503Sobrien	    }
987169699Skan	  XEXP (pat, 2) = gen_rtx_LABEL_REF (Pmode, min_lab);
988169699Skan	  XEXP (pat, 3) = gen_rtx_LABEL_REF (Pmode, max_lab);
98950503Sobrien	  insn_shuid = INSN_SHUID (insn);
99050503Sobrien	  rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0));
991169699Skan	  memset (&flags, 0, sizeof (flags));
99250503Sobrien	  flags.min_align = min_align;
99350503Sobrien	  flags.base_after_vec = rel > insn_shuid;
99450503Sobrien	  flags.min_after_vec  = min > insn_shuid;
99550503Sobrien	  flags.max_after_vec  = max > insn_shuid;
99650503Sobrien	  flags.min_after_base = min > rel;
99750503Sobrien	  flags.max_after_base = max > rel;
99850503Sobrien	  ADDR_DIFF_VEC_FLAGS (pat) = flags;
99950503Sobrien	}
100050503Sobrien    }
100150503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */
100250503Sobrien
100318334Speter  /* Compute initial lengths, addresses, and varying flags for each insn.  */
1004132727Skan  for (insn_current_address = 0, insn = first;
100518334Speter       insn != 0;
100618334Speter       insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
100718334Speter    {
100818334Speter      uid = INSN_UID (insn);
100950503Sobrien
101050503Sobrien      insn_lengths[uid] = 0;
101150503Sobrien
1012169699Skan      if (LABEL_P (insn))
101350503Sobrien	{
1014260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
1015260919Spfg	  int log = LABEL_ALIGN_LOG (insn);
1016260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
101750503Sobrien	  if (log)
101850503Sobrien	    {
101950503Sobrien	      int align = 1 << log;
102050503Sobrien	      int new_address = (insn_current_address + align - 1) & -align;
102150503Sobrien	      insn_lengths[uid] = new_address - insn_current_address;
102250503Sobrien	    }
102350503Sobrien	}
102450503Sobrien
1025117404Skan      INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid];
102690087Sobrien
1027169699Skan      if (NOTE_P (insn) || BARRIER_P (insn)
1028169699Skan	  || LABEL_P (insn))
102918334Speter	continue;
103050503Sobrien      if (INSN_DELETED_P (insn))
103150503Sobrien	continue;
103218334Speter
103318334Speter      body = PATTERN (insn);
103418334Speter      if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
103518334Speter	{
103618334Speter	  /* This only takes room if read-only data goes into the text
103718334Speter	     section.  */
1038169699Skan	  if (JUMP_TABLES_IN_TEXT_SECTION
1039169699Skan	      || readonly_data_section == text_section)
104050503Sobrien	    insn_lengths[uid] = (XVECLEN (body,
104150503Sobrien					  GET_CODE (body) == ADDR_DIFF_VEC)
104250503Sobrien				 * GET_MODE_SIZE (GET_MODE (body)));
104350503Sobrien	  /* Alignment is handled by ADDR_VEC_ALIGN.  */
104418334Speter	}
104590087Sobrien      else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
104618334Speter	insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn);
104718334Speter      else if (GET_CODE (body) == SEQUENCE)
104818334Speter	{
104918334Speter	  int i;
105018334Speter	  int const_delay_slots;
105118334Speter#ifdef DELAY_SLOTS
105218334Speter	  const_delay_slots = const_num_delay_slots (XVECEXP (body, 0, 0));
105318334Speter#else
105418334Speter	  const_delay_slots = 0;
105518334Speter#endif
105618334Speter	  /* Inside a delay slot sequence, we do not do any branch shortening
105718334Speter	     if the shortening could change the number of delay slots
105850503Sobrien	     of the branch.  */
105918334Speter	  for (i = 0; i < XVECLEN (body, 0); i++)
106018334Speter	    {
106118334Speter	      rtx inner_insn = XVECEXP (body, 0, i);
106218334Speter	      int inner_uid = INSN_UID (inner_insn);
106318334Speter	      int inner_length;
106418334Speter
106590087Sobrien	      if (GET_CODE (body) == ASM_INPUT
106690087Sobrien		  || asm_noperands (PATTERN (XVECEXP (body, 0, i))) >= 0)
106718334Speter		inner_length = (asm_insn_count (PATTERN (inner_insn))
106818334Speter				* insn_default_length (inner_insn));
106918334Speter	      else
107018334Speter		inner_length = insn_default_length (inner_insn);
107190087Sobrien
107218334Speter	      insn_lengths[inner_uid] = inner_length;
107318334Speter	      if (const_delay_slots)
107418334Speter		{
107518334Speter		  if ((varying_length[inner_uid]
107618334Speter		       = insn_variable_length_p (inner_insn)) != 0)
107718334Speter		    varying_length[uid] = 1;
107890087Sobrien		  INSN_ADDRESSES (inner_uid) = (insn_current_address
107990087Sobrien						+ insn_lengths[uid]);
108018334Speter		}
108118334Speter	      else
108218334Speter		varying_length[inner_uid] = 0;
108318334Speter	      insn_lengths[uid] += inner_length;
108418334Speter	    }
108518334Speter	}
108618334Speter      else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER)
108718334Speter	{
108818334Speter	  insn_lengths[uid] = insn_default_length (insn);
108918334Speter	  varying_length[uid] = insn_variable_length_p (insn);
109018334Speter	}
109118334Speter
109218334Speter      /* If needed, do any adjustment.  */
109318334Speter#ifdef ADJUST_INSN_LENGTH
109418334Speter      ADJUST_INSN_LENGTH (insn, insn_lengths[uid]);
109552515Sobrien      if (insn_lengths[uid] < 0)
109690087Sobrien	fatal_insn ("negative insn length", insn);
109718334Speter#endif
109818334Speter    }
109918334Speter
110018334Speter  /* Now loop over all the insns finding varying length insns.  For each,
110118334Speter     get the current insn length.  If it has changed, reflect the change.
110218334Speter     When nothing changes for a full pass, we are done.  */
110318334Speter
110418334Speter  while (something_changed)
110518334Speter    {
110618334Speter      something_changed = 0;
110750503Sobrien      insn_current_align = MAX_CODE_ALIGN - 1;
1108132727Skan      for (insn_current_address = 0, insn = first;
110918334Speter	   insn != 0;
111018334Speter	   insn = NEXT_INSN (insn))
111118334Speter	{
111218334Speter	  int new_length;
111350503Sobrien#ifdef ADJUST_INSN_LENGTH
111418334Speter	  int tmp_length;
111550503Sobrien#endif
111650503Sobrien	  int length_align;
111718334Speter
111818334Speter	  uid = INSN_UID (insn);
111950503Sobrien
1120169699Skan	  if (LABEL_P (insn))
112150503Sobrien	    {
1122260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
1123260919Spfg	      int log = LABEL_ALIGN_LOG (insn);
1124260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
112550503Sobrien	      if (log > insn_current_align)
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		  insn_current_align = log;
113150503Sobrien		  insn_current_address = new_address;
113250503Sobrien		}
113350503Sobrien	      else
113450503Sobrien		insn_lengths[uid] = 0;
113590087Sobrien	      INSN_ADDRESSES (uid) = insn_current_address;
113650503Sobrien	      continue;
113750503Sobrien	    }
113850503Sobrien
113950503Sobrien	  length_align = INSN_LENGTH_ALIGNMENT (insn);
114050503Sobrien	  if (length_align < insn_current_align)
114150503Sobrien	    insn_current_align = length_align;
114250503Sobrien
114390087Sobrien	  insn_last_address = INSN_ADDRESSES (uid);
114490087Sobrien	  INSN_ADDRESSES (uid) = insn_current_address;
114550503Sobrien
114650503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE
1147169699Skan	  if (optimize && JUMP_P (insn)
114850503Sobrien	      && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
114918334Speter	    {
115050503Sobrien	      rtx body = PATTERN (insn);
115150503Sobrien	      int old_length = insn_lengths[uid];
115250503Sobrien	      rtx rel_lab = XEXP (XEXP (body, 0), 0);
115350503Sobrien	      rtx min_lab = XEXP (XEXP (body, 2), 0);
115450503Sobrien	      rtx max_lab = XEXP (XEXP (body, 3), 0);
115590087Sobrien	      int rel_addr = INSN_ADDRESSES (INSN_UID (rel_lab));
115690087Sobrien	      int min_addr = INSN_ADDRESSES (INSN_UID (min_lab));
115790087Sobrien	      int max_addr = INSN_ADDRESSES (INSN_UID (max_lab));
115850503Sobrien	      rtx prev;
115950503Sobrien	      int rel_align = 0;
116090087Sobrien	      addr_diff_vec_flags flags;
116150503Sobrien
116290087Sobrien	      /* Avoid automatic aggregate initialization.  */
116390087Sobrien	      flags = ADDR_DIFF_VEC_FLAGS (body);
116490087Sobrien
116550503Sobrien	      /* Try to find a known alignment for rel_lab.  */
116650503Sobrien	      for (prev = rel_lab;
116750503Sobrien		   prev
116850503Sobrien		   && ! insn_lengths[INSN_UID (prev)]
116950503Sobrien		   && ! (varying_length[INSN_UID (prev)] & 1);
117050503Sobrien		   prev = PREV_INSN (prev))
117150503Sobrien		if (varying_length[INSN_UID (prev)] & 2)
117250503Sobrien		  {
1173260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
1174260919Spfg		    rel_align = LABEL_ALIGN_LOG (prev);
1175260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
117650503Sobrien		    break;
117750503Sobrien		  }
117850503Sobrien
117950503Sobrien	      /* See the comment on addr_diff_vec_flags in rtl.h for the
118050503Sobrien		 meaning of the flags values.  base: REL_LAB   vec: INSN  */
118150503Sobrien	      /* Anything after INSN has still addresses from the last
118250503Sobrien		 pass; adjust these so that they reflect our current
118350503Sobrien		 estimate for this pass.  */
118450503Sobrien	      if (flags.base_after_vec)
118550503Sobrien		rel_addr += insn_current_address - insn_last_address;
118650503Sobrien	      if (flags.min_after_vec)
118750503Sobrien		min_addr += insn_current_address - insn_last_address;
118850503Sobrien	      if (flags.max_after_vec)
118950503Sobrien		max_addr += insn_current_address - insn_last_address;
119050503Sobrien	      /* We want to know the worst case, i.e. lowest possible value
119150503Sobrien		 for the offset of MIN_LAB.  If MIN_LAB is after REL_LAB,
119250503Sobrien		 its offset is positive, and we have to be wary of code shrink;
119350503Sobrien		 otherwise, it is negative, and we have to be vary of code
119450503Sobrien		 size increase.  */
119550503Sobrien	      if (flags.min_after_base)
119650503Sobrien		{
119750503Sobrien		  /* If INSN is between REL_LAB and MIN_LAB, the size
119850503Sobrien		     changes we are about to make can change the alignment
119950503Sobrien		     within the observed offset, therefore we have to break
120050503Sobrien		     it up into two parts that are independent.  */
120150503Sobrien		  if (! flags.base_after_vec && flags.min_after_vec)
120250503Sobrien		    {
120350503Sobrien		      min_addr -= align_fuzz (rel_lab, insn, rel_align, 0);
120450503Sobrien		      min_addr -= align_fuzz (insn, min_lab, 0, 0);
120550503Sobrien		    }
120650503Sobrien		  else
120750503Sobrien		    min_addr -= align_fuzz (rel_lab, min_lab, rel_align, 0);
120850503Sobrien		}
120950503Sobrien	      else
121050503Sobrien		{
121150503Sobrien		  if (flags.base_after_vec && ! flags.min_after_vec)
121250503Sobrien		    {
121350503Sobrien		      min_addr -= align_fuzz (min_lab, insn, 0, ~0);
121450503Sobrien		      min_addr -= align_fuzz (insn, rel_lab, 0, ~0);
121550503Sobrien		    }
121650503Sobrien		  else
121750503Sobrien		    min_addr -= align_fuzz (min_lab, rel_lab, 0, ~0);
121850503Sobrien		}
121950503Sobrien	      /* Likewise, determine the highest lowest possible value
122050503Sobrien		 for the offset of MAX_LAB.  */
122150503Sobrien	      if (flags.max_after_base)
122250503Sobrien		{
122350503Sobrien		  if (! flags.base_after_vec && flags.max_after_vec)
122450503Sobrien		    {
122550503Sobrien		      max_addr += align_fuzz (rel_lab, insn, rel_align, ~0);
122650503Sobrien		      max_addr += align_fuzz (insn, max_lab, 0, ~0);
122750503Sobrien		    }
122850503Sobrien		  else
122950503Sobrien		    max_addr += align_fuzz (rel_lab, max_lab, rel_align, ~0);
123050503Sobrien		}
123150503Sobrien	      else
123250503Sobrien		{
123350503Sobrien		  if (flags.base_after_vec && ! flags.max_after_vec)
123450503Sobrien		    {
123550503Sobrien		      max_addr += align_fuzz (max_lab, insn, 0, 0);
123650503Sobrien		      max_addr += align_fuzz (insn, rel_lab, 0, 0);
123750503Sobrien		    }
123850503Sobrien		  else
123950503Sobrien		    max_addr += align_fuzz (max_lab, rel_lab, 0, 0);
124050503Sobrien		}
124150503Sobrien	      PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
124250503Sobrien							max_addr - rel_addr,
124350503Sobrien							body));
1244169699Skan	      if (JUMP_TABLES_IN_TEXT_SECTION
1245169699Skan		  || readonly_data_section == text_section)
124650503Sobrien		{
124750503Sobrien		  insn_lengths[uid]
124850503Sobrien		    = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body)));
124950503Sobrien		  insn_current_address += insn_lengths[uid];
125050503Sobrien		  if (insn_lengths[uid] != old_length)
125150503Sobrien		    something_changed = 1;
125250503Sobrien		}
125350503Sobrien
125450503Sobrien	      continue;
125550503Sobrien	    }
125650503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */
125750503Sobrien
125850503Sobrien	  if (! (varying_length[uid]))
125950503Sobrien	    {
1260169699Skan	      if (NONJUMP_INSN_P (insn)
126190087Sobrien		  && GET_CODE (PATTERN (insn)) == SEQUENCE)
126290087Sobrien		{
126390087Sobrien		  int i;
126490087Sobrien
126590087Sobrien		  body = PATTERN (insn);
126690087Sobrien		  for (i = 0; i < XVECLEN (body, 0); i++)
126790087Sobrien		    {
126890087Sobrien		      rtx inner_insn = XVECEXP (body, 0, i);
126990087Sobrien		      int inner_uid = INSN_UID (inner_insn);
127090087Sobrien
127190087Sobrien		      INSN_ADDRESSES (inner_uid) = insn_current_address;
127290087Sobrien
127390087Sobrien		      insn_current_address += insn_lengths[inner_uid];
127490087Sobrien		    }
1275117404Skan		}
127690087Sobrien	      else
127790087Sobrien		insn_current_address += insn_lengths[uid];
127890087Sobrien
127918334Speter	      continue;
128018334Speter	    }
128190087Sobrien
1282169699Skan	  if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
128318334Speter	    {
128418334Speter	      int i;
128590087Sobrien
128618334Speter	      body = PATTERN (insn);
128718334Speter	      new_length = 0;
128818334Speter	      for (i = 0; i < XVECLEN (body, 0); i++)
128918334Speter		{
129018334Speter		  rtx inner_insn = XVECEXP (body, 0, i);
129118334Speter		  int inner_uid = INSN_UID (inner_insn);
129218334Speter		  int inner_length;
129318334Speter
129490087Sobrien		  INSN_ADDRESSES (inner_uid) = insn_current_address;
129518334Speter
129618334Speter		  /* insn_current_length returns 0 for insns with a
129718334Speter		     non-varying length.  */
129818334Speter		  if (! varying_length[inner_uid])
129918334Speter		    inner_length = insn_lengths[inner_uid];
130018334Speter		  else
130118334Speter		    inner_length = insn_current_length (inner_insn);
130218334Speter
130318334Speter		  if (inner_length != insn_lengths[inner_uid])
130418334Speter		    {
130518334Speter		      insn_lengths[inner_uid] = inner_length;
130618334Speter		      something_changed = 1;
130718334Speter		    }
130818334Speter		  insn_current_address += insn_lengths[inner_uid];
130918334Speter		  new_length += inner_length;
131018334Speter		}
131118334Speter	    }
131218334Speter	  else
131318334Speter	    {
131418334Speter	      new_length = insn_current_length (insn);
131518334Speter	      insn_current_address += new_length;
131618334Speter	    }
131718334Speter
131818334Speter#ifdef ADJUST_INSN_LENGTH
131918334Speter	  /* If needed, do any adjustment.  */
132018334Speter	  tmp_length = new_length;
132118334Speter	  ADJUST_INSN_LENGTH (insn, new_length);
132218334Speter	  insn_current_address += (new_length - tmp_length);
132318334Speter#endif
132418334Speter
132518334Speter	  if (new_length != insn_lengths[uid])
132618334Speter	    {
132718334Speter	      insn_lengths[uid] = new_length;
132818334Speter	      something_changed = 1;
132918334Speter	    }
133018334Speter	}
133118334Speter      /* For a non-optimizing compile, do only a single pass.  */
133218334Speter      if (!optimize)
133318334Speter	break;
133418334Speter    }
133550503Sobrien
133650503Sobrien  free (varying_length);
133750503Sobrien
133818334Speter#endif /* HAVE_ATTR_length */
133918334Speter}
134018334Speter
134118334Speter#ifdef HAVE_ATTR_length
134218334Speter/* Given the body of an INSN known to be generated by an ASM statement, return
134318334Speter   the number of machine instructions likely to be generated for this insn.
134418334Speter   This is used to compute its length.  */
134518334Speter
134618334Speterstatic int
1347132727Skanasm_insn_count (rtx body)
134818334Speter{
134990087Sobrien  const char *template;
135018334Speter  int count = 1;
135118334Speter
135218334Speter  if (GET_CODE (body) == ASM_INPUT)
135318334Speter    template = XSTR (body, 0);
135418334Speter  else
135590087Sobrien    template = decode_asm_operands (body, NULL, NULL, NULL, NULL);
135618334Speter
135790087Sobrien  for (; *template; template++)
135890087Sobrien    if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n')
135918334Speter      count++;
136018334Speter
136118334Speter  return count;
136218334Speter}
136318334Speter#endif
136418334Speter
136518334Speter/* Output assembler code for the start of a function,
136618334Speter   and initialize some of the variables in this file
136718334Speter   for the new function.  The label for the function and associated
136818334Speter   assembler pseudo-ops have already been output in `assemble_start_function'.
136918334Speter
137018334Speter   FIRST is the first insn of the rtl for the function being compiled.
137118334Speter   FILE is the file to write assembler code to.
137218334Speter   OPTIMIZE is nonzero if we should eliminate redundant
137318334Speter     test and compare insns.  */
137418334Speter
137518334Spetervoid
1376132727Skanfinal_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
1377132727Skan		      int optimize ATTRIBUTE_UNUSED)
137818334Speter{
137918334Speter  block_depth = 0;
138018334Speter
138118334Speter  this_is_asm_operands = 0;
138218334Speter
1383132727Skan  last_filename = locator_file (prologue_locator);
1384132727Skan  last_linenum = locator_line (prologue_locator);
138518334Speter
138690087Sobrien  high_block_linenum = high_function_linenum = last_linenum;
138718334Speter
138890087Sobrien  (*debug_hooks->begin_prologue) (last_linenum, last_filename);
138950503Sobrien
1390169699Skan#if defined (DWARF2_UNWIND_INFO) || defined (TARGET_UNWIND_INFO)
139190087Sobrien  if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG)
139290087Sobrien    dwarf2out_begin_prologue (0, NULL);
139318334Speter#endif
139418334Speter
139518334Speter#ifdef LEAF_REG_REMAP
139652515Sobrien  if (current_function_uses_only_leaf_regs)
139718334Speter    leaf_renumber_regs (first);
139818334Speter#endif
139918334Speter
140018334Speter  /* The Sun386i and perhaps other machines don't work right
140118334Speter     if the profiling code comes after the prologue.  */
140218334Speter#ifdef PROFILE_BEFORE_PROLOGUE
140390087Sobrien  if (current_function_profile)
140418334Speter    profile_function (file);
140518334Speter#endif /* PROFILE_BEFORE_PROLOGUE */
140618334Speter
140750503Sobrien#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
140850503Sobrien  if (dwarf2out_do_frame ())
1409169699Skan    dwarf2out_frame_debug (NULL_RTX, false);
141050503Sobrien#endif
141150503Sobrien
141290087Sobrien  /* If debugging, assign block numbers to all of the blocks in this
141390087Sobrien     function.  */
141490087Sobrien  if (write_symbols)
141590087Sobrien    {
1416132727Skan      reemit_insn_block_notes ();
141790087Sobrien      number_blocks (current_function_decl);
141890087Sobrien      /* We never actually put out begin/end notes for the top-level
141990087Sobrien	 block in the function.  But, conceptually, that block is
142090087Sobrien	 always needed.  */
142190087Sobrien      TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
142290087Sobrien    }
142390087Sobrien
1424259406Spfg  if (warn_frame_larger_than
1425259406Spfg    && get_frame_size () > frame_larger_than_size)
1426259406Spfg  {
1427259406Spfg      /* Issue a warning */
1428259406Spfg      warning (OPT_Wframe_larger_than_,
1429259406Spfg               "the frame size of %wd bytes is larger than %wd bytes",
1430259406Spfg               get_frame_size (), frame_larger_than_size);
1431259406Spfg  }
1432259406Spfg
143318334Speter  /* First output the function prologue: code to set up the stack frame.  */
1434169699Skan  targetm.asm_out.function_prologue (file, get_frame_size ());
143518334Speter
143618334Speter  /* If the machine represents the prologue as RTL, the profiling code must
143718334Speter     be emitted when NOTE_INSN_PROLOGUE_END is scanned.  */
143818334Speter#ifdef HAVE_prologue
143918334Speter  if (! HAVE_prologue)
144018334Speter#endif
144118334Speter    profile_after_prologue (file);
144218334Speter}
144318334Speter
144418334Speterstatic void
1445132727Skanprofile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
144618334Speter{
144718334Speter#ifndef PROFILE_BEFORE_PROLOGUE
144890087Sobrien  if (current_function_profile)
144918334Speter    profile_function (file);
145018334Speter#endif /* not PROFILE_BEFORE_PROLOGUE */
145118334Speter}
145218334Speter
145318334Speterstatic void
1454132727Skanprofile_function (FILE *file ATTRIBUTE_UNUSED)
145518334Speter{
145674478Sobrien#ifndef NO_PROFILE_COUNTERS
1457132727Skan# define NO_PROFILE_COUNTERS	0
145874478Sobrien#endif
145950503Sobrien#if defined(ASM_OUTPUT_REG_PUSH)
146018334Speter  int sval = current_function_returns_struct;
1461132727Skan  rtx svrtx = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl), 1);
146250503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM)
1463169699Skan  int cxt = cfun->static_chain_decl != NULL;
146450503Sobrien#endif
146550503Sobrien#endif /* ASM_OUTPUT_REG_PUSH */
146618334Speter
1467132727Skan  if (! NO_PROFILE_COUNTERS)
1468132727Skan    {
1469132727Skan      int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
1470169699Skan      switch_to_section (data_section);
1471132727Skan      ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
1472169699Skan      targetm.asm_out.internal_label (file, "LP", current_function_funcdef_no);
1473132727Skan      assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
1474132727Skan    }
147518334Speter
1476169699Skan  switch_to_section (current_function_section ());
147718334Speter
1478132727Skan#if defined(ASM_OUTPUT_REG_PUSH)
1479169699Skan  if (sval && svrtx != NULL_RTX && REG_P (svrtx))
1480132727Skan    ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx));
148118334Speter#endif
148218334Speter
148350503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
148418334Speter  if (cxt)
148518334Speter    ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM);
148618334Speter#else
148750503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
148818334Speter  if (cxt)
148950503Sobrien    {
149050503Sobrien      ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM);
149150503Sobrien    }
149218334Speter#endif
149318334Speter#endif
149418334Speter
1495117404Skan  FUNCTION_PROFILER (file, current_function_funcdef_no);
149618334Speter
149750503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
149818334Speter  if (cxt)
149918334Speter    ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM);
150018334Speter#else
150150503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
150218334Speter  if (cxt)
150350503Sobrien    {
150450503Sobrien      ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM);
150550503Sobrien    }
150618334Speter#endif
150718334Speter#endif
150818334Speter
1509132727Skan#if defined(ASM_OUTPUT_REG_PUSH)
1510169699Skan  if (sval && svrtx != NULL_RTX && REG_P (svrtx))
1511132727Skan    ASM_OUTPUT_REG_POP (file, REGNO (svrtx));
151218334Speter#endif
151318334Speter}
151418334Speter
151518334Speter/* Output assembler code for the end of a function.
151618334Speter   For clarity, args are same as those of `final_start_function'
151718334Speter   even though not all of them are needed.  */
151818334Speter
151918334Spetervoid
1520132727Skanfinal_end_function (void)
152118334Speter{
152290087Sobrien  app_disable ();
152318334Speter
152490087Sobrien  (*debug_hooks->end_function) (high_function_linenum);
152518334Speter
152618334Speter  /* Finally, output the function epilogue:
152718334Speter     code to restore the stack frame and return to the caller.  */
1528169699Skan  targetm.asm_out.function_epilogue (asm_out_file, get_frame_size ());
152918334Speter
153090087Sobrien  /* And debug output.  */
1531117404Skan  (*debug_hooks->end_epilogue) (last_linenum, last_filename);
153290087Sobrien
153390087Sobrien#if defined (DWARF2_UNWIND_INFO)
153490087Sobrien  if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG
153590087Sobrien      && dwarf2out_do_frame ())
1536117404Skan    dwarf2out_end_epilogue (last_linenum, last_filename);
153750503Sobrien#endif
153818334Speter}
153918334Speter
154018334Speter/* Output assembler code for some insns: all or part of a function.
1541169699Skan   For description of args, see `final_start_function', above.  */
154218334Speter
154318334Spetervoid
1544169699Skanfinal (rtx first, FILE *file, int optimize)
154518334Speter{
154690087Sobrien  rtx insn;
154750503Sobrien  int max_uid = 0;
1548132727Skan  int seen = 0;
154918334Speter
155018334Speter  last_ignored_compare = 0;
155118334Speter
1552132727Skan#ifdef SDB_DEBUGGING_INFO
1553132727Skan  /* When producing SDB debugging info, delete troublesome line number
155418334Speter     notes from inlined functions in other files as well as duplicate
155518334Speter     line number notes.  */
155618334Speter  if (write_symbols == SDB_DEBUG)
155718334Speter    {
155818334Speter      rtx last = 0;
155918334Speter      for (insn = first; insn; insn = NEXT_INSN (insn))
1560169699Skan	if (NOTE_P (insn) && NOTE_LINE_NUMBER (insn) > 0)
156118334Speter	  {
1562169699Skan	    if (last != 0
1563169699Skan#ifdef USE_MAPPED_LOCATION
1564169699Skan		&& NOTE_SOURCE_LOCATION (insn) == NOTE_SOURCE_LOCATION (last)
1565169699Skan#else
1566169699Skan		&& NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
1567169699Skan		&& NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)
1568169699Skan#endif
1569169699Skan	      )
157018334Speter	      {
157190087Sobrien		delete_insn (insn);	/* Use delete_note.  */
157218334Speter		continue;
157318334Speter	      }
157418334Speter	    last = insn;
157518334Speter	  }
157618334Speter    }
157718334Speter#endif
157818334Speter
157918334Speter  for (insn = first; insn; insn = NEXT_INSN (insn))
158050503Sobrien    {
1581132727Skan      if (INSN_UID (insn) > max_uid)       /* Find largest UID.  */
158290087Sobrien	max_uid = INSN_UID (insn);
158352515Sobrien#ifdef HAVE_cc0
158452515Sobrien      /* If CC tracking across branches is enabled, record the insn which
158552515Sobrien	 jumps to each branch only reached from one place.  */
1586169699Skan      if (optimize && JUMP_P (insn))
158752515Sobrien	{
158852515Sobrien	  rtx lab = JUMP_LABEL (insn);
158952515Sobrien	  if (lab && LABEL_NUSES (lab) == 1)
159052515Sobrien	    {
159152515Sobrien	      LABEL_REFS (lab) = insn;
159252515Sobrien	    }
159352515Sobrien	}
159452515Sobrien#endif
159550503Sobrien    }
159618334Speter
159718334Speter  init_recog ();
159818334Speter
159918334Speter  CC_STATUS_INIT;
160018334Speter
160118334Speter  /* Output the insns.  */
160218334Speter  for (insn = NEXT_INSN (first); insn;)
160350503Sobrien    {
160450503Sobrien#ifdef HAVE_ATTR_length
160590087Sobrien      if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ())
160690087Sobrien	{
160790087Sobrien	  /* This can be triggered by bugs elsewhere in the compiler if
160890087Sobrien	     new insns are created after init_insn_lengths is called.  */
1609169699Skan	  gcc_assert (NOTE_P (insn));
1610169699Skan	  insn_current_address = -1;
161190087Sobrien	}
161290087Sobrien      else
161390087Sobrien	insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
161490087Sobrien#endif /* HAVE_ATTR_length */
161590087Sobrien
1616169699Skan      insn = final_scan_insn (insn, file, optimize, 0, &seen);
161750503Sobrien    }
161890087Sobrien}
161990087Sobrien
162090087Sobrienconst char *
1621132727Skanget_insn_template (int code, rtx insn)
162290087Sobrien{
162390087Sobrien  switch (insn_data[code].output_format)
162490087Sobrien    {
162590087Sobrien    case INSN_OUTPUT_FORMAT_SINGLE:
1626132727Skan      return insn_data[code].output.single;
162790087Sobrien    case INSN_OUTPUT_FORMAT_MULTI:
1628132727Skan      return insn_data[code].output.multi[which_alternative];
162990087Sobrien    case INSN_OUTPUT_FORMAT_FUNCTION:
1630169699Skan      gcc_assert (insn);
1631132727Skan      return (*insn_data[code].output.function) (recog_data.operand, insn);
163250503Sobrien
163390087Sobrien    default:
1634169699Skan      gcc_unreachable ();
163590087Sobrien    }
163618334Speter}
163790087Sobrien
1638117404Skan/* Emit the appropriate declaration for an alternate-entry-point
1639117404Skan   symbol represented by INSN, to FILE.  INSN is a CODE_LABEL with
1640117404Skan   LABEL_KIND != LABEL_NORMAL.
1641117404Skan
1642117404Skan   The case fall-through in this function is intentional.  */
1643117404Skanstatic void
1644132727Skanoutput_alternate_entry_point (FILE *file, rtx insn)
1645117404Skan{
1646117404Skan  const char *name = LABEL_NAME (insn);
1647117404Skan
1648117404Skan  switch (LABEL_KIND (insn))
1649117404Skan    {
1650117404Skan    case LABEL_WEAK_ENTRY:
1651117404Skan#ifdef ASM_WEAKEN_LABEL
1652117404Skan      ASM_WEAKEN_LABEL (file, name);
1653117404Skan#endif
1654117404Skan    case LABEL_GLOBAL_ENTRY:
1655169699Skan      targetm.asm_out.globalize_label (file, name);
1656117404Skan    case LABEL_STATIC_ENTRY:
1657117404Skan#ifdef ASM_OUTPUT_TYPE_DIRECTIVE
1658117404Skan      ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
1659117404Skan#endif
1660117404Skan      ASM_OUTPUT_LABEL (file, name);
1661117404Skan      break;
1662117404Skan
1663117404Skan    case LABEL_NORMAL:
1664117404Skan    default:
1665169699Skan      gcc_unreachable ();
1666117404Skan    }
1667117404Skan}
1668117404Skan
166918334Speter/* The final scan for one insn, INSN.
167018334Speter   Args are same as in `final', except that INSN
167118334Speter   is the insn being scanned.
167218334Speter   Value returned is the next insn to be scanned.
167318334Speter
167418334Speter   NOPEEPHOLES is the flag to disallow peephole processing (currently
1675132727Skan   used for within delayed branch sequence output).
167618334Speter
1677132727Skan   SEEN is used to track the end of the prologue, for emitting
1678132727Skan   debug information.  We force the emission of a line note after
1679132727Skan   both NOTE_INSN_PROLOGUE_END and NOTE_INSN_FUNCTION_BEG, or
1680132727Skan   at the beginning of the second basic block, whichever comes
1681132727Skan   first.  */
1682132727Skan
168318334Speterrtx
1684132727Skanfinal_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
1685169699Skan		 int nopeepholes ATTRIBUTE_UNUSED, int *seen)
168618334Speter{
168750503Sobrien#ifdef HAVE_cc0
168850503Sobrien  rtx set;
168950503Sobrien#endif
1690169699Skan  rtx next;
169150503Sobrien
169218334Speter  insn_counter++;
169318334Speter
169418334Speter  /* Ignore deleted insns.  These can occur when we split insns (due to a
169518334Speter     template of "#") while not optimizing.  */
169618334Speter  if (INSN_DELETED_P (insn))
169718334Speter    return NEXT_INSN (insn);
169818334Speter
169918334Speter  switch (GET_CODE (insn))
170018334Speter    {
170118334Speter    case NOTE:
170290087Sobrien      switch (NOTE_LINE_NUMBER (insn))
170318334Speter	{
170490087Sobrien	case NOTE_INSN_DELETED:
170590087Sobrien	case NOTE_INSN_FUNCTION_END:
170690087Sobrien	case NOTE_INSN_REPEATED_LINE_NUMBER:
170790087Sobrien	case NOTE_INSN_EXPECTED_VALUE:
170818334Speter	  break;
170918334Speter
1710169699Skan	case NOTE_INSN_SWITCH_TEXT_SECTIONS:
1711169699Skan	  in_cold_section_p = !in_cold_section_p;
1712169699Skan	  (*debug_hooks->switch_text_section) ();
1713169699Skan	  switch_to_section (current_function_section ());
1714169699Skan	  break;
1715169699Skan
171690087Sobrien	case NOTE_INSN_BASIC_BLOCK:
1717169699Skan#ifdef TARGET_UNWIND_INFO
1718169699Skan	  targetm.asm_out.unwind_emit (asm_out_file, insn);
171950503Sobrien#endif
1720169699Skan
172190087Sobrien	  if (flag_debug_asm)
172290087Sobrien	    fprintf (asm_out_file, "\t%s basic block %d\n",
172390087Sobrien		     ASM_COMMENT_START, NOTE_BASIC_BLOCK (insn)->index);
1724132727Skan
1725132727Skan	  if ((*seen & (SEEN_EMITTED | SEEN_BB)) == SEEN_BB)
1726132727Skan	    {
1727132727Skan	      *seen |= SEEN_EMITTED;
1728169699Skan	      force_source_line = true;
1729132727Skan	    }
1730132727Skan	  else
1731132727Skan	    *seen |= SEEN_BB;
1732132727Skan
173350503Sobrien	  break;
173450503Sobrien
173590087Sobrien	case NOTE_INSN_EH_REGION_BEG:
173690087Sobrien	  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHB",
173790087Sobrien				  NOTE_EH_HANDLER (insn));
173890087Sobrien	  break;
173990087Sobrien
174090087Sobrien	case NOTE_INSN_EH_REGION_END:
174190087Sobrien	  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHE",
174290087Sobrien				  NOTE_EH_HANDLER (insn));
174390087Sobrien	  break;
174490087Sobrien
174590087Sobrien	case NOTE_INSN_PROLOGUE_END:
1746169699Skan	  targetm.asm_out.function_end_prologue (file);
174718334Speter	  profile_after_prologue (file);
1748132727Skan
1749132727Skan	  if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
1750132727Skan	    {
1751132727Skan	      *seen |= SEEN_EMITTED;
1752169699Skan	      force_source_line = true;
1753132727Skan	    }
1754132727Skan	  else
1755132727Skan	    *seen |= SEEN_NOTE;
1756132727Skan
175718334Speter	  break;
175818334Speter
175990087Sobrien	case NOTE_INSN_EPILOGUE_BEG:
1760169699Skan	  targetm.asm_out.function_begin_epilogue (file);
176118334Speter	  break;
176218334Speter
176390087Sobrien	case NOTE_INSN_FUNCTION_BEG:
176490087Sobrien	  app_disable ();
1765117404Skan	  (*debug_hooks->end_prologue) (last_linenum, last_filename);
1766132727Skan
1767132727Skan	  if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
1768132727Skan	    {
1769132727Skan	      *seen |= SEEN_EMITTED;
1770169699Skan	      force_source_line = true;
1771132727Skan	    }
1772132727Skan	  else
1773132727Skan	    *seen |= SEEN_NOTE;
1774132727Skan
177518334Speter	  break;
177690087Sobrien
177790087Sobrien	case NOTE_INSN_BLOCK_BEG:
177890087Sobrien	  if (debug_info_level == DINFO_LEVEL_NORMAL
177918334Speter	      || debug_info_level == DINFO_LEVEL_VERBOSE
178090087Sobrien	      || write_symbols == DWARF2_DEBUG
178190087Sobrien	      || write_symbols == VMS_AND_DWARF2_DEBUG
178290087Sobrien	      || write_symbols == VMS_DEBUG)
178390087Sobrien	    {
178490087Sobrien	      int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
178518334Speter
178690087Sobrien	      app_disable ();
178790087Sobrien	      ++block_depth;
178890087Sobrien	      high_block_linenum = last_linenum;
178990087Sobrien
179090087Sobrien	      /* Output debugging info about the symbol-block beginning.  */
179190087Sobrien	      (*debug_hooks->begin_block) (last_linenum, n);
179290087Sobrien
179390087Sobrien	      /* Mark this block as output.  */
179490087Sobrien	      TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
179518334Speter	    }
179690087Sobrien	  break;
179718334Speter
179890087Sobrien	case NOTE_INSN_BLOCK_END:
179990087Sobrien	  if (debug_info_level == DINFO_LEVEL_NORMAL
180090087Sobrien	      || debug_info_level == DINFO_LEVEL_VERBOSE
180190087Sobrien	      || write_symbols == DWARF2_DEBUG
180290087Sobrien	      || write_symbols == VMS_AND_DWARF2_DEBUG
180390087Sobrien	      || write_symbols == VMS_DEBUG)
180490087Sobrien	    {
180590087Sobrien	      int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
180618334Speter
180790087Sobrien	      app_disable ();
180818334Speter
180990087Sobrien	      /* End of a symbol-block.  */
181090087Sobrien	      --block_depth;
1811169699Skan	      gcc_assert (block_depth >= 0);
181218334Speter
181390087Sobrien	      (*debug_hooks->end_block) (high_block_linenum, n);
181490087Sobrien	    }
181590087Sobrien	  break;
181618334Speter
181790087Sobrien	case NOTE_INSN_DELETED_LABEL:
181890087Sobrien	  /* Emit the label.  We may have deleted the CODE_LABEL because
181990087Sobrien	     the label could be proved to be unreachable, though still
182090087Sobrien	     referenced (in the form of having its address taken.  */
182190087Sobrien	  ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
182290087Sobrien	  break;
182318334Speter
1824169699Skan	case NOTE_INSN_VAR_LOCATION:
1825169699Skan	  (*debug_hooks->var_location) (insn);
1826169699Skan	  break;
1827169699Skan
182890087Sobrien	case 0:
182990087Sobrien	  break;
183018334Speter
183190087Sobrien	default:
1832169699Skan	  gcc_assert (NOTE_LINE_NUMBER (insn) > 0);
183390087Sobrien	  break;
183418334Speter	}
183518334Speter      break;
183618334Speter
183718334Speter    case BARRIER:
183890087Sobrien#if defined (DWARF2_UNWIND_INFO)
183990087Sobrien      if (dwarf2out_do_frame ())
1840169699Skan	dwarf2out_frame_debug (insn, false);
184118334Speter#endif
184218334Speter      break;
184318334Speter
184418334Speter    case CODE_LABEL:
184550503Sobrien      /* The target port might emit labels in the output function for
184650503Sobrien	 some insn, e.g. sh.c output_branchy_insn.  */
1847260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \
1848260919Spfg      {
1849260919Spfg	int align = LABEL_ALIGN_LOG (insn);
185050503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
1851260919Spfg	int max_skip = LABEL_MAX_SKIP (insn);
185250503Sobrien#endif
1853260919Spfg
1854260919Spfg	if (align && NEXT_INSN (insn))
1855260919Spfg	  {
185650503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
1857260919Spfg	    ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip);
185850503Sobrien#else
1859117404Skan#ifdef ASM_OUTPUT_ALIGN_WITH_NOP
1860260919Spfg	    ASM_OUTPUT_ALIGN_WITH_NOP (file, align);
1861117404Skan#else
1862260919Spfg	    ASM_OUTPUT_ALIGN (file, align);
186350503Sobrien#endif
1864117404Skan#endif
1865260919Spfg	  }
1866260919Spfg      }
1867260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \
186852515Sobrien#ifdef HAVE_cc0
186918334Speter      CC_STATUS_INIT;
187052515Sobrien      /* If this label is reached from only one place, set the condition
187152515Sobrien	 codes from the instruction just before the branch.  */
187252515Sobrien
187352515Sobrien      /* Disabled because some insns set cc_status in the C output code
187452515Sobrien	 and NOTICE_UPDATE_CC alone can set incorrect status.  */
187552515Sobrien      if (0 /* optimize && LABEL_NUSES (insn) == 1*/)
187652515Sobrien	{
187752515Sobrien	  rtx jump = LABEL_REFS (insn);
187852515Sobrien	  rtx barrier = prev_nonnote_insn (insn);
187952515Sobrien	  rtx prev;
188052515Sobrien	  /* If the LABEL_REFS field of this label has been set to point
188152515Sobrien	     at a branch, the predecessor of the branch is a regular
188252515Sobrien	     insn, and that branch is the only way to reach this label,
188352515Sobrien	     set the condition codes based on the branch and its
188452515Sobrien	     predecessor.  */
1885169699Skan	  if (barrier && BARRIER_P (barrier)
1886169699Skan	      && jump && JUMP_P (jump)
188752515Sobrien	      && (prev = prev_nonnote_insn (jump))
1888169699Skan	      && NONJUMP_INSN_P (prev))
188952515Sobrien	    {
189052515Sobrien	      NOTICE_UPDATE_CC (PATTERN (prev), prev);
189152515Sobrien	      NOTICE_UPDATE_CC (PATTERN (jump), jump);
189252515Sobrien	    }
189352515Sobrien	}
189452515Sobrien#endif
189550503Sobrien
189690087Sobrien      if (LABEL_NAME (insn))
189790087Sobrien	(*debug_hooks->label) (insn);
189890087Sobrien
189918334Speter      if (app_on)
190018334Speter	{
190150503Sobrien	  fputs (ASM_APP_OFF, file);
190218334Speter	  app_on = 0;
190318334Speter	}
1904169699Skan
1905169699Skan      next = next_nonnote_insn (insn);
1906169699Skan      if (next != 0 && JUMP_P (next))
190718334Speter	{
1908169699Skan	  rtx nextbody = PATTERN (next);
190918334Speter
191018334Speter	  /* If this label is followed by a jump-table,
191118334Speter	     make sure we put the label in the read-only section.  Also
191218334Speter	     possibly write the label and jump table together.  */
191318334Speter
191418334Speter	  if (GET_CODE (nextbody) == ADDR_VEC
191518334Speter	      || GET_CODE (nextbody) == ADDR_DIFF_VEC)
191618334Speter	    {
191752515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
191852515Sobrien	      /* In this case, the case vector is being moved by the
191952515Sobrien		 target, so don't output the label at all.  Leave that
192052515Sobrien		 to the back end macros.  */
192152515Sobrien#else
192250503Sobrien	      if (! JUMP_TABLES_IN_TEXT_SECTION)
192350503Sobrien		{
192490087Sobrien		  int log_align;
192590087Sobrien
1926169699Skan		  switch_to_section (targetm.asm_out.function_rodata_section
1927169699Skan				     (current_function_decl));
192890087Sobrien
192990087Sobrien#ifdef ADDR_VEC_ALIGN
1930169699Skan		  log_align = ADDR_VEC_ALIGN (next);
193190087Sobrien#else
193290087Sobrien		  log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
193390087Sobrien#endif
193490087Sobrien		  ASM_OUTPUT_ALIGN (file, log_align);
193550503Sobrien		}
193650503Sobrien	      else
1937169699Skan		switch_to_section (current_function_section ());
193850503Sobrien
193918334Speter#ifdef ASM_OUTPUT_CASE_LABEL
194018334Speter	      ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
1941169699Skan				     next);
194218334Speter#else
1943169699Skan	      targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
194418334Speter#endif
194552515Sobrien#endif
194618334Speter	      break;
194718334Speter	    }
194818334Speter	}
1949117404Skan      if (LABEL_ALT_ENTRY_P (insn))
1950117404Skan	output_alternate_entry_point (file, insn);
195190087Sobrien      else
1952169699Skan	targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
195318334Speter      break;
195418334Speter
195518334Speter    default:
195618334Speter      {
195790087Sobrien	rtx body = PATTERN (insn);
195818334Speter	int insn_code_number;
195952515Sobrien	const char *template;
196018334Speter
1961169699Skan#ifdef HAVE_conditional_execution
1962169699Skan	/* Reset this early so it is correct for ASM statements.  */
1963169699Skan	current_insn_predicate = NULL_RTX;
1964169699Skan#endif
196518334Speter	/* An INSN, JUMP_INSN or CALL_INSN.
196618334Speter	   First check for special kinds that recog doesn't recognize.  */
196718334Speter
1968132727Skan	if (GET_CODE (body) == USE /* These are just declarations.  */
196918334Speter	    || GET_CODE (body) == CLOBBER)
197018334Speter	  break;
197118334Speter
197218334Speter#ifdef HAVE_cc0
1973169699Skan	{
1974169699Skan	  /* If there is a REG_CC_SETTER note on this insn, it means that
1975169699Skan	     the setting of the condition code was done in the delay slot
1976169699Skan	     of the insn that branched here.  So recover the cc status
1977169699Skan	     from the insn that set it.  */
197818334Speter
1979169699Skan	  rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
1980169699Skan	  if (note)
1981169699Skan	    {
1982169699Skan	      NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0));
1983169699Skan	      cc_prev_status = cc_status;
1984169699Skan	    }
1985169699Skan	}
198618334Speter#endif
198718334Speter
198818334Speter	/* Detect insns that are really jump-tables
198918334Speter	   and output them as such.  */
199018334Speter
199118334Speter	if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
199218334Speter	  {
199352515Sobrien#if !(defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC))
199490087Sobrien	    int vlen, idx;
199552515Sobrien#endif
199618334Speter
1997169699Skan	    if (! JUMP_TABLES_IN_TEXT_SECTION)
1998169699Skan	      switch_to_section (targetm.asm_out.function_rodata_section
1999169699Skan				 (current_function_decl));
2000169699Skan	    else
2001169699Skan	      switch_to_section (current_function_section ());
200218334Speter
200318334Speter	    if (app_on)
200418334Speter	      {
200550503Sobrien		fputs (ASM_APP_OFF, file);
200618334Speter		app_on = 0;
200718334Speter	      }
200818334Speter
200952515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
201052515Sobrien	    if (GET_CODE (body) == ADDR_VEC)
201152515Sobrien	      {
201252515Sobrien#ifdef ASM_OUTPUT_ADDR_VEC
201352515Sobrien		ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body);
201452515Sobrien#else
2015169699Skan		gcc_unreachable ();
201652515Sobrien#endif
201752515Sobrien	      }
201852515Sobrien	    else
201952515Sobrien	      {
202052515Sobrien#ifdef ASM_OUTPUT_ADDR_DIFF_VEC
202152515Sobrien		ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body);
202252515Sobrien#else
2023169699Skan		gcc_unreachable ();
202452515Sobrien#endif
202552515Sobrien	      }
202652515Sobrien#else
202718334Speter	    vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC);
202818334Speter	    for (idx = 0; idx < vlen; idx++)
202918334Speter	      {
203018334Speter		if (GET_CODE (body) == ADDR_VEC)
203118334Speter		  {
203218334Speter#ifdef ASM_OUTPUT_ADDR_VEC_ELT
203318334Speter		    ASM_OUTPUT_ADDR_VEC_ELT
203418334Speter		      (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
203518334Speter#else
2036169699Skan		    gcc_unreachable ();
203718334Speter#endif
203818334Speter		  }
203918334Speter		else
204018334Speter		  {
204118334Speter#ifdef ASM_OUTPUT_ADDR_DIFF_ELT
204218334Speter		    ASM_OUTPUT_ADDR_DIFF_ELT
204318334Speter		      (file,
204450503Sobrien		       body,
204518334Speter		       CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
204618334Speter		       CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
204718334Speter#else
2048169699Skan		    gcc_unreachable ();
204918334Speter#endif
205018334Speter		  }
205118334Speter	      }
205218334Speter#ifdef ASM_OUTPUT_CASE_END
205318334Speter	    ASM_OUTPUT_CASE_END (file,
205418334Speter				 CODE_LABEL_NUMBER (PREV_INSN (insn)),
205518334Speter				 insn);
205618334Speter#endif
205752515Sobrien#endif
205818334Speter
2059169699Skan	    switch_to_section (current_function_section ());
206018334Speter
206118334Speter	    break;
206218334Speter	  }
2063132727Skan	/* Output this line note if it is the first or the last line
2064132727Skan	   note in a row.  */
2065132727Skan	if (notice_source_line (insn))
2066132727Skan	  {
2067132727Skan	    (*debug_hooks->source_line) (last_linenum, last_filename);
2068132727Skan	  }
206918334Speter
207018334Speter	if (GET_CODE (body) == ASM_INPUT)
207118334Speter	  {
207290087Sobrien	    const char *string = XSTR (body, 0);
207390087Sobrien
207418334Speter	    /* There's no telling what that did to the condition codes.  */
207518334Speter	    CC_STATUS_INIT;
207690087Sobrien
207790087Sobrien	    if (string[0])
207818334Speter	      {
207990087Sobrien		if (! app_on)
208090087Sobrien		  {
208190087Sobrien		    fputs (ASM_APP_ON, file);
208290087Sobrien		    app_on = 1;
208390087Sobrien		  }
208490087Sobrien		fprintf (asm_out_file, "\t%s\n", string);
208518334Speter	      }
208618334Speter	    break;
208718334Speter	  }
208818334Speter
208918334Speter	/* Detect `asm' construct with operands.  */
209018334Speter	if (asm_noperands (body) >= 0)
209118334Speter	  {
209250503Sobrien	    unsigned int noperands = asm_noperands (body);
2093132727Skan	    rtx *ops = alloca (noperands * sizeof (rtx));
209490087Sobrien	    const char *string;
209518334Speter
209618334Speter	    /* There's no telling what that did to the condition codes.  */
209718334Speter	    CC_STATUS_INIT;
209818334Speter
209918334Speter	    /* Get out the operand values.  */
210090087Sobrien	    string = decode_asm_operands (body, ops, NULL, NULL, NULL);
2101169699Skan	    /* Inhibit dieing on what would otherwise be compiler bugs.  */
210218334Speter	    insn_noperands = noperands;
210318334Speter	    this_is_asm_operands = insn;
210418334Speter
2105132727Skan#ifdef FINAL_PRESCAN_INSN
2106132727Skan	    FINAL_PRESCAN_INSN (insn, ops, insn_noperands);
2107132727Skan#endif
2108132727Skan
210918334Speter	    /* Output the insn using them.  */
211090087Sobrien	    if (string[0])
211190087Sobrien	      {
211290087Sobrien		if (! app_on)
211390087Sobrien		  {
211490087Sobrien		    fputs (ASM_APP_ON, file);
211590087Sobrien		    app_on = 1;
211690087Sobrien		  }
211790087Sobrien	        output_asm_insn (string, ops);
211890087Sobrien	      }
211990087Sobrien
212018334Speter	    this_is_asm_operands = 0;
212118334Speter	    break;
212218334Speter	  }
212318334Speter
2124169699Skan	if (app_on)
212518334Speter	  {
212650503Sobrien	    fputs (ASM_APP_OFF, file);
212718334Speter	    app_on = 0;
212818334Speter	  }
212918334Speter
213018334Speter	if (GET_CODE (body) == SEQUENCE)
213118334Speter	  {
213218334Speter	    /* A delayed-branch sequence */
213390087Sobrien	    int i;
213418334Speter
213518334Speter	    final_sequence = body;
213618334Speter
2137132727Skan	    /* Record the delay slots' frame information before the branch.
2138132727Skan	       This is needed for delayed calls: see execute_cfa_program().  */
2139132727Skan#if defined (DWARF2_UNWIND_INFO)
2140132727Skan	    if (dwarf2out_do_frame ())
2141132727Skan	      for (i = 1; i < XVECLEN (body, 0); i++)
2142169699Skan		dwarf2out_frame_debug (XVECEXP (body, 0, i), false);
2143132727Skan#endif
2144132727Skan
214518334Speter	    /* The first insn in this SEQUENCE might be a JUMP_INSN that will
214618334Speter	       force the restoration of a comparison that was previously
214718334Speter	       thought unnecessary.  If that happens, cancel this sequence
214818334Speter	       and cause that insn to be restored.  */
214918334Speter
2150169699Skan	    next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, 1, seen);
215118334Speter	    if (next != XVECEXP (body, 0, 1))
215218334Speter	      {
215318334Speter		final_sequence = 0;
215418334Speter		return next;
215518334Speter	      }
215618334Speter
215718334Speter	    for (i = 1; i < XVECLEN (body, 0); i++)
215818334Speter	      {
215918334Speter		rtx insn = XVECEXP (body, 0, i);
216018334Speter		rtx next = NEXT_INSN (insn);
216118334Speter		/* We loop in case any instruction in a delay slot gets
216218334Speter		   split.  */
216318334Speter		do
2164169699Skan		  insn = final_scan_insn (insn, file, 0, 1, seen);
216518334Speter		while (insn != next);
216618334Speter	      }
216718334Speter#ifdef DBR_OUTPUT_SEQEND
216818334Speter	    DBR_OUTPUT_SEQEND (file);
216918334Speter#endif
217018334Speter	    final_sequence = 0;
217118334Speter
217218334Speter	    /* If the insn requiring the delay slot was a CALL_INSN, the
217318334Speter	       insns in the delay slot are actually executed before the
217418334Speter	       called function.  Hence we don't preserve any CC-setting
217518334Speter	       actions in these insns and the CC must be marked as being
217618334Speter	       clobbered by the function.  */
2177169699Skan	    if (CALL_P (XVECEXP (body, 0, 0)))
217850503Sobrien	      {
217950503Sobrien		CC_STATUS_INIT;
218050503Sobrien	      }
218118334Speter	    break;
218218334Speter	  }
218318334Speter
218418334Speter	/* We have a real machine instruction as rtl.  */
218518334Speter
218618334Speter	body = PATTERN (insn);
218718334Speter
218818334Speter#ifdef HAVE_cc0
218990087Sobrien	set = single_set (insn);
219050503Sobrien
219118334Speter	/* Check for redundant test and compare instructions
219218334Speter	   (when the condition codes are already set up as desired).
219318334Speter	   This is done only when optimizing; if not optimizing,
219418334Speter	   it should be possible for the user to alter a variable
219518334Speter	   with the debugger in between statements
219618334Speter	   and the next statement should reexamine the variable
219718334Speter	   to compute the condition codes.  */
219818334Speter
219950503Sobrien	if (optimize)
220018334Speter	  {
220150503Sobrien	    if (set
220250503Sobrien		&& GET_CODE (SET_DEST (set)) == CC0
220350503Sobrien		&& insn != last_ignored_compare)
220418334Speter	      {
220550503Sobrien		if (GET_CODE (SET_SRC (set)) == SUBREG)
220690087Sobrien		  SET_SRC (set) = alter_subreg (&SET_SRC (set));
220750503Sobrien		else if (GET_CODE (SET_SRC (set)) == COMPARE)
220818334Speter		  {
220950503Sobrien		    if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
221050503Sobrien		      XEXP (SET_SRC (set), 0)
221190087Sobrien			= alter_subreg (&XEXP (SET_SRC (set), 0));
221250503Sobrien		    if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG)
221350503Sobrien		      XEXP (SET_SRC (set), 1)
221490087Sobrien			= alter_subreg (&XEXP (SET_SRC (set), 1));
221518334Speter		  }
221650503Sobrien		if ((cc_status.value1 != 0
221750503Sobrien		     && rtx_equal_p (SET_SRC (set), cc_status.value1))
221850503Sobrien		    || (cc_status.value2 != 0
221950503Sobrien			&& rtx_equal_p (SET_SRC (set), cc_status.value2)))
222050503Sobrien		  {
222150503Sobrien		    /* Don't delete insn if it has an addressing side-effect.  */
222290087Sobrien		    if (! FIND_REG_INC_NOTE (insn, NULL_RTX)
222350503Sobrien			/* or if anything in it is volatile.  */
222450503Sobrien			&& ! volatile_refs_p (PATTERN (insn)))
222550503Sobrien		      {
222650503Sobrien			/* We don't really delete the insn; just ignore it.  */
222750503Sobrien			last_ignored_compare = insn;
222850503Sobrien			break;
222950503Sobrien		      }
223050503Sobrien		  }
223118334Speter	      }
223218334Speter	  }
223318334Speter#endif
223418334Speter
223518334Speter#ifdef HAVE_cc0
223618334Speter	/* If this is a conditional branch, maybe modify it
223718334Speter	   if the cc's are in a nonstandard state
223818334Speter	   so that it accomplishes the same thing that it would
223918334Speter	   do straightforwardly if the cc's were set up normally.  */
224018334Speter
224118334Speter	if (cc_status.flags != 0
2242169699Skan	    && JUMP_P (insn)
224318334Speter	    && GET_CODE (body) == SET
224418334Speter	    && SET_DEST (body) == pc_rtx
224518334Speter	    && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
2246169699Skan	    && COMPARISON_P (XEXP (SET_SRC (body), 0))
2247169699Skan	    && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx)
224818334Speter	  {
224918334Speter	    /* This function may alter the contents of its argument
225018334Speter	       and clear some of the cc_status.flags bits.
225118334Speter	       It may also return 1 meaning condition now always true
225218334Speter	       or -1 meaning condition now always false
225318334Speter	       or 2 meaning condition nontrivial but altered.  */
225490087Sobrien	    int result = alter_cond (XEXP (SET_SRC (body), 0));
225518334Speter	    /* If condition now has fixed value, replace the IF_THEN_ELSE
225618334Speter	       with its then-operand or its else-operand.  */
225718334Speter	    if (result == 1)
225818334Speter	      SET_SRC (body) = XEXP (SET_SRC (body), 1);
225918334Speter	    if (result == -1)
226018334Speter	      SET_SRC (body) = XEXP (SET_SRC (body), 2);
226118334Speter
226218334Speter	    /* The jump is now either unconditional or a no-op.
226318334Speter	       If it has become a no-op, don't try to output it.
226418334Speter	       (It would not be recognized.)  */
226518334Speter	    if (SET_SRC (body) == pc_rtx)
226618334Speter	      {
226790087Sobrien	        delete_insn (insn);
226818334Speter		break;
226918334Speter	      }
227018334Speter	    else if (GET_CODE (SET_SRC (body)) == RETURN)
227118334Speter	      /* Replace (set (pc) (return)) with (return).  */
227218334Speter	      PATTERN (insn) = body = SET_SRC (body);
227318334Speter
227418334Speter	    /* Rerecognize the instruction if it has changed.  */
227518334Speter	    if (result != 0)
227618334Speter	      INSN_CODE (insn) = -1;
227718334Speter	  }
227818334Speter
227918334Speter	/* Make same adjustments to instructions that examine the
228050503Sobrien	   condition codes without jumping and instructions that
228150503Sobrien	   handle conditional moves (if this machine has either one).  */
228218334Speter
228318334Speter	if (cc_status.flags != 0
228450503Sobrien	    && set != 0)
228518334Speter	  {
228650503Sobrien	    rtx cond_rtx, then_rtx, else_rtx;
228790087Sobrien
2288169699Skan	    if (!JUMP_P (insn)
228950503Sobrien		&& GET_CODE (SET_SRC (set)) == IF_THEN_ELSE)
229018334Speter	      {
229150503Sobrien		cond_rtx = XEXP (SET_SRC (set), 0);
229250503Sobrien		then_rtx = XEXP (SET_SRC (set), 1);
229350503Sobrien		else_rtx = XEXP (SET_SRC (set), 2);
229450503Sobrien	      }
229550503Sobrien	    else
229650503Sobrien	      {
229750503Sobrien		cond_rtx = SET_SRC (set);
229850503Sobrien		then_rtx = const_true_rtx;
229950503Sobrien		else_rtx = const0_rtx;
230050503Sobrien	      }
230190087Sobrien
230250503Sobrien	    switch (GET_CODE (cond_rtx))
230350503Sobrien	      {
230418334Speter	      case GTU:
230518334Speter	      case GT:
230618334Speter	      case LTU:
230718334Speter	      case LT:
230818334Speter	      case GEU:
230918334Speter	      case GE:
231018334Speter	      case LEU:
231118334Speter	      case LE:
231218334Speter	      case EQ:
231318334Speter	      case NE:
231418334Speter		{
231590087Sobrien		  int result;
231650503Sobrien		  if (XEXP (cond_rtx, 0) != cc0_rtx)
231718334Speter		    break;
231850503Sobrien		  result = alter_cond (cond_rtx);
231918334Speter		  if (result == 1)
232050503Sobrien		    validate_change (insn, &SET_SRC (set), then_rtx, 0);
232118334Speter		  else if (result == -1)
232250503Sobrien		    validate_change (insn, &SET_SRC (set), else_rtx, 0);
232318334Speter		  else if (result == 2)
232418334Speter		    INSN_CODE (insn) = -1;
232550503Sobrien		  if (SET_DEST (set) == SET_SRC (set))
232690087Sobrien		    delete_insn (insn);
232718334Speter		}
232850503Sobrien		break;
232950503Sobrien
233050503Sobrien	      default:
233150503Sobrien		break;
233218334Speter	      }
233318334Speter	  }
233450503Sobrien
233518334Speter#endif
233618334Speter
233790087Sobrien#ifdef HAVE_peephole
233818334Speter	/* Do machine-specific peephole optimizations if desired.  */
233918334Speter
234018334Speter	if (optimize && !flag_no_peephole && !nopeepholes)
234118334Speter	  {
234218334Speter	    rtx next = peephole (insn);
234318334Speter	    /* When peepholing, if there were notes within the peephole,
234418334Speter	       emit them before the peephole.  */
234518334Speter	    if (next != 0 && next != NEXT_INSN (insn))
234618334Speter	      {
2347169699Skan		rtx note, prev = PREV_INSN (insn);
234818334Speter
234918334Speter		for (note = NEXT_INSN (insn); note != next;
235018334Speter		     note = NEXT_INSN (note))
2351169699Skan		  final_scan_insn (note, file, optimize, nopeepholes, seen);
235218334Speter
2353169699Skan		/* Put the notes in the proper position for a later
2354169699Skan		   rescan.  For example, the SH target can do this
2355169699Skan		   when generating a far jump in a delayed branch
2356169699Skan		   sequence.  */
235718334Speter		note = NEXT_INSN (insn);
235818334Speter		PREV_INSN (note) = prev;
235918334Speter		NEXT_INSN (prev) = note;
236018334Speter		NEXT_INSN (PREV_INSN (next)) = insn;
236118334Speter		PREV_INSN (insn) = PREV_INSN (next);
236218334Speter		NEXT_INSN (insn) = next;
236318334Speter		PREV_INSN (next) = insn;
236418334Speter	      }
236518334Speter
236618334Speter	    /* PEEPHOLE might have changed this.  */
236718334Speter	    body = PATTERN (insn);
236818334Speter	  }
236990087Sobrien#endif
237018334Speter
237118334Speter	/* Try to recognize the instruction.
237218334Speter	   If successful, verify that the operands satisfy the
237318334Speter	   constraints for the instruction.  Crash if they don't,
237418334Speter	   since `reload' should have changed them so that they do.  */
237518334Speter
237618334Speter	insn_code_number = recog_memoized (insn);
237752515Sobrien	cleanup_subreg_operands (insn);
237818334Speter
2379117404Skan	/* Dump the insn in the assembly for debugging.  */
2380117404Skan	if (flag_dump_rtl_in_asm)
2381117404Skan	  {
2382117404Skan	    print_rtx_head = ASM_COMMENT_START;
2383117404Skan	    print_rtl_single (asm_out_file, insn);
2384117404Skan	    print_rtx_head = "";
2385117404Skan	  }
238690087Sobrien
238790087Sobrien	if (! constrain_operands_cached (1))
238818334Speter	  fatal_insn_not_found (insn);
238918334Speter
239018334Speter	/* Some target machines need to prescan each insn before
239118334Speter	   it is output.  */
239218334Speter
239318334Speter#ifdef FINAL_PRESCAN_INSN
239490087Sobrien	FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands);
239518334Speter#endif
239618334Speter
239790087Sobrien#ifdef HAVE_conditional_execution
239890087Sobrien	if (GET_CODE (PATTERN (insn)) == COND_EXEC)
239990087Sobrien	  current_insn_predicate = COND_EXEC_TEST (PATTERN (insn));
240090087Sobrien#endif
240190087Sobrien
240218334Speter#ifdef HAVE_cc0
240318334Speter	cc_prev_status = cc_status;
240418334Speter
240518334Speter	/* Update `cc_status' for this instruction.
240618334Speter	   The instruction's output routine may change it further.
240718334Speter	   If the output routine for a jump insn needs to depend
240818334Speter	   on the cc status, it should look at cc_prev_status.  */
240918334Speter
241018334Speter	NOTICE_UPDATE_CC (body, insn);
241118334Speter#endif
241218334Speter
241390087Sobrien	current_output_insn = debug_insn = insn;
241418334Speter
241590087Sobrien#if defined (DWARF2_UNWIND_INFO)
2416169699Skan	if (CALL_P (insn) && dwarf2out_do_frame ())
2417169699Skan	  dwarf2out_frame_debug (insn, false);
241850503Sobrien#endif
241950503Sobrien
242090087Sobrien	/* Find the proper template for this insn.  */
242190087Sobrien	template = get_insn_template (insn_code_number, insn);
242218334Speter
242390087Sobrien	/* If the C code returns 0, it means that it is a jump insn
242490087Sobrien	   which follows a deleted test insn, and that test insn
242590087Sobrien	   needs to be reinserted.  */
242618334Speter	if (template == 0)
242718334Speter	  {
242890087Sobrien	    rtx prev;
242918334Speter
2430169699Skan	    gcc_assert (prev_nonnote_insn (insn) == last_ignored_compare);
243190087Sobrien
243290087Sobrien	    /* We have already processed the notes between the setter and
243390087Sobrien	       the user.  Make sure we don't process them again, this is
243490087Sobrien	       particularly important if one of the notes is a block
243590087Sobrien	       scope note or an EH note.  */
243690087Sobrien	    for (prev = insn;
243790087Sobrien		 prev != last_ignored_compare;
243890087Sobrien		 prev = PREV_INSN (prev))
243918334Speter	      {
2440169699Skan		if (NOTE_P (prev))
244190087Sobrien		  delete_insn (prev);	/* Use delete_note.  */
244218334Speter	      }
244390087Sobrien
244490087Sobrien	    return prev;
244518334Speter	  }
244618334Speter
244718334Speter	/* If the template is the string "#", it means that this insn must
244818334Speter	   be split.  */
244918334Speter	if (template[0] == '#' && template[1] == '\0')
245018334Speter	  {
245118334Speter	    rtx new = try_split (body, insn, 0);
245218334Speter
245318334Speter	    /* If we didn't split the insn, go away.  */
245418334Speter	    if (new == insn && PATTERN (new) == body)
245590087Sobrien	      fatal_insn ("could not split insn", insn);
245690087Sobrien
245750503Sobrien#ifdef HAVE_ATTR_length
245850503Sobrien	    /* This instruction should have been split in shorten_branches,
245950503Sobrien	       to ensure that we would have valid length info for the
246050503Sobrien	       splitees.  */
2461169699Skan	    gcc_unreachable ();
246250503Sobrien#endif
246350503Sobrien
246418334Speter	    return new;
246518334Speter	  }
246690087Sobrien
2467169699Skan#ifdef TARGET_UNWIND_INFO
2468169699Skan	/* ??? This will put the directives in the wrong place if
2469169699Skan	   get_insn_template outputs assembly directly.  However calling it
2470169699Skan	   before get_insn_template breaks if the insns is split.  */
2471169699Skan	targetm.asm_out.unwind_emit (asm_out_file, insn);
2472169699Skan#endif
247318334Speter
247418334Speter	/* Output assembler code from the template.  */
247590087Sobrien	output_asm_insn (template, recog_data.operand);
247618334Speter
2477132727Skan	/* If necessary, report the effect that the instruction has on
2478132727Skan	   the unwind info.   We've already done this for delay slots
2479132727Skan	   and call instructions.  */
248050503Sobrien#if defined (DWARF2_UNWIND_INFO)
2481169699Skan	if (final_sequence == 0
2482132727Skan#if !defined (HAVE_prologue)
2483132727Skan	    && !ACCUMULATE_OUTGOING_ARGS
2484132727Skan#endif
248590087Sobrien	    && dwarf2out_do_frame ())
2486169699Skan	  dwarf2out_frame_debug (insn, true);
248750503Sobrien#endif
248850503Sobrien
248990087Sobrien	current_output_insn = debug_insn = 0;
249018334Speter      }
249118334Speter    }
249218334Speter  return NEXT_INSN (insn);
249318334Speter}
249418334Speter
2495169699Skan/* Return whether a source line note needs to be emitted before INSN.  */
249618334Speter
2497132727Skanstatic bool
2498132727Skannotice_source_line (rtx insn)
249918334Speter{
2500132727Skan  const char *filename = insn_file (insn);
2501132727Skan  int linenum = insn_line (insn);
250218334Speter
2503169699Skan  if (filename
2504169699Skan      && (force_source_line
2505169699Skan	  || filename != last_filename
2506169699Skan	  || last_linenum != linenum))
2507132727Skan    {
2508169699Skan      force_source_line = false;
2509132727Skan      last_filename = filename;
2510132727Skan      last_linenum = linenum;
2511132727Skan      high_block_linenum = MAX (last_linenum, high_block_linenum);
2512132727Skan      high_function_linenum = MAX (last_linenum, high_function_linenum);
2513132727Skan      return true;
2514132727Skan    }
2515132727Skan  return false;
251618334Speter}
251718334Speter
251852515Sobrien/* For each operand in INSN, simplify (subreg (reg)) so that it refers
251952515Sobrien   directly to the desired hard register.  */
252090087Sobrien
252152515Sobrienvoid
2522132727Skancleanup_subreg_operands (rtx insn)
252352515Sobrien{
252452515Sobrien  int i;
252590087Sobrien  extract_insn_cached (insn);
252690087Sobrien  for (i = 0; i < recog_data.n_operands; i++)
252752515Sobrien    {
2528132727Skan      /* The following test cannot use recog_data.operand when testing
252990087Sobrien	 for a SUBREG: the underlying object might have been changed
253090087Sobrien	 already if we are inside a match_operator expression that
253190087Sobrien	 matches the else clause.  Instead we test the underlying
253290087Sobrien	 expression directly.  */
253390087Sobrien      if (GET_CODE (*recog_data.operand_loc[i]) == SUBREG)
253490087Sobrien	recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]);
253590087Sobrien      else if (GET_CODE (recog_data.operand[i]) == PLUS
253690087Sobrien	       || GET_CODE (recog_data.operand[i]) == MULT
2537169699Skan	       || MEM_P (recog_data.operand[i]))
253890087Sobrien	recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i]);
253952515Sobrien    }
254052515Sobrien
254190087Sobrien  for (i = 0; i < recog_data.n_dups; i++)
254252515Sobrien    {
254390087Sobrien      if (GET_CODE (*recog_data.dup_loc[i]) == SUBREG)
254490087Sobrien	*recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]);
254590087Sobrien      else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS
254690087Sobrien	       || GET_CODE (*recog_data.dup_loc[i]) == MULT
2547169699Skan	       || MEM_P (*recog_data.dup_loc[i]))
254890087Sobrien	*recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]);
254952515Sobrien    }
255052515Sobrien}
255152515Sobrien
255218334Speter/* If X is a SUBREG, replace it with a REG or a MEM,
255318334Speter   based on the thing it is a subreg of.  */
255418334Speter
255518334Speterrtx
2556132727Skanalter_subreg (rtx *xp)
255718334Speter{
255890087Sobrien  rtx x = *xp;
255990087Sobrien  rtx y = SUBREG_REG (x);
256050503Sobrien
256190087Sobrien  /* simplify_subreg does not remove subreg from volatile references.
256290087Sobrien     We are required to.  */
2563169699Skan  if (MEM_P (y))
2564169699Skan    {
2565169699Skan      int offset = SUBREG_BYTE (x);
2566169699Skan
2567169699Skan      /* For paradoxical subregs on big-endian machines, SUBREG_BYTE
2568169699Skan	 contains 0 instead of the proper offset.  See simplify_subreg.  */
2569169699Skan      if (offset == 0
2570169699Skan	  && GET_MODE_SIZE (GET_MODE (y)) < GET_MODE_SIZE (GET_MODE (x)))
2571169699Skan        {
2572169699Skan          int difference = GET_MODE_SIZE (GET_MODE (y))
2573169699Skan			   - GET_MODE_SIZE (GET_MODE (x));
2574169699Skan          if (WORDS_BIG_ENDIAN)
2575169699Skan            offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
2576169699Skan          if (BYTES_BIG_ENDIAN)
2577169699Skan            offset += difference % UNITS_PER_WORD;
2578169699Skan        }
2579169699Skan
2580169699Skan      *xp = adjust_address (y, GET_MODE (x), offset);
2581169699Skan    }
258290087Sobrien  else
258318334Speter    {
258490087Sobrien      rtx new = simplify_subreg (GET_MODE (x), y, GET_MODE (y),
258590087Sobrien				 SUBREG_BYTE (x));
258650503Sobrien
258790087Sobrien      if (new != 0)
258890087Sobrien	*xp = new;
2589169699Skan      else if (REG_P (y))
259090087Sobrien	{
2591169699Skan	  /* Simplify_subreg can't handle some REG cases, but we have to.  */
2592169699Skan	  unsigned int regno = subreg_regno (x);
2593132727Skan	  *xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, SUBREG_BYTE (x));
259490087Sobrien	}
259518334Speter    }
259618334Speter
259790087Sobrien  return *xp;
259818334Speter}
259918334Speter
260018334Speter/* Do alter_subreg on all the SUBREGs contained in X.  */
260118334Speter
260218334Speterstatic rtx
2603132727Skanwalk_alter_subreg (rtx *xp)
260418334Speter{
260590087Sobrien  rtx x = *xp;
260618334Speter  switch (GET_CODE (x))
260718334Speter    {
260818334Speter    case PLUS:
260918334Speter    case MULT:
2610169699Skan    case AND:
261190087Sobrien      XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
261290087Sobrien      XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1));
261318334Speter      break;
261418334Speter
261518334Speter    case MEM:
2616169699Skan    case ZERO_EXTEND:
261790087Sobrien      XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
261818334Speter      break;
261918334Speter
262018334Speter    case SUBREG:
262190087Sobrien      return alter_subreg (xp);
262290087Sobrien
262350503Sobrien    default:
262450503Sobrien      break;
262518334Speter    }
262618334Speter
262790087Sobrien  return *xp;
262818334Speter}
262918334Speter
263018334Speter#ifdef HAVE_cc0
263118334Speter
263218334Speter/* Given BODY, the body of a jump instruction, alter the jump condition
263318334Speter   as required by the bits that are set in cc_status.flags.
263418334Speter   Not all of the bits there can be handled at this level in all cases.
263518334Speter
263618334Speter   The value is normally 0.
263718334Speter   1 means that the condition has become always true.
263818334Speter   -1 means that the condition has become always false.
263918334Speter   2 means that COND has been altered.  */
264018334Speter
264118334Speterstatic int
2642132727Skanalter_cond (rtx cond)
264318334Speter{
264418334Speter  int value = 0;
264518334Speter
264618334Speter  if (cc_status.flags & CC_REVERSED)
264718334Speter    {
264818334Speter      value = 2;
264918334Speter      PUT_CODE (cond, swap_condition (GET_CODE (cond)));
265018334Speter    }
265118334Speter
265218334Speter  if (cc_status.flags & CC_INVERTED)
265318334Speter    {
265418334Speter      value = 2;
265518334Speter      PUT_CODE (cond, reverse_condition (GET_CODE (cond)));
265618334Speter    }
265718334Speter
265818334Speter  if (cc_status.flags & CC_NOT_POSITIVE)
265918334Speter    switch (GET_CODE (cond))
266018334Speter      {
266118334Speter      case LE:
266218334Speter      case LEU:
266318334Speter      case GEU:
266418334Speter	/* Jump becomes unconditional.  */
266518334Speter	return 1;
266618334Speter
266718334Speter      case GT:
266818334Speter      case GTU:
266918334Speter      case LTU:
267018334Speter	/* Jump becomes no-op.  */
267118334Speter	return -1;
267218334Speter
267318334Speter      case GE:
267418334Speter	PUT_CODE (cond, EQ);
267518334Speter	value = 2;
267618334Speter	break;
267718334Speter
267818334Speter      case LT:
267918334Speter	PUT_CODE (cond, NE);
268018334Speter	value = 2;
268118334Speter	break;
268290087Sobrien
268350503Sobrien      default:
268450503Sobrien	break;
268518334Speter      }
268618334Speter
268718334Speter  if (cc_status.flags & CC_NOT_NEGATIVE)
268818334Speter    switch (GET_CODE (cond))
268918334Speter      {
269018334Speter      case GE:
269118334Speter      case GEU:
269218334Speter	/* Jump becomes unconditional.  */
269318334Speter	return 1;
269418334Speter
269518334Speter      case LT:
269618334Speter      case LTU:
269718334Speter	/* Jump becomes no-op.  */
269818334Speter	return -1;
269918334Speter
270018334Speter      case LE:
270118334Speter      case LEU:
270218334Speter	PUT_CODE (cond, EQ);
270318334Speter	value = 2;
270418334Speter	break;
270518334Speter
270618334Speter      case GT:
270718334Speter      case GTU:
270818334Speter	PUT_CODE (cond, NE);
270918334Speter	value = 2;
271018334Speter	break;
271190087Sobrien
271250503Sobrien      default:
271350503Sobrien	break;
271418334Speter      }
271518334Speter
271618334Speter  if (cc_status.flags & CC_NO_OVERFLOW)
271718334Speter    switch (GET_CODE (cond))
271818334Speter      {
271918334Speter      case GEU:
272018334Speter	/* Jump becomes unconditional.  */
272118334Speter	return 1;
272218334Speter
272318334Speter      case LEU:
272418334Speter	PUT_CODE (cond, EQ);
272518334Speter	value = 2;
272618334Speter	break;
272718334Speter
272818334Speter      case GTU:
272918334Speter	PUT_CODE (cond, NE);
273018334Speter	value = 2;
273118334Speter	break;
273218334Speter
273318334Speter      case LTU:
273418334Speter	/* Jump becomes no-op.  */
273518334Speter	return -1;
273690087Sobrien
273750503Sobrien      default:
273850503Sobrien	break;
273918334Speter      }
274018334Speter
274118334Speter  if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N))
274218334Speter    switch (GET_CODE (cond))
274318334Speter      {
274450503Sobrien      default:
2745169699Skan	gcc_unreachable ();
274618334Speter
274718334Speter      case NE:
274818334Speter	PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT);
274918334Speter	value = 2;
275018334Speter	break;
275118334Speter
275218334Speter      case EQ:
275318334Speter	PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE);
275418334Speter	value = 2;
275518334Speter	break;
275618334Speter      }
275718334Speter
275818334Speter  if (cc_status.flags & CC_NOT_SIGNED)
275918334Speter    /* The flags are valid if signed condition operators are converted
276018334Speter       to unsigned.  */
276118334Speter    switch (GET_CODE (cond))
276218334Speter      {
276318334Speter      case LE:
276418334Speter	PUT_CODE (cond, LEU);
276518334Speter	value = 2;
276618334Speter	break;
276718334Speter
276818334Speter      case LT:
276918334Speter	PUT_CODE (cond, LTU);
277018334Speter	value = 2;
277118334Speter	break;
277218334Speter
277318334Speter      case GT:
277418334Speter	PUT_CODE (cond, GTU);
277518334Speter	value = 2;
277618334Speter	break;
277718334Speter
277818334Speter      case GE:
277918334Speter	PUT_CODE (cond, GEU);
278018334Speter	value = 2;
278118334Speter	break;
278250503Sobrien
278350503Sobrien      default:
278450503Sobrien	break;
278518334Speter      }
278618334Speter
278718334Speter  return value;
278818334Speter}
278918334Speter#endif
279018334Speter
279118334Speter/* Report inconsistency between the assembler template and the operands.
279218334Speter   In an `asm', it's the user's fault; otherwise, the compiler's fault.  */
279318334Speter
279418334Spetervoid
2795169699Skanoutput_operand_lossage (const char *cmsgid, ...)
279618334Speter{
279796281Sobrien  char *fmt_string;
279896281Sobrien  char *new_message;
279996281Sobrien  const char *pfx_str;
2800132727Skan  va_list ap;
280196281Sobrien
2802169699Skan  va_start (ap, cmsgid);
2803132727Skan
2804169699Skan  pfx_str = this_is_asm_operands ? _("invalid 'asm': ") : "output_operand: ";
2805169699Skan  asprintf (&fmt_string, "%s%s", pfx_str, _(cmsgid));
280696281Sobrien  vasprintf (&new_message, fmt_string, ap);
2807117404Skan
280818334Speter  if (this_is_asm_operands)
280996281Sobrien    error_for_asm (this_is_asm_operands, "%s", new_message);
281018334Speter  else
281196281Sobrien    internal_error ("%s", new_message);
281296281Sobrien
281396281Sobrien  free (fmt_string);
281496281Sobrien  free (new_message);
2815132727Skan  va_end (ap);
281618334Speter}
281718334Speter
281818334Speter/* Output of assembler code from a template, and its subroutines.  */
281918334Speter
282090087Sobrien/* Annotate the assembly with a comment describing the pattern and
282190087Sobrien   alternative used.  */
282290087Sobrien
282390087Sobrienstatic void
2824132727Skanoutput_asm_name (void)
282590087Sobrien{
282690087Sobrien  if (debug_insn)
282790087Sobrien    {
282890087Sobrien      int num = INSN_CODE (debug_insn);
282990087Sobrien      fprintf (asm_out_file, "\t%s %d\t%s",
283090087Sobrien	       ASM_COMMENT_START, INSN_UID (debug_insn),
283190087Sobrien	       insn_data[num].name);
283290087Sobrien      if (insn_data[num].n_alternatives > 1)
283390087Sobrien	fprintf (asm_out_file, "/%d", which_alternative + 1);
283490087Sobrien#ifdef HAVE_ATTR_length
283590087Sobrien      fprintf (asm_out_file, "\t[length = %d]",
283690087Sobrien	       get_attr_length (debug_insn));
283790087Sobrien#endif
283890087Sobrien      /* Clear this so only the first assembler insn
283990087Sobrien	 of any rtl insn will get the special comment for -dp.  */
284090087Sobrien      debug_insn = 0;
284190087Sobrien    }
284290087Sobrien}
284390087Sobrien
284490087Sobrien/* If OP is a REG or MEM and we can find a MEM_EXPR corresponding to it
284590087Sobrien   or its address, return that expr .  Set *PADDRESSP to 1 if the expr
284690087Sobrien   corresponds to the address of the object and 0 if to the object.  */
284790087Sobrien
284890087Sobrienstatic tree
2849132727Skanget_mem_expr_from_op (rtx op, int *paddressp)
285090087Sobrien{
285190087Sobrien  tree expr;
285290087Sobrien  int inner_addressp;
285390087Sobrien
285490087Sobrien  *paddressp = 0;
285590087Sobrien
2856169699Skan  if (REG_P (op))
2857132727Skan    return REG_EXPR (op);
2858169699Skan  else if (!MEM_P (op))
285990087Sobrien    return 0;
286090087Sobrien
286190087Sobrien  if (MEM_EXPR (op) != 0)
286290087Sobrien    return MEM_EXPR (op);
286390087Sobrien
286490087Sobrien  /* Otherwise we have an address, so indicate it and look at the address.  */
286590087Sobrien  *paddressp = 1;
286690087Sobrien  op = XEXP (op, 0);
286790087Sobrien
286890087Sobrien  /* First check if we have a decl for the address, then look at the right side
286990087Sobrien     if it is a PLUS.  Otherwise, strip off arithmetic and keep looking.
287090087Sobrien     But don't allow the address to itself be indirect.  */
287190087Sobrien  if ((expr = get_mem_expr_from_op (op, &inner_addressp)) && ! inner_addressp)
287290087Sobrien    return expr;
287390087Sobrien  else if (GET_CODE (op) == PLUS
287490087Sobrien	   && (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp)))
287590087Sobrien    return expr;
287690087Sobrien
2877169699Skan  while (GET_RTX_CLASS (GET_CODE (op)) == RTX_UNARY
2878169699Skan	 || GET_RTX_CLASS (GET_CODE (op)) == RTX_BIN_ARITH)
287990087Sobrien    op = XEXP (op, 0);
288090087Sobrien
288190087Sobrien  expr = get_mem_expr_from_op (op, &inner_addressp);
288290087Sobrien  return inner_addressp ? 0 : expr;
288390087Sobrien}
288490087Sobrien
288590087Sobrien/* Output operand names for assembler instructions.  OPERANDS is the
288690087Sobrien   operand vector, OPORDER is the order to write the operands, and NOPS
288790087Sobrien   is the number of operands to write.  */
288890087Sobrien
288990087Sobrienstatic void
2890132727Skanoutput_asm_operand_names (rtx *operands, int *oporder, int nops)
289190087Sobrien{
289290087Sobrien  int wrote = 0;
289390087Sobrien  int i;
289490087Sobrien
289590087Sobrien  for (i = 0; i < nops; i++)
289690087Sobrien    {
289790087Sobrien      int addressp;
2898132727Skan      rtx op = operands[oporder[i]];
2899132727Skan      tree expr = get_mem_expr_from_op (op, &addressp);
290090087Sobrien
2901132727Skan      fprintf (asm_out_file, "%c%s",
2902132727Skan	       wrote ? ',' : '\t', wrote ? "" : ASM_COMMENT_START);
2903132727Skan      wrote = 1;
290490087Sobrien      if (expr)
290590087Sobrien	{
2906132727Skan	  fprintf (asm_out_file, "%s",
290790087Sobrien		   addressp ? "*" : "");
290890087Sobrien	  print_mem_expr (asm_out_file, expr);
290990087Sobrien	  wrote = 1;
291090087Sobrien	}
2911132727Skan      else if (REG_P (op) && ORIGINAL_REGNO (op)
2912132727Skan	       && ORIGINAL_REGNO (op) != REGNO (op))
2913132727Skan	fprintf (asm_out_file, " tmp%i", ORIGINAL_REGNO (op));
291490087Sobrien    }
291590087Sobrien}
291690087Sobrien
291718334Speter/* Output text from TEMPLATE to the assembler output file,
291818334Speter   obeying %-directions to substitute operands taken from
291918334Speter   the vector OPERANDS.
292018334Speter
292118334Speter   %N (for N a digit) means print operand N in usual manner.
292218334Speter   %lN means require operand N to be a CODE_LABEL or LABEL_REF
292318334Speter      and print the label name with no punctuation.
292418334Speter   %cN means require operand N to be a constant
292518334Speter      and print the constant expression with no punctuation.
292618334Speter   %aN means expect operand N to be a memory address
292718334Speter      (not a memory reference!) and print a reference
292818334Speter      to that address.
292918334Speter   %nN means expect operand N to be a constant
293018334Speter      and print a constant expression for minus the value
293118334Speter      of the operand, with no other punctuation.  */
293218334Speter
293318334Spetervoid
2934132727Skanoutput_asm_insn (const char *template, rtx *operands)
293518334Speter{
293690087Sobrien  const char *p;
293790087Sobrien  int c;
293890087Sobrien#ifdef ASSEMBLER_DIALECT
293990087Sobrien  int dialect = 0;
294090087Sobrien#endif
294190087Sobrien  int oporder[MAX_RECOG_OPERANDS];
294290087Sobrien  char opoutput[MAX_RECOG_OPERANDS];
294390087Sobrien  int ops = 0;
294418334Speter
294518334Speter  /* An insn may return a null string template
294618334Speter     in a case where no assembler code is needed.  */
294718334Speter  if (*template == 0)
294818334Speter    return;
294918334Speter
295090087Sobrien  memset (opoutput, 0, sizeof opoutput);
295118334Speter  p = template;
295218334Speter  putc ('\t', asm_out_file);
295318334Speter
295418334Speter#ifdef ASM_OUTPUT_OPCODE
295518334Speter  ASM_OUTPUT_OPCODE (asm_out_file, p);
295618334Speter#endif
295718334Speter
295850503Sobrien  while ((c = *p++))
295918334Speter    switch (c)
296018334Speter      {
296118334Speter      case '\n':
296290087Sobrien	if (flag_verbose_asm)
296390087Sobrien	  output_asm_operand_names (operands, oporder, ops);
296490087Sobrien	if (flag_print_asm_name)
296590087Sobrien	  output_asm_name ();
296690087Sobrien
296790087Sobrien	ops = 0;
296890087Sobrien	memset (opoutput, 0, sizeof opoutput);
296990087Sobrien
297018334Speter	putc (c, asm_out_file);
297118334Speter#ifdef ASM_OUTPUT_OPCODE
297218334Speter	while ((c = *p) == '\t')
297318334Speter	  {
297418334Speter	    putc (c, asm_out_file);
297518334Speter	    p++;
297618334Speter	  }
297718334Speter	ASM_OUTPUT_OPCODE (asm_out_file, p);
297818334Speter#endif
297918334Speter	break;
298018334Speter
298118334Speter#ifdef ASSEMBLER_DIALECT
298218334Speter      case '{':
298350503Sobrien	{
298490087Sobrien	  int i;
298590087Sobrien
298690087Sobrien	  if (dialect)
298790087Sobrien	    output_operand_lossage ("nested assembly dialect alternatives");
298890087Sobrien	  else
298990087Sobrien	    dialect = 1;
299090087Sobrien
299150503Sobrien	  /* If we want the first dialect, do nothing.  Otherwise, skip
299250503Sobrien	     DIALECT_NUMBER of strings ending with '|'.  */
299350503Sobrien	  for (i = 0; i < dialect_number; i++)
299450503Sobrien	    {
299590087Sobrien	      while (*p && *p != '}' && *p++ != '|')
299650503Sobrien		;
299790087Sobrien	      if (*p == '}')
299890087Sobrien		break;
299950503Sobrien	      if (*p == '|')
300050503Sobrien		p++;
300150503Sobrien	    }
300290087Sobrien
300390087Sobrien	  if (*p == '\0')
300490087Sobrien	    output_operand_lossage ("unterminated assembly dialect alternative");
300550503Sobrien	}
300618334Speter	break;
300718334Speter
300818334Speter      case '|':
300990087Sobrien	if (dialect)
301090087Sobrien	  {
301190087Sobrien	    /* Skip to close brace.  */
301290087Sobrien	    do
301390087Sobrien	      {
301490087Sobrien		if (*p == '\0')
301590087Sobrien		  {
301690087Sobrien		    output_operand_lossage ("unterminated assembly dialect alternative");
301790087Sobrien		    break;
301890087Sobrien		  }
301990087Sobrien	      }
302090087Sobrien	    while (*p++ != '}');
302190087Sobrien	    dialect = 0;
302290087Sobrien	  }
302390087Sobrien	else
302490087Sobrien	  putc (c, asm_out_file);
302518334Speter	break;
302618334Speter
302718334Speter      case '}':
302890087Sobrien	if (! dialect)
302990087Sobrien	  putc (c, asm_out_file);
303090087Sobrien	dialect = 0;
303118334Speter	break;
303218334Speter#endif
303318334Speter
303418334Speter      case '%':
303518334Speter	/* %% outputs a single %.  */
303618334Speter	if (*p == '%')
303718334Speter	  {
303818334Speter	    p++;
303918334Speter	    putc (c, asm_out_file);
304018334Speter	  }
304118334Speter	/* %= outputs a number which is unique to each insn in the entire
304218334Speter	   compilation.  This is useful for making local labels that are
304318334Speter	   referred to more than once in a given insn.  */
304418334Speter	else if (*p == '=')
304518334Speter	  {
304618334Speter	    p++;
304718334Speter	    fprintf (asm_out_file, "%d", insn_counter);
304818334Speter	  }
304918334Speter	/* % followed by a letter and some digits
305018334Speter	   outputs an operand in a special way depending on the letter.
305118334Speter	   Letters `acln' are implemented directly.
305218334Speter	   Other letters are passed to `output_operand' so that
305318334Speter	   the PRINT_OPERAND macro can define them.  */
305490087Sobrien	else if (ISALPHA (*p))
305518334Speter	  {
305618334Speter	    int letter = *p++;
3057169699Skan	    unsigned long opnum;
3058169699Skan	    char *endptr;
305918334Speter
3060169699Skan	    opnum = strtoul (p, &endptr, 10);
3061169699Skan
3062169699Skan	    if (endptr == p)
3063169699Skan	      output_operand_lossage ("operand number missing "
3064169699Skan				      "after %%-letter");
3065169699Skan	    else if (this_is_asm_operands && opnum >= insn_noperands)
306618334Speter	      output_operand_lossage ("operand number out of range");
306718334Speter	    else if (letter == 'l')
3068169699Skan	      output_asm_label (operands[opnum]);
306918334Speter	    else if (letter == 'a')
3070169699Skan	      output_address (operands[opnum]);
307118334Speter	    else if (letter == 'c')
307218334Speter	      {
3073169699Skan		if (CONSTANT_ADDRESS_P (operands[opnum]))
3074169699Skan		  output_addr_const (asm_out_file, operands[opnum]);
307518334Speter		else
3076169699Skan		  output_operand (operands[opnum], 'c');
307718334Speter	      }
307818334Speter	    else if (letter == 'n')
307918334Speter	      {
3080169699Skan		if (GET_CODE (operands[opnum]) == CONST_INT)
308150503Sobrien		  fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
3082169699Skan			   - INTVAL (operands[opnum]));
308318334Speter		else
308418334Speter		  {
308518334Speter		    putc ('-', asm_out_file);
3086169699Skan		    output_addr_const (asm_out_file, operands[opnum]);
308718334Speter		  }
308818334Speter	      }
308918334Speter	    else
3090169699Skan	      output_operand (operands[opnum], letter);
309190087Sobrien
3092169699Skan	    if (!opoutput[opnum])
3093169699Skan	      oporder[ops++] = opnum;
3094169699Skan	    opoutput[opnum] = 1;
309590087Sobrien
3096169699Skan	    p = endptr;
3097169699Skan	    c = *p;
309818334Speter	  }
309918334Speter	/* % followed by a digit outputs an operand the default way.  */
310090087Sobrien	else if (ISDIGIT (*p))
310118334Speter	  {
3102169699Skan	    unsigned long opnum;
3103169699Skan	    char *endptr;
3104169699Skan
3105169699Skan	    opnum = strtoul (p, &endptr, 10);
3106169699Skan	    if (this_is_asm_operands && opnum >= insn_noperands)
310718334Speter	      output_operand_lossage ("operand number out of range");
310818334Speter	    else
3109169699Skan	      output_operand (operands[opnum], 0);
311090087Sobrien
3111169699Skan	    if (!opoutput[opnum])
3112169699Skan	      oporder[ops++] = opnum;
3113169699Skan	    opoutput[opnum] = 1;
311490087Sobrien
3115169699Skan	    p = endptr;
3116169699Skan	    c = *p;
311718334Speter	  }
311818334Speter	/* % followed by punctuation: output something for that
311918334Speter	   punctuation character alone, with no operand.
312018334Speter	   The PRINT_OPERAND macro decides what is actually done.  */
312118334Speter#ifdef PRINT_OPERAND_PUNCT_VALID_P
312290087Sobrien	else if (PRINT_OPERAND_PUNCT_VALID_P ((unsigned char) *p))
312318334Speter	  output_operand (NULL_RTX, *p++);
312418334Speter#endif
312518334Speter	else
312618334Speter	  output_operand_lossage ("invalid %%-code");
312718334Speter	break;
312818334Speter
312918334Speter      default:
313018334Speter	putc (c, asm_out_file);
313118334Speter      }
313218334Speter
313390087Sobrien  /* Write out the variable names for operands, if we know them.  */
313490087Sobrien  if (flag_verbose_asm)
313590087Sobrien    output_asm_operand_names (operands, oporder, ops);
313690087Sobrien  if (flag_print_asm_name)
313790087Sobrien    output_asm_name ();
313818334Speter
313918334Speter  putc ('\n', asm_out_file);
314018334Speter}
314118334Speter
314218334Speter/* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol.  */
314318334Speter
314418334Spetervoid
3145132727Skanoutput_asm_label (rtx x)
314618334Speter{
314718334Speter  char buf[256];
314818334Speter
314918334Speter  if (GET_CODE (x) == LABEL_REF)
315090087Sobrien    x = XEXP (x, 0);
3151169699Skan  if (LABEL_P (x)
3152169699Skan      || (NOTE_P (x)
315390087Sobrien	  && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL))
315418334Speter    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
315518334Speter  else
3156169699Skan    output_operand_lossage ("'%%l' operand isn't a label");
315718334Speter
315818334Speter  assemble_name (asm_out_file, buf);
315918334Speter}
316018334Speter
316118334Speter/* Print operand X using machine-dependent assembler syntax.
316218334Speter   The macro PRINT_OPERAND is defined just to control this function.
316318334Speter   CODE is a non-digit that preceded the operand-number in the % spec,
316418334Speter   such as 'z' if the spec was `%z3'.  CODE is 0 if there was no char
316518334Speter   between the % and the digits.
316618334Speter   When CODE is a non-letter, X is 0.
316718334Speter
316818334Speter   The meanings of the letters are machine-dependent and controlled
316918334Speter   by PRINT_OPERAND.  */
317018334Speter
317118334Speterstatic void
3172132727Skanoutput_operand (rtx x, int code ATTRIBUTE_UNUSED)
317318334Speter{
317418334Speter  if (x && GET_CODE (x) == SUBREG)
317590087Sobrien    x = alter_subreg (&x);
317618334Speter
3177169699Skan  /* X must not be a pseudo reg.  */
3178169699Skan  gcc_assert (!x || !REG_P (x) || REGNO (x) < FIRST_PSEUDO_REGISTER);
317918334Speter
318018334Speter  PRINT_OPERAND (asm_out_file, x, code);
318118334Speter}
318218334Speter
318318334Speter/* Print a memory reference operand for address X
318418334Speter   using machine-dependent assembler syntax.
318518334Speter   The macro PRINT_OPERAND_ADDRESS exists just to control this function.  */
318618334Speter
318718334Spetervoid
3188132727Skanoutput_address (rtx x)
318918334Speter{
319090087Sobrien  walk_alter_subreg (&x);
319118334Speter  PRINT_OPERAND_ADDRESS (asm_out_file, x);
319218334Speter}
319318334Speter
319418334Speter/* Print an integer constant expression in assembler syntax.
319518334Speter   Addition and subtraction are the only arithmetic
319618334Speter   that may appear in these expressions.  */
319718334Speter
319818334Spetervoid
3199132727Skanoutput_addr_const (FILE *file, rtx x)
320018334Speter{
320118334Speter  char buf[256];
320218334Speter
320318334Speter restart:
320418334Speter  switch (GET_CODE (x))
320518334Speter    {
320618334Speter    case PC:
320790087Sobrien      putc ('.', file);
320818334Speter      break;
320918334Speter
321018334Speter    case SYMBOL_REF:
3211169699Skan      if (SYMBOL_REF_DECL (x))
3212169699Skan	mark_decl_referenced (SYMBOL_REF_DECL (x));
321390087Sobrien#ifdef ASM_OUTPUT_SYMBOL_REF
321490087Sobrien      ASM_OUTPUT_SYMBOL_REF (file, x);
321590087Sobrien#else
321618334Speter      assemble_name (file, XSTR (x, 0));
321790087Sobrien#endif
321818334Speter      break;
321918334Speter
322018334Speter    case LABEL_REF:
322190087Sobrien      x = XEXP (x, 0);
322290087Sobrien      /* Fall through.  */
322318334Speter    case CODE_LABEL:
322418334Speter      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
322590087Sobrien#ifdef ASM_OUTPUT_LABEL_REF
322690087Sobrien      ASM_OUTPUT_LABEL_REF (file, buf);
322790087Sobrien#else
322818334Speter      assemble_name (file, buf);
322990087Sobrien#endif
323018334Speter      break;
323118334Speter
323218334Speter    case CONST_INT:
323350503Sobrien      fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
323418334Speter      break;
323518334Speter
323618334Speter    case CONST:
323718334Speter      /* This used to output parentheses around the expression,
323818334Speter	 but that does not work on the 386 (either ATT or BSD assembler).  */
323918334Speter      output_addr_const (file, XEXP (x, 0));
324018334Speter      break;
324118334Speter
324218334Speter    case CONST_DOUBLE:
324318334Speter      if (GET_MODE (x) == VOIDmode)
324418334Speter	{
324518334Speter	  /* We can use %d if the number is one word and positive.  */
324618334Speter	  if (CONST_DOUBLE_HIGH (x))
324750503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
324818334Speter		     CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
324990087Sobrien	  else if (CONST_DOUBLE_LOW (x) < 0)
325050503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
325118334Speter	  else
325250503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
325318334Speter	}
325418334Speter      else
325518334Speter	/* We can't handle floating point constants;
325618334Speter	   PRINT_OPERAND must handle them.  */
325718334Speter	output_operand_lossage ("floating constant misused");
325818334Speter      break;
325918334Speter
326018334Speter    case PLUS:
326118334Speter      /* Some assemblers need integer constants to appear last (eg masm).  */
326218334Speter      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
326318334Speter	{
326418334Speter	  output_addr_const (file, XEXP (x, 1));
326518334Speter	  if (INTVAL (XEXP (x, 0)) >= 0)
326618334Speter	    fprintf (file, "+");
326718334Speter	  output_addr_const (file, XEXP (x, 0));
326818334Speter	}
326918334Speter      else
327018334Speter	{
327118334Speter	  output_addr_const (file, XEXP (x, 0));
327290087Sobrien	  if (GET_CODE (XEXP (x, 1)) != CONST_INT
327390087Sobrien	      || INTVAL (XEXP (x, 1)) >= 0)
327418334Speter	    fprintf (file, "+");
327518334Speter	  output_addr_const (file, XEXP (x, 1));
327618334Speter	}
327718334Speter      break;
327818334Speter
327918334Speter    case MINUS:
328018334Speter      /* Avoid outputting things like x-x or x+5-x,
328118334Speter	 since some assemblers can't handle that.  */
328218334Speter      x = simplify_subtraction (x);
328318334Speter      if (GET_CODE (x) != MINUS)
328418334Speter	goto restart;
328518334Speter
328618334Speter      output_addr_const (file, XEXP (x, 0));
328718334Speter      fprintf (file, "-");
328890087Sobrien      if ((GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0)
328990087Sobrien	  || GET_CODE (XEXP (x, 1)) == PC
329090087Sobrien	  || GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
329190087Sobrien	output_addr_const (file, XEXP (x, 1));
329290087Sobrien      else
329318334Speter	{
329490087Sobrien	  fputs (targetm.asm_out.open_paren, file);
329518334Speter	  output_addr_const (file, XEXP (x, 1));
329690087Sobrien	  fputs (targetm.asm_out.close_paren, file);
329718334Speter	}
329818334Speter      break;
329918334Speter
330018334Speter    case ZERO_EXTEND:
330118334Speter    case SIGN_EXTEND:
330296281Sobrien    case SUBREG:
330318334Speter      output_addr_const (file, XEXP (x, 0));
330418334Speter      break;
330518334Speter
330618334Speter    default:
330790087Sobrien#ifdef OUTPUT_ADDR_CONST_EXTRA
330890087Sobrien      OUTPUT_ADDR_CONST_EXTRA (file, x, fail);
330990087Sobrien      break;
331090087Sobrien
331190087Sobrien    fail:
331290087Sobrien#endif
331318334Speter      output_operand_lossage ("invalid expression as operand");
331418334Speter    }
331518334Speter}
331618334Speter
331718334Speter/* A poor man's fprintf, with the added features of %I, %R, %L, and %U.
331818334Speter   %R prints the value of REGISTER_PREFIX.
331918334Speter   %L prints the value of LOCAL_LABEL_PREFIX.
332018334Speter   %U prints the value of USER_LABEL_PREFIX.
332118334Speter   %I prints the value of IMMEDIATE_PREFIX.
332218334Speter   %O runs ASM_OUTPUT_OPCODE to transform what follows in the string.
3323132727Skan   Also supported are %d, %i, %u, %x, %X, %o, %c, %s and %%.
332418334Speter
332518334Speter   We handle alternate assembler dialects here, just like output_asm_insn.  */
332618334Speter
332718334Spetervoid
3328132727Skanasm_fprintf (FILE *file, const char *p, ...)
332918334Speter{
333018334Speter  char buf[10];
333118334Speter  char *q, c;
3332132727Skan  va_list argptr;
333318334Speter
3334132727Skan  va_start (argptr, p);
333518334Speter
333618334Speter  buf[0] = '%';
333718334Speter
333850503Sobrien  while ((c = *p++))
333918334Speter    switch (c)
334018334Speter      {
334118334Speter#ifdef ASSEMBLER_DIALECT
334218334Speter      case '{':
334350503Sobrien	{
334450503Sobrien	  int i;
334518334Speter
334650503Sobrien	  /* If we want the first dialect, do nothing.  Otherwise, skip
334750503Sobrien	     DIALECT_NUMBER of strings ending with '|'.  */
334850503Sobrien	  for (i = 0; i < dialect_number; i++)
334950503Sobrien	    {
335050503Sobrien	      while (*p && *p++ != '|')
335150503Sobrien		;
335250503Sobrien
335350503Sobrien	      if (*p == '|')
335450503Sobrien		p++;
335590087Sobrien	    }
335650503Sobrien	}
335718334Speter	break;
335818334Speter
335918334Speter      case '|':
336018334Speter	/* Skip to close brace.  */
336118334Speter	while (*p && *p++ != '}')
336218334Speter	  ;
336318334Speter	break;
336418334Speter
336518334Speter      case '}':
336618334Speter	break;
336718334Speter#endif
336818334Speter
336918334Speter      case '%':
337018334Speter	c = *p++;
337118334Speter	q = &buf[1];
3372132727Skan	while (strchr ("-+ #0", c))
3373132727Skan	  {
3374132727Skan	    *q++ = c;
3375132727Skan	    c = *p++;
3376132727Skan	  }
337790087Sobrien	while (ISDIGIT (c) || c == '.')
337818334Speter	  {
337918334Speter	    *q++ = c;
338018334Speter	    c = *p++;
338118334Speter	  }
338218334Speter	switch (c)
338318334Speter	  {
338418334Speter	  case '%':
3385132727Skan	    putc ('%', file);
338618334Speter	    break;
338718334Speter
338818334Speter	  case 'd':  case 'i':  case 'u':
3389132727Skan	  case 'x':  case 'X':  case 'o':
3390132727Skan	  case 'c':
339118334Speter	    *q++ = c;
339218334Speter	    *q = 0;
339318334Speter	    fprintf (file, buf, va_arg (argptr, int));
339418334Speter	    break;
339518334Speter
339618334Speter	  case 'w':
3397132727Skan	    /* This is a prefix to the 'd', 'i', 'u', 'x', 'X', and
3398132727Skan	       'o' cases, but we do not check for those cases.  It
3399132727Skan	       means that the value is a HOST_WIDE_INT, which may be
3400132727Skan	       either `long' or `long long'.  */
3401132727Skan	    memcpy (q, HOST_WIDE_INT_PRINT, strlen (HOST_WIDE_INT_PRINT));
3402132727Skan	    q += strlen (HOST_WIDE_INT_PRINT);
340318334Speter	    *q++ = *p++;
340418334Speter	    *q = 0;
340518334Speter	    fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT));
340618334Speter	    break;
340718334Speter
340818334Speter	  case 'l':
340918334Speter	    *q++ = c;
3410132727Skan#ifdef HAVE_LONG_LONG
3411132727Skan	    if (*p == 'l')
3412132727Skan	      {
3413132727Skan		*q++ = *p++;
3414132727Skan		*q++ = *p++;
3415132727Skan		*q = 0;
3416132727Skan		fprintf (file, buf, va_arg (argptr, long long));
3417132727Skan	      }
3418132727Skan	    else
3419132727Skan#endif
3420132727Skan	      {
3421132727Skan		*q++ = *p++;
3422132727Skan		*q = 0;
3423132727Skan		fprintf (file, buf, va_arg (argptr, long));
3424132727Skan	      }
342518334Speter
342618334Speter	    break;
342718334Speter
342818334Speter	  case 's':
342918334Speter	    *q++ = c;
343018334Speter	    *q = 0;
343118334Speter	    fprintf (file, buf, va_arg (argptr, char *));
343218334Speter	    break;
343318334Speter
343418334Speter	  case 'O':
343518334Speter#ifdef ASM_OUTPUT_OPCODE
343618334Speter	    ASM_OUTPUT_OPCODE (asm_out_file, p);
343718334Speter#endif
343818334Speter	    break;
343918334Speter
344018334Speter	  case 'R':
344118334Speter#ifdef REGISTER_PREFIX
344218334Speter	    fprintf (file, "%s", REGISTER_PREFIX);
344318334Speter#endif
344418334Speter	    break;
344518334Speter
344618334Speter	  case 'I':
344718334Speter#ifdef IMMEDIATE_PREFIX
344818334Speter	    fprintf (file, "%s", IMMEDIATE_PREFIX);
344918334Speter#endif
345018334Speter	    break;
345118334Speter
345218334Speter	  case 'L':
345318334Speter#ifdef LOCAL_LABEL_PREFIX
345418334Speter	    fprintf (file, "%s", LOCAL_LABEL_PREFIX);
345518334Speter#endif
345618334Speter	    break;
345718334Speter
345818334Speter	  case 'U':
345952515Sobrien	    fputs (user_label_prefix, file);
346018334Speter	    break;
346118334Speter
346290087Sobrien#ifdef ASM_FPRINTF_EXTENSIONS
3463132727Skan	    /* Uppercase letters are reserved for general use by asm_fprintf
346490087Sobrien	       and so are not available to target specific code.  In order to
346590087Sobrien	       prevent the ASM_FPRINTF_EXTENSIONS macro from using them then,
346690087Sobrien	       they are defined here.  As they get turned into real extensions
346790087Sobrien	       to asm_fprintf they should be removed from this list.  */
346890087Sobrien	  case 'A': case 'B': case 'C': case 'D': case 'E':
346990087Sobrien	  case 'F': case 'G': case 'H': case 'J': case 'K':
347090087Sobrien	  case 'M': case 'N': case 'P': case 'Q': case 'S':
347190087Sobrien	  case 'T': case 'V': case 'W': case 'Y': case 'Z':
347290087Sobrien	    break;
347390087Sobrien
347490087Sobrien	  ASM_FPRINTF_EXTENSIONS (file, argptr, p)
347590087Sobrien#endif
347618334Speter	  default:
3477169699Skan	    gcc_unreachable ();
347818334Speter	  }
347918334Speter	break;
348018334Speter
348118334Speter      default:
3482132727Skan	putc (c, file);
348318334Speter      }
3484132727Skan  va_end (argptr);
348518334Speter}
348618334Speter
348718334Speter/* Split up a CONST_DOUBLE or integer constant rtx
348818334Speter   into two rtx's for single words,
348918334Speter   storing in *FIRST the word that comes first in memory in the target
349018334Speter   and in *SECOND the other.  */
349118334Speter
349218334Spetervoid
3493132727Skansplit_double (rtx value, rtx *first, rtx *second)
349418334Speter{
349518334Speter  if (GET_CODE (value) == CONST_INT)
349618334Speter    {
349718334Speter      if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD))
349818334Speter	{
349918334Speter	  /* In this case the CONST_INT holds both target words.
350050503Sobrien	     Extract the bits from it into two word-sized pieces.
350150503Sobrien	     Sign extend each half to HOST_WIDE_INT.  */
350290087Sobrien	  unsigned HOST_WIDE_INT low, high;
350390087Sobrien	  unsigned HOST_WIDE_INT mask, sign_bit, sign_extend;
350418334Speter
350590087Sobrien	  /* Set sign_bit to the most significant bit of a word.  */
350690087Sobrien	  sign_bit = 1;
350790087Sobrien	  sign_bit <<= BITS_PER_WORD - 1;
350890087Sobrien
350990087Sobrien	  /* Set mask so that all bits of the word are set.  We could
351090087Sobrien	     have used 1 << BITS_PER_WORD instead of basing the
351190087Sobrien	     calculation on sign_bit.  However, on machines where
351290087Sobrien	     HOST_BITS_PER_WIDE_INT == BITS_PER_WORD, it could cause a
351390087Sobrien	     compiler warning, even though the code would never be
351490087Sobrien	     executed.  */
351590087Sobrien	  mask = sign_bit << 1;
351690087Sobrien	  mask--;
351790087Sobrien
351890087Sobrien	  /* Set sign_extend as any remaining bits.  */
351990087Sobrien	  sign_extend = ~mask;
352090087Sobrien
352190087Sobrien	  /* Pick the lower word and sign-extend it.  */
352290087Sobrien	  low = INTVAL (value);
352390087Sobrien	  low &= mask;
352490087Sobrien	  if (low & sign_bit)
352590087Sobrien	    low |= sign_extend;
352690087Sobrien
352790087Sobrien	  /* Pick the higher word, shifted to the least significant
352890087Sobrien	     bits, and sign-extend it.  */
352990087Sobrien	  high = INTVAL (value);
353090087Sobrien	  high >>= BITS_PER_WORD - 1;
353190087Sobrien	  high >>= 1;
353290087Sobrien	  high &= mask;
353390087Sobrien	  if (high & sign_bit)
353490087Sobrien	    high |= sign_extend;
353590087Sobrien
353690087Sobrien	  /* Store the words in the target machine order.  */
353718334Speter	  if (WORDS_BIG_ENDIAN)
353818334Speter	    {
353990087Sobrien	      *first = GEN_INT (high);
354090087Sobrien	      *second = GEN_INT (low);
354118334Speter	    }
354218334Speter	  else
354318334Speter	    {
354490087Sobrien	      *first = GEN_INT (low);
354590087Sobrien	      *second = GEN_INT (high);
354618334Speter	    }
354718334Speter	}
354818334Speter      else
354918334Speter	{
355018334Speter	  /* The rule for using CONST_INT for a wider mode
355118334Speter	     is that we regard the value as signed.
355218334Speter	     So sign-extend it.  */
355318334Speter	  rtx high = (INTVAL (value) < 0 ? constm1_rtx : const0_rtx);
355418334Speter	  if (WORDS_BIG_ENDIAN)
355518334Speter	    {
355618334Speter	      *first = high;
355718334Speter	      *second = value;
355818334Speter	    }
355918334Speter	  else
356018334Speter	    {
356118334Speter	      *first = value;
356218334Speter	      *second = high;
356318334Speter	    }
356418334Speter	}
356518334Speter    }
356618334Speter  else if (GET_CODE (value) != CONST_DOUBLE)
356718334Speter    {
356818334Speter      if (WORDS_BIG_ENDIAN)
356918334Speter	{
357018334Speter	  *first = const0_rtx;
357118334Speter	  *second = value;
357218334Speter	}
357318334Speter      else
357418334Speter	{
357518334Speter	  *first = value;
357618334Speter	  *second = const0_rtx;
357718334Speter	}
357818334Speter    }
357918334Speter  else if (GET_MODE (value) == VOIDmode
358018334Speter	   /* This is the old way we did CONST_DOUBLE integers.  */
358118334Speter	   || GET_MODE_CLASS (GET_MODE (value)) == MODE_INT)
358218334Speter    {
358318334Speter      /* In an integer, the words are defined as most and least significant.
358418334Speter	 So order them by the target's convention.  */
358518334Speter      if (WORDS_BIG_ENDIAN)
358618334Speter	{
358718334Speter	  *first = GEN_INT (CONST_DOUBLE_HIGH (value));
358818334Speter	  *second = GEN_INT (CONST_DOUBLE_LOW (value));
358918334Speter	}
359018334Speter      else
359118334Speter	{
359218334Speter	  *first = GEN_INT (CONST_DOUBLE_LOW (value));
359318334Speter	  *second = GEN_INT (CONST_DOUBLE_HIGH (value));
359418334Speter	}
359518334Speter    }
359618334Speter  else
359718334Speter    {
359890087Sobrien      REAL_VALUE_TYPE r;
359990087Sobrien      long l[2];
360018334Speter      REAL_VALUE_FROM_CONST_DOUBLE (r, value);
360118334Speter
360218334Speter      /* Note, this converts the REAL_VALUE_TYPE to the target's
360318334Speter	 format, splits up the floating point double and outputs
360418334Speter	 exactly 32 bits of it into each of l[0] and l[1] --
360550503Sobrien	 not necessarily BITS_PER_WORD bits.  */
360618334Speter      REAL_VALUE_TO_TARGET_DOUBLE (r, l);
360718334Speter
360852515Sobrien      /* If 32 bits is an entire word for the target, but not for the host,
360952515Sobrien	 then sign-extend on the host so that the number will look the same
361052515Sobrien	 way on the host that it would on the target.  See for instance
361152515Sobrien	 simplify_unary_operation.  The #if is needed to avoid compiler
361252515Sobrien	 warnings.  */
361352515Sobrien
361452515Sobrien#if HOST_BITS_PER_LONG > 32
361552515Sobrien      if (BITS_PER_WORD < HOST_BITS_PER_LONG && BITS_PER_WORD == 32)
361652515Sobrien	{
361752515Sobrien	  if (l[0] & ((long) 1 << 31))
361852515Sobrien	    l[0] |= ((long) (-1) << 32);
361952515Sobrien	  if (l[1] & ((long) 1 << 31))
362052515Sobrien	    l[1] |= ((long) (-1) << 32);
362152515Sobrien	}
362252515Sobrien#endif
362352515Sobrien
3624169699Skan      *first = GEN_INT (l[0]);
3625169699Skan      *second = GEN_INT (l[1]);
362618334Speter    }
362718334Speter}
362818334Speter
362918334Speter/* Return nonzero if this function has no function calls.  */
363018334Speter
363118334Speterint
3632132727Skanleaf_function_p (void)
363318334Speter{
363418334Speter  rtx insn;
363590087Sobrien  rtx link;
363618334Speter
363790087Sobrien  if (current_function_profile || profile_arc_flag)
363818334Speter    return 0;
363918334Speter
364018334Speter  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
364118334Speter    {
3642169699Skan      if (CALL_P (insn)
364390087Sobrien	  && ! SIBLING_CALL_P (insn))
364418334Speter	return 0;
3645169699Skan      if (NONJUMP_INSN_P (insn)
364618334Speter	  && GET_CODE (PATTERN (insn)) == SEQUENCE
3647169699Skan	  && CALL_P (XVECEXP (PATTERN (insn), 0, 0))
364890087Sobrien	  && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
364918334Speter	return 0;
365018334Speter    }
365190087Sobrien  for (link = current_function_epilogue_delay_list;
365290087Sobrien       link;
365390087Sobrien       link = XEXP (link, 1))
365418334Speter    {
365590087Sobrien      insn = XEXP (link, 0);
365690087Sobrien
3657169699Skan      if (CALL_P (insn)
365890087Sobrien	  && ! SIBLING_CALL_P (insn))
365918334Speter	return 0;
3660169699Skan      if (NONJUMP_INSN_P (insn)
366190087Sobrien	  && GET_CODE (PATTERN (insn)) == SEQUENCE
3662169699Skan	  && CALL_P (XVECEXP (PATTERN (insn), 0, 0))
366390087Sobrien	  && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
366418334Speter	return 0;
366518334Speter    }
366618334Speter
366718334Speter  return 1;
366818334Speter}
366918334Speter
3670117404Skan/* Return 1 if branch is a forward branch.
367190087Sobrien   Uses insn_shuid array, so it works only in the final pass.  May be used by
367290087Sobrien   output templates to customary add branch prediction hints.
367390087Sobrien */
367490087Sobrienint
3675132727Skanfinal_forward_branch_p (rtx insn)
367690087Sobrien{
367790087Sobrien  int insn_id, label_id;
3678169699Skan
3679169699Skan  gcc_assert (uid_shuid);
368090087Sobrien  insn_id = INSN_SHUID (insn);
368190087Sobrien  label_id = INSN_SHUID (JUMP_LABEL (insn));
368290087Sobrien  /* We've hit some insns that does not have id information available.  */
3683169699Skan  gcc_assert (insn_id && label_id);
368490087Sobrien  return insn_id < label_id;
368590087Sobrien}
368690087Sobrien
368718334Speter/* On some machines, a function with no call insns
368818334Speter   can run faster if it doesn't create its own register window.
368918334Speter   When output, the leaf function should use only the "output"
369018334Speter   registers.  Ordinarily, the function would be compiled to use
369118334Speter   the "input" registers to find its arguments; it is a candidate
369218334Speter   for leaf treatment if it uses only the "input" registers.
369318334Speter   Leaf function treatment means renumbering so the function
369418334Speter   uses the "output" registers instead.  */
369518334Speter
369618334Speter#ifdef LEAF_REGISTERS
369718334Speter
369818334Speter/* Return 1 if this function uses only the registers that can be
369918334Speter   safely renumbered.  */
370018334Speter
370118334Speterint
3702132727Skanonly_leaf_regs_used (void)
370318334Speter{
370418334Speter  int i;
3705132727Skan  const char *const permitted_reg_in_leaf_functions = LEAF_REGISTERS;
370618334Speter
370718334Speter  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
370850503Sobrien    if ((regs_ever_live[i] || global_regs[i])
370950503Sobrien	&& ! permitted_reg_in_leaf_functions[i])
371050503Sobrien      return 0;
371150503Sobrien
371250503Sobrien  if (current_function_uses_pic_offset_table
371350503Sobrien      && pic_offset_table_rtx != 0
3714169699Skan      && REG_P (pic_offset_table_rtx)
371550503Sobrien      && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
371650503Sobrien    return 0;
371750503Sobrien
371818334Speter  return 1;
371918334Speter}
372018334Speter
372118334Speter/* Scan all instructions and renumber all registers into those
372218334Speter   available in leaf functions.  */
372318334Speter
372418334Speterstatic void
3725132727Skanleaf_renumber_regs (rtx first)
372618334Speter{
372718334Speter  rtx insn;
372818334Speter
372918334Speter  /* Renumber only the actual patterns.
373018334Speter     The reg-notes can contain frame pointer refs,
373118334Speter     and renumbering them could crash, and should not be needed.  */
373218334Speter  for (insn = first; insn; insn = NEXT_INSN (insn))
373390087Sobrien    if (INSN_P (insn))
373418334Speter      leaf_renumber_regs_insn (PATTERN (insn));
373590087Sobrien  for (insn = current_function_epilogue_delay_list;
373690087Sobrien       insn;
373790087Sobrien       insn = XEXP (insn, 1))
373890087Sobrien    if (INSN_P (XEXP (insn, 0)))
373918334Speter      leaf_renumber_regs_insn (PATTERN (XEXP (insn, 0)));
374018334Speter}
374118334Speter
374218334Speter/* Scan IN_RTX and its subexpressions, and renumber all regs into those
374318334Speter   available in leaf functions.  */
374418334Speter
374518334Spetervoid
3746132727Skanleaf_renumber_regs_insn (rtx in_rtx)
374718334Speter{
374890087Sobrien  int i, j;
374990087Sobrien  const char *format_ptr;
375018334Speter
375118334Speter  if (in_rtx == 0)
375218334Speter    return;
375318334Speter
375418334Speter  /* Renumber all input-registers into output-registers.
375518334Speter     renumbered_regs would be 1 for an output-register;
375618334Speter     they  */
375718334Speter
3758169699Skan  if (REG_P (in_rtx))
375918334Speter    {
376018334Speter      int newreg;
376118334Speter
376218334Speter      /* Don't renumber the same reg twice.  */
376318334Speter      if (in_rtx->used)
376418334Speter	return;
376518334Speter
376618334Speter      newreg = REGNO (in_rtx);
376718334Speter      /* Don't try to renumber pseudo regs.  It is possible for a pseudo reg
376818334Speter	 to reach here as part of a REG_NOTE.  */
376918334Speter      if (newreg >= FIRST_PSEUDO_REGISTER)
377018334Speter	{
377118334Speter	  in_rtx->used = 1;
377218334Speter	  return;
377318334Speter	}
377418334Speter      newreg = LEAF_REG_REMAP (newreg);
3775169699Skan      gcc_assert (newreg >= 0);
377618334Speter      regs_ever_live[REGNO (in_rtx)] = 0;
377718334Speter      regs_ever_live[newreg] = 1;
377818334Speter      REGNO (in_rtx) = newreg;
377918334Speter      in_rtx->used = 1;
378018334Speter    }
378118334Speter
378290087Sobrien  if (INSN_P (in_rtx))
378318334Speter    {
378418334Speter      /* Inside a SEQUENCE, we find insns.
378518334Speter	 Renumber just the patterns of these insns,
378618334Speter	 just as we do for the top-level insns.  */
378718334Speter      leaf_renumber_regs_insn (PATTERN (in_rtx));
378818334Speter      return;
378918334Speter    }
379018334Speter
379118334Speter  format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx));
379218334Speter
379318334Speter  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++)
379418334Speter    switch (*format_ptr++)
379518334Speter      {
379618334Speter      case 'e':
379718334Speter	leaf_renumber_regs_insn (XEXP (in_rtx, i));
379818334Speter	break;
379918334Speter
380018334Speter      case 'E':
380118334Speter	if (NULL != XVEC (in_rtx, i))
380218334Speter	  {
380318334Speter	    for (j = 0; j < XVECLEN (in_rtx, i); j++)
380418334Speter	      leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j));
380518334Speter	  }
380618334Speter	break;
380718334Speter
380818334Speter      case 'S':
380918334Speter      case 's':
381018334Speter      case '0':
381118334Speter      case 'i':
381218334Speter      case 'w':
381318334Speter      case 'n':
381418334Speter      case 'u':
381518334Speter	break;
381618334Speter
381718334Speter      default:
3818169699Skan	gcc_unreachable ();
381918334Speter      }
382018334Speter}
382118334Speter#endif
3822132727Skan
3823132727Skan
3824132727Skan/* When -gused is used, emit debug info for only used symbols. But in
3825132727Skan   addition to the standard intercepted debug_hooks there are some direct
3826132727Skan   calls into this file, i.e., dbxout_symbol, dbxout_parms, and dbxout_reg_params.
3827132727Skan   Those routines may also be called from a higher level intercepted routine. So
3828132727Skan   to prevent recording data for an inner call to one of these for an intercept,
3829132727Skan   we maintain an intercept nesting counter (debug_nesting). We only save the
3830132727Skan   intercepted arguments if the nesting is 1.  */
3831132727Skanint debug_nesting = 0;
3832132727Skan
3833132727Skanstatic tree *symbol_queue;
3834132727Skanint symbol_queue_index = 0;
3835132727Skanstatic int symbol_queue_size = 0;
3836132727Skan
3837132727Skan/* Generate the symbols for any queued up type symbols we encountered
3838132727Skan   while generating the type info for some originally used symbol.
3839132727Skan   This might generate additional entries in the queue.  Only when
3840132727Skan   the nesting depth goes to 0 is this routine called.  */
3841132727Skan
3842132727Skanvoid
3843132727Skandebug_flush_symbol_queue (void)
3844132727Skan{
3845132727Skan  int i;
3846132727Skan
3847132727Skan  /* Make sure that additionally queued items are not flushed
3848132727Skan     prematurely.  */
3849132727Skan
3850132727Skan  ++debug_nesting;
3851132727Skan
3852132727Skan  for (i = 0; i < symbol_queue_index; ++i)
3853132727Skan    {
3854169699Skan      /* If we pushed queued symbols then such symbols must be
3855132727Skan         output no matter what anyone else says.  Specifically,
3856132727Skan         we need to make sure dbxout_symbol() thinks the symbol was
3857132727Skan         used and also we need to override TYPE_DECL_SUPPRESS_DEBUG
3858132727Skan         which may be set for outside reasons.  */
3859132727Skan      int saved_tree_used = TREE_USED (symbol_queue[i]);
3860132727Skan      int saved_suppress_debug = TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]);
3861132727Skan      TREE_USED (symbol_queue[i]) = 1;
3862132727Skan      TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = 0;
3863132727Skan
3864132727Skan#ifdef DBX_DEBUGGING_INFO
3865132727Skan      dbxout_symbol (symbol_queue[i], 0);
3866132727Skan#endif
3867132727Skan
3868132727Skan      TREE_USED (symbol_queue[i]) = saved_tree_used;
3869132727Skan      TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = saved_suppress_debug;
3870132727Skan    }
3871132727Skan
3872132727Skan  symbol_queue_index = 0;
3873132727Skan  --debug_nesting;
3874132727Skan}
3875132727Skan
3876132727Skan/* Queue a type symbol needed as part of the definition of a decl
3877132727Skan   symbol.  These symbols are generated when debug_flush_symbol_queue()
3878132727Skan   is called.  */
3879132727Skan
3880132727Skanvoid
3881132727Skandebug_queue_symbol (tree decl)
3882132727Skan{
3883132727Skan  if (symbol_queue_index >= symbol_queue_size)
3884132727Skan    {
3885132727Skan      symbol_queue_size += 10;
3886132727Skan      symbol_queue = xrealloc (symbol_queue,
3887132727Skan			       symbol_queue_size * sizeof (tree));
3888132727Skan    }
3889132727Skan
3890132727Skan  symbol_queue[symbol_queue_index++] = decl;
3891132727Skan}
3892132727Skan
3893132727Skan/* Free symbol queue.  */
3894132727Skanvoid
3895132727Skandebug_free_queue (void)
3896132727Skan{
3897132727Skan  if (symbol_queue)
3898132727Skan    {
3899132727Skan      free (symbol_queue);
3900132727Skan      symbol_queue = NULL;
3901132727Skan      symbol_queue_size = 0;
3902132727Skan    }
3903132727Skan}
3904169699Skan
3905169699Skan/* Turn the RTL into assembly.  */
3906169699Skanstatic unsigned int
3907169699Skanrest_of_handle_final (void)
3908169699Skan{
3909169699Skan  rtx x;
3910169699Skan  const char *fnname;
3911169699Skan
3912169699Skan  /* Get the function's name, as described by its RTL.  This may be
3913169699Skan     different from the DECL_NAME name used in the source file.  */
3914169699Skan
3915169699Skan  x = DECL_RTL (current_function_decl);
3916169699Skan  gcc_assert (MEM_P (x));
3917169699Skan  x = XEXP (x, 0);
3918169699Skan  gcc_assert (GET_CODE (x) == SYMBOL_REF);
3919169699Skan  fnname = XSTR (x, 0);
3920169699Skan
3921169699Skan  assemble_start_function (current_function_decl, fnname);
3922169699Skan  final_start_function (get_insns (), asm_out_file, optimize);
3923169699Skan  final (get_insns (), asm_out_file, optimize);
3924169699Skan  final_end_function ();
3925169699Skan
3926169699Skan#ifdef TARGET_UNWIND_INFO
3927169699Skan  /* ??? The IA-64 ".handlerdata" directive must be issued before
3928169699Skan     the ".endp" directive that closes the procedure descriptor.  */
3929169699Skan  output_function_exception_table ();
3930169699Skan#endif
3931169699Skan
3932169699Skan  assemble_end_function (current_function_decl, fnname);
3933169699Skan
3934169699Skan#ifndef TARGET_UNWIND_INFO
3935169699Skan  /* Otherwise, it feels unclean to switch sections in the middle.  */
3936169699Skan  output_function_exception_table ();
3937169699Skan#endif
3938169699Skan
3939169699Skan  user_defined_section_attribute = false;
3940169699Skan
3941169699Skan  if (! quiet_flag)
3942169699Skan    fflush (asm_out_file);
3943169699Skan
3944169699Skan  /* Release all memory allocated by flow.  */
3945169699Skan  free_basic_block_vars ();
3946169699Skan
3947169699Skan  /* Write DBX symbols if requested.  */
3948169699Skan
3949169699Skan  /* Note that for those inline functions where we don't initially
3950169699Skan     know for certain that we will be generating an out-of-line copy,
3951169699Skan     the first invocation of this routine (rest_of_compilation) will
3952169699Skan     skip over this code by doing a `goto exit_rest_of_compilation;'.
3953169699Skan     Later on, wrapup_global_declarations will (indirectly) call
3954169699Skan     rest_of_compilation again for those inline functions that need
3955169699Skan     to have out-of-line copies generated.  During that call, we
3956169699Skan     *will* be routed past here.  */
3957169699Skan
3958169699Skan  timevar_push (TV_SYMOUT);
3959169699Skan  (*debug_hooks->function_decl) (current_function_decl);
3960169699Skan  timevar_pop (TV_SYMOUT);
3961169699Skan  return 0;
3962169699Skan}
3963169699Skan
3964169699Skanstruct tree_opt_pass pass_final =
3965169699Skan{
3966169699Skan  NULL,                                 /* name */
3967169699Skan  NULL,                                 /* gate */
3968169699Skan  rest_of_handle_final,                 /* execute */
3969169699Skan  NULL,                                 /* sub */
3970169699Skan  NULL,                                 /* next */
3971169699Skan  0,                                    /* static_pass_number */
3972169699Skan  TV_FINAL,                             /* tv_id */
3973169699Skan  0,                                    /* properties_required */
3974169699Skan  0,                                    /* properties_provided */
3975169699Skan  0,                                    /* properties_destroyed */
3976169699Skan  0,                                    /* todo_flags_start */
3977169699Skan  TODO_ggc_collect,                     /* todo_flags_finish */
3978169699Skan  0                                     /* letter */
3979169699Skan};
3980169699Skan
3981169699Skan
3982169699Skanstatic unsigned int
3983169699Skanrest_of_handle_shorten_branches (void)
3984169699Skan{
3985169699Skan  /* Shorten branches.  */
3986169699Skan  shorten_branches (get_insns ());
3987169699Skan  return 0;
3988169699Skan}
3989169699Skan
3990169699Skanstruct tree_opt_pass pass_shorten_branches =
3991169699Skan{
3992169699Skan  "shorten",                            /* name */
3993169699Skan  NULL,                                 /* gate */
3994169699Skan  rest_of_handle_shorten_branches,      /* execute */
3995169699Skan  NULL,                                 /* sub */
3996169699Skan  NULL,                                 /* next */
3997169699Skan  0,                                    /* static_pass_number */
3998169699Skan  TV_FINAL,                             /* tv_id */
3999169699Skan  0,                                    /* properties_required */
4000169699Skan  0,                                    /* properties_provided */
4001169699Skan  0,                                    /* properties_destroyed */
4002169699Skan  0,                                    /* todo_flags_start */
4003169699Skan  TODO_dump_func,                       /* todo_flags_finish */
4004169699Skan  0                                     /* letter */
4005169699Skan};
4006169699Skan
4007169699Skan
4008169699Skanstatic unsigned int
4009169699Skanrest_of_clean_state (void)
4010169699Skan{
4011169699Skan  rtx insn, next;
4012169699Skan
4013169699Skan  /* It is very important to decompose the RTL instruction chain here:
4014169699Skan     debug information keeps pointing into CODE_LABEL insns inside the function
4015169699Skan     body.  If these remain pointing to the other insns, we end up preserving
4016169699Skan     whole RTL chain and attached detailed debug info in memory.  */
4017169699Skan  for (insn = get_insns (); insn; insn = next)
4018169699Skan    {
4019169699Skan      next = NEXT_INSN (insn);
4020169699Skan      NEXT_INSN (insn) = NULL;
4021169699Skan      PREV_INSN (insn) = NULL;
4022169699Skan    }
4023169699Skan
4024169699Skan  /* In case the function was not output,
4025169699Skan     don't leave any temporary anonymous types
4026169699Skan     queued up for sdb output.  */
4027169699Skan#ifdef SDB_DEBUGGING_INFO
4028169699Skan  if (write_symbols == SDB_DEBUG)
4029169699Skan    sdbout_types (NULL_TREE);
4030169699Skan#endif
4031169699Skan
4032169699Skan  reload_completed = 0;
4033169699Skan  epilogue_completed = 0;
4034169699Skan  flow2_completed = 0;
4035169699Skan  no_new_pseudos = 0;
4036169699Skan#ifdef STACK_REGS
4037169699Skan  regstack_completed = 0;
4038169699Skan#endif
4039169699Skan
4040169699Skan  /* Clear out the insn_length contents now that they are no
4041169699Skan     longer valid.  */
4042169699Skan  init_insn_lengths ();
4043169699Skan
4044169699Skan  /* Show no temporary slots allocated.  */
4045169699Skan  init_temp_slots ();
4046169699Skan
4047169699Skan  free_basic_block_vars ();
4048169699Skan  free_bb_for_insn ();
4049169699Skan
4050169699Skan
4051169699Skan  if (targetm.binds_local_p (current_function_decl))
4052169699Skan    {
4053169699Skan      int pref = cfun->preferred_stack_boundary;
4054169699Skan      if (cfun->stack_alignment_needed > cfun->preferred_stack_boundary)
4055169699Skan        pref = cfun->stack_alignment_needed;
4056169699Skan      cgraph_rtl_info (current_function_decl)->preferred_incoming_stack_boundary
4057169699Skan        = pref;
4058169699Skan    }
4059169699Skan
4060169699Skan  /* Make sure volatile mem refs aren't considered valid operands for
4061169699Skan     arithmetic insns.  We must call this here if this is a nested inline
4062169699Skan     function, since the above code leaves us in the init_recog state,
4063169699Skan     and the function context push/pop code does not save/restore volatile_ok.
4064169699Skan
4065169699Skan     ??? Maybe it isn't necessary for expand_start_function to call this
4066169699Skan     anymore if we do it here?  */
4067169699Skan
4068169699Skan  init_recog_no_volatile ();
4069169699Skan
4070169699Skan  /* We're done with this function.  Free up memory if we can.  */
4071169699Skan  free_after_parsing (cfun);
4072169699Skan  free_after_compilation (cfun);
4073169699Skan  return 0;
4074169699Skan}
4075169699Skan
4076169699Skanstruct tree_opt_pass pass_clean_state =
4077169699Skan{
4078169699Skan  NULL,                                 /* name */
4079169699Skan  NULL,                                 /* gate */
4080169699Skan  rest_of_clean_state,                  /* execute */
4081169699Skan  NULL,                                 /* sub */
4082169699Skan  NULL,                                 /* next */
4083169699Skan  0,                                    /* static_pass_number */
4084169699Skan  TV_FINAL,                             /* tv_id */
4085169699Skan  0,                                    /* properties_required */
4086169699Skan  0,                                    /* properties_provided */
4087169699Skan  PROP_rtl,                             /* properties_destroyed */
4088169699Skan  0,                                    /* todo_flags_start */
4089169699Skan  0,                                    /* todo_flags_finish */
4090169699Skan  0                                     /* letter */
4091169699Skan};
4092