final.c revision 117404
118334Speter/* Convert RTL to assembler code and output it, for GNU compiler.
290087Sobrien   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
390087Sobrien   1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
418334Speter
590087SobrienThis file is part of GCC.
618334Speter
790087SobrienGCC is free software; you can redistribute it and/or modify it under
890087Sobrienthe terms of the GNU General Public License as published by the Free
990087SobrienSoftware Foundation; either version 2, or (at your option) any later
1090087Sobrienversion.
1118334Speter
1290087SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1390087SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1490087SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1590087Sobrienfor more details.
1618334Speter
1718334SpeterYou should have received a copy of the GNU General Public License
1890087Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
1990087SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
2090087Sobrien02111-1307, USA.  */
2118334Speter
2218334Speter/* This is the final pass of the compiler.
2318334Speter   It looks at the rtl code for a function and outputs assembler code.
2418334Speter
2518334Speter   Call `final_start_function' to output the assembler code for function entry,
2618334Speter   `final' to output assembler code for some RTL code,
2718334Speter   `final_end_function' to output assembler code for function exit.
2818334Speter   If a function is compiled in several pieces, each piece is
2918334Speter   output separately with `final'.
3018334Speter
3118334Speter   Some optimizations are also done at this level.
3218334Speter   Move instructions that were made unnecessary by good register allocation
3318334Speter   are detected and omitted from the output.  (Though most of these
3418334Speter   are removed by the last jump pass.)
3518334Speter
3618334Speter   Instructions to set the condition codes are omitted when it can be
3718334Speter   seen that the condition codes already had the desired values.
3818334Speter
3918334Speter   In some cases it is sufficient if the inherited condition codes
4018334Speter   have related values, but this may require the following insn
4118334Speter   (the one that tests the condition codes) to be modified.
4218334Speter
4318334Speter   The code for the function prologue and epilogue are generated
4490087Sobrien   directly in assembler by the target functions function_prologue and
4590087Sobrien   function_epilogue.  Those instructions never exist as rtl.  */
4618334Speter
4718334Speter#include "config.h"
4850503Sobrien#include "system.h"
4918334Speter
5018334Speter#include "tree.h"
5118334Speter#include "rtl.h"
5290087Sobrien#include "tm_p.h"
5318334Speter#include "regs.h"
5418334Speter#include "insn-config.h"
5518334Speter#include "insn-attr.h"
5618334Speter#include "recog.h"
5718334Speter#include "conditions.h"
5818334Speter#include "flags.h"
5918334Speter#include "real.h"
6018334Speter#include "hard-reg-set.h"
6118334Speter#include "output.h"
6250503Sobrien#include "except.h"
6390087Sobrien#include "function.h"
6450503Sobrien#include "toplev.h"
6550503Sobrien#include "reload.h"
6652515Sobrien#include "intl.h"
6790087Sobrien#include "basic-block.h"
6890087Sobrien#include "target.h"
6990087Sobrien#include "debug.h"
7090087Sobrien#include "expr.h"
71117404Skan#include "profile.h"
72117404Skan#include "cfglayout.h"
7318334Speter
7418334Speter#ifdef XCOFF_DEBUGGING_INFO
7590087Sobrien#include "xcoffout.h"		/* Needed for external data
7690087Sobrien				   declarations for e.g. AIX 4.x.  */
7718334Speter#endif
7818334Speter
7950503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
8050503Sobrien#include "dwarf2out.h"
8150503Sobrien#endif
8250503Sobrien
8318334Speter/* If we aren't using cc0, CC_STATUS_INIT shouldn't exist.  So define a
8418334Speter   null default for it to save conditionalization later.  */
8518334Speter#ifndef CC_STATUS_INIT
8618334Speter#define CC_STATUS_INIT
8718334Speter#endif
8818334Speter
8918334Speter/* How to start an assembler comment.  */
9018334Speter#ifndef ASM_COMMENT_START
9118334Speter#define ASM_COMMENT_START ";#"
9218334Speter#endif
9318334Speter
9418334Speter/* Is the given character a logical line separator for the assembler?  */
9518334Speter#ifndef IS_ASM_LOGICAL_LINE_SEPARATOR
9618334Speter#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';')
9718334Speter#endif
9818334Speter
9950503Sobrien#ifndef JUMP_TABLES_IN_TEXT_SECTION
10050503Sobrien#define JUMP_TABLES_IN_TEXT_SECTION 0
10150503Sobrien#endif
10250503Sobrien
103117404Skan#if defined(READONLY_DATA_SECTION) || defined(READONLY_DATA_SECTION_ASM_OP)
104117404Skan#define HAVE_READONLY_DATA_SECTION 1
105117404Skan#else
106117404Skan#define HAVE_READONLY_DATA_SECTION 0
107117404Skan#endif
108117404Skan
10918334Speter/* Last insn processed by final_scan_insn.  */
11090087Sobrienstatic rtx debug_insn;
11190087Sobrienrtx current_output_insn;
11218334Speter
11318334Speter/* Line number of last NOTE.  */
11418334Speterstatic int last_linenum;
11518334Speter
11618334Speter/* Highest line number in current block.  */
11718334Speterstatic int high_block_linenum;
11818334Speter
11918334Speter/* Likewise for function.  */
12018334Speterstatic int high_function_linenum;
12118334Speter
12218334Speter/* Filename of last NOTE.  */
12390087Sobrienstatic const char *last_filename;
12418334Speter
12550503Sobrienextern int length_unit_log; /* This is defined in insn-attrtab.c.  */
12650503Sobrien
12718334Speter/* Nonzero while outputting an `asm' with operands.
12818334Speter   This means that inconsistencies are the user's fault, so don't abort.
12918334Speter   The precise value is the insn being output, to pass to error_for_asm.  */
130117404Skanrtx this_is_asm_operands;
13118334Speter
13218334Speter/* Number of operands of this insn, for an `asm' with operands.  */
13350503Sobrienstatic unsigned int insn_noperands;
13418334Speter
13518334Speter/* Compare optimization flag.  */
13618334Speter
13718334Speterstatic rtx last_ignored_compare = 0;
13818334Speter
13918334Speter/* Flag indicating this insn is the start of a new basic block.  */
14018334Speter
14118334Speterstatic int new_block = 1;
14218334Speter
14318334Speter/* Assign a unique number to each insn that is output.
14418334Speter   This can be used to generate unique local labels.  */
14518334Speter
14618334Speterstatic int insn_counter = 0;
14718334Speter
14818334Speter#ifdef HAVE_cc0
14918334Speter/* This variable contains machine-dependent flags (defined in tm.h)
15018334Speter   set and examined by output routines
15118334Speter   that describe how to interpret the condition codes properly.  */
15218334Speter
15318334SpeterCC_STATUS cc_status;
15418334Speter
15518334Speter/* During output of an insn, this contains a copy of cc_status
15618334Speter   from before the insn.  */
15718334Speter
15818334SpeterCC_STATUS cc_prev_status;
15918334Speter#endif
16018334Speter
16118334Speter/* Indexed by hardware reg number, is 1 if that register is ever
16218334Speter   used in the current function.
16318334Speter
16418334Speter   In life_analysis, or in stupid_life_analysis, this is set
16518334Speter   up to record the hard regs used explicitly.  Reload adds
16618334Speter   in the hard regs used for holding pseudo regs.  Final uses
16718334Speter   it to generate the code in the function prologue and epilogue
16818334Speter   to save and restore registers as needed.  */
16918334Speter
17018334Speterchar regs_ever_live[FIRST_PSEUDO_REGISTER];
17118334Speter
17218334Speter/* Nonzero means current function must be given a frame pointer.
17318334Speter   Set in stmt.c if anything is allocated on the stack there.
17418334Speter   Set in reload1.c if anything is allocated on the stack there.  */
17518334Speter
17618334Speterint frame_pointer_needed;
17718334Speter
17890087Sobrien/* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen.  */
17918334Speter
18018334Speterstatic int block_depth;
18118334Speter
18218334Speter/* Nonzero if have enabled APP processing of our assembler output.  */
18318334Speter
18418334Speterstatic int app_on;
18518334Speter
18618334Speter/* If we are outputting an insn sequence, this contains the sequence rtx.
18718334Speter   Zero otherwise.  */
18818334Speter
18918334Speterrtx final_sequence;
19018334Speter
19118334Speter#ifdef ASSEMBLER_DIALECT
19218334Speter
19318334Speter/* Number of the assembler dialect to use, starting at 0.  */
19418334Speterstatic int dialect_number;
19518334Speter#endif
19618334Speter
19718334Speter/* Indexed by line number, nonzero if there is a note for that line.  */
19818334Speter
19918334Speterstatic char *line_note_exists;
20018334Speter
20190087Sobrien#ifdef HAVE_conditional_execution
20290087Sobrien/* Nonnull if the insn currently being emitted was a COND_EXEC pattern.  */
20390087Sobrienrtx current_insn_predicate;
20490087Sobrien#endif
20518334Speter
206117404Skanstruct function_list
207117404Skan{
208117404Skan  struct function_list *next; 	/* next function */
209117404Skan  const char *name; 		/* function name */
210117404Skan  long cfg_checksum;		/* function checksum */
211117404Skan  long count_edges;		/* number of intrumented edges in this function */
212117404Skan};
213117404Skan
214117404Skanstatic struct function_list *functions_head = 0;
215117404Skanstatic struct function_list **functions_tail = &functions_head;
216117404Skan
21750503Sobrien#ifdef HAVE_ATTR_length
21890087Sobrienstatic int asm_insn_count	PARAMS ((rtx));
21950503Sobrien#endif
22090087Sobrienstatic void profile_function	PARAMS ((FILE *));
22190087Sobrienstatic void profile_after_prologue PARAMS ((FILE *));
22290087Sobrienstatic void notice_source_line	PARAMS ((rtx));
22390087Sobrienstatic rtx walk_alter_subreg	PARAMS ((rtx *));
22490087Sobrienstatic void output_asm_name	PARAMS ((void));
225117404Skanstatic void output_alternate_entry_point PARAMS ((FILE *, rtx));
22690087Sobrienstatic tree get_mem_expr_from_op	PARAMS ((rtx, int *));
22790087Sobrienstatic void output_asm_operand_names PARAMS ((rtx *, int *, int));
22890087Sobrienstatic void output_operand	PARAMS ((rtx, int));
22950503Sobrien#ifdef LEAF_REGISTERS
23090087Sobrienstatic void leaf_renumber_regs	PARAMS ((rtx));
23150503Sobrien#endif
23250503Sobrien#ifdef HAVE_cc0
23390087Sobrienstatic int alter_cond		PARAMS ((rtx));
23450503Sobrien#endif
23590087Sobrien#ifndef ADDR_VEC_ALIGN
23690087Sobrienstatic int final_addr_vec_align PARAMS ((rtx));
23790087Sobrien#endif
23890087Sobrien#ifdef HAVE_ATTR_length
23990087Sobrienstatic int align_fuzz		PARAMS ((rtx, rtx, int, unsigned));
24090087Sobrien#endif
24118334Speter
24218334Speter/* Initialize data in final at the beginning of a compilation.  */
24318334Speter
24418334Spetervoid
24518334Speterinit_final (filename)
24690087Sobrien     const char *filename ATTRIBUTE_UNUSED;
24718334Speter{
24818334Speter  app_on = 0;
24918334Speter  final_sequence = 0;
25018334Speter
25118334Speter#ifdef ASSEMBLER_DIALECT
25218334Speter  dialect_number = ASSEMBLER_DIALECT;
25318334Speter#endif
25418334Speter}
25518334Speter
25618334Speter/* Called at end of source file,
257117404Skan   to output the arc-profiling table for this entire compilation.  */
25818334Speter
25918334Spetervoid
26018334Speterend_final (filename)
26190087Sobrien     const char *filename;
26218334Speter{
263117404Skan  if (profile_arc_flag && profile_info.count_instrumented_edges)
26418334Speter    {
26518334Speter      char name[20];
266117404Skan      tree string_type, string_cst;
267117404Skan      tree structure_decl, structure_value, structure_pointer_type;
268117404Skan      tree field_decl, decl_chain, value_chain;
269117404Skan      tree sizeof_field_value, domain_type;
27018334Speter
271117404Skan      /* Build types.  */
272117404Skan      string_type = build_pointer_type (char_type_node);
27350503Sobrien
274117404Skan      /* Libgcc2 bb structure.  */
275117404Skan      structure_decl = make_node (RECORD_TYPE);
276117404Skan      structure_pointer_type = build_pointer_type (structure_decl);
27718334Speter
278117404Skan      /* Output the main header, of 7 words:
279117404Skan         0:  1 if this file is initialized, else 0.
280117404Skan         1:  address of file name (LPBX1).
281117404Skan         2:  address of table of counts (LPBX2).
282117404Skan         3:  number of counts in the table.
283117404Skan         4:  always 0, libgcc2 uses this as a pointer to next ``struct bb''
28490087Sobrien
285117404Skan         The following are GNU extensions:
28618334Speter
287117404Skan         5:  Number of bytes in this header.
288117404Skan         6:  address of table of function checksums (LPBX7).  */
28918334Speter
290117404Skan      /* The zero word.  */
291117404Skan      decl_chain =
292117404Skan	build_decl (FIELD_DECL, get_identifier ("zero_word"),
293117404Skan		    long_integer_type_node);
294117404Skan      value_chain = build_tree_list (decl_chain,
295117404Skan				     convert (long_integer_type_node,
296117404Skan					      integer_zero_node));
29718334Speter
298117404Skan      /* Address of filename.  */
299117404Skan      {
300117404Skan	char *cwd, *da_filename;
301117404Skan	int da_filename_len;
30218334Speter
303117404Skan	field_decl =
304117404Skan	  build_decl (FIELD_DECL, get_identifier ("filename"), string_type);
305117404Skan	TREE_CHAIN (field_decl) = decl_chain;
306117404Skan	decl_chain = field_decl;
30718334Speter
308117404Skan	cwd = getpwd ();
309117404Skan	da_filename_len = strlen (filename) + strlen (cwd) + 4 + 1;
310117404Skan	da_filename = (char *) alloca (da_filename_len);
311117404Skan	strcpy (da_filename, cwd);
312117404Skan	strcat (da_filename, "/");
313117404Skan	strcat (da_filename, filename);
314117404Skan	strcat (da_filename, ".da");
315117404Skan	da_filename_len = strlen (da_filename);
316117404Skan	string_cst = build_string (da_filename_len + 1, da_filename);
317117404Skan	domain_type = build_index_type (build_int_2 (da_filename_len, 0));
318117404Skan	TREE_TYPE (string_cst)
319117404Skan	  = build_array_type (char_type_node, domain_type);
320117404Skan	value_chain = tree_cons (field_decl,
321117404Skan				 build1 (ADDR_EXPR, string_type, string_cst),
322117404Skan				 value_chain);
323117404Skan      }
32418334Speter
325117404Skan      /* Table of counts.  */
326117404Skan      {
327117404Skan	tree gcov_type_type = make_unsigned_type (GCOV_TYPE_SIZE);
328117404Skan	tree gcov_type_pointer_type = build_pointer_type (gcov_type_type);
329117404Skan	tree domain_tree
330117404Skan	  = build_index_type (build_int_2 (profile_info.
331117404Skan					   count_instrumented_edges - 1, 0));
332117404Skan	tree gcov_type_array_type
333117404Skan	  = build_array_type (gcov_type_type, domain_tree);
334117404Skan	tree gcov_type_array_pointer_type
335117404Skan	  = build_pointer_type (gcov_type_array_type);
336117404Skan	tree counts_table;
33790087Sobrien
338117404Skan	field_decl =
339117404Skan	  build_decl (FIELD_DECL, get_identifier ("counts"),
340117404Skan		      gcov_type_pointer_type);
341117404Skan	TREE_CHAIN (field_decl) = decl_chain;
342117404Skan	decl_chain = field_decl;
34318334Speter
344117404Skan	/* No values.  */
345117404Skan	counts_table
346117404Skan	  = build (VAR_DECL, gcov_type_array_type, NULL_TREE, NULL_TREE);
347117404Skan	TREE_STATIC (counts_table) = 1;
348117404Skan	ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
349117404Skan	DECL_NAME (counts_table) = get_identifier (name);
350117404Skan	assemble_variable (counts_table, 0, 0, 0);
35118334Speter
352117404Skan	value_chain = tree_cons (field_decl,
353117404Skan				 build1 (ADDR_EXPR,
354117404Skan					 gcov_type_array_pointer_type,
355117404Skan					 counts_table), value_chain);
356117404Skan      }
357117404Skan
35890087Sobrien      /* Count of the # of instrumented arcs.  */
359117404Skan      field_decl
360117404Skan	= build_decl (FIELD_DECL, get_identifier ("ncounts"),
361117404Skan		      long_integer_type_node);
362117404Skan      TREE_CHAIN (field_decl) = decl_chain;
363117404Skan      decl_chain = field_decl;
36418334Speter
365117404Skan      value_chain = tree_cons (field_decl,
366117404Skan			       convert (long_integer_type_node,
367117404Skan					build_int_2 (profile_info.
368117404Skan						     count_instrumented_edges,
369117404Skan						     0)), value_chain);
370117404Skan      /* Pointer to the next bb.  */
371117404Skan      field_decl
372117404Skan	= build_decl (FIELD_DECL, get_identifier ("next"),
373117404Skan		      structure_pointer_type);
374117404Skan      TREE_CHAIN (field_decl) = decl_chain;
375117404Skan      decl_chain = field_decl;
37618334Speter
377117404Skan      value_chain = tree_cons (field_decl, null_pointer_node, value_chain);
37818334Speter
379117404Skan      /* sizeof(struct bb).  We'll set this after entire structure
380117404Skan	 is laid out.  */
381117404Skan      field_decl
382117404Skan	= build_decl (FIELD_DECL, get_identifier ("sizeof_bb"),
383117404Skan		      long_integer_type_node);
384117404Skan      TREE_CHAIN (field_decl) = decl_chain;
385117404Skan      decl_chain = field_decl;
38618334Speter
387117404Skan      sizeof_field_value = tree_cons (field_decl, NULL, value_chain);
388117404Skan      value_chain = sizeof_field_value;
38918334Speter
390117404Skan      /* struct bb_function [].  */
391117404Skan      {
392117404Skan	struct function_list *item;
393117404Skan	int num_nodes;
394117404Skan	tree checksum_field, arc_count_field, name_field;
395117404Skan	tree domain;
396117404Skan	tree array_value_chain = NULL_TREE;
397117404Skan	tree bb_fn_struct_type;
398117404Skan	tree bb_fn_struct_array_type;
399117404Skan	tree bb_fn_struct_array_pointer_type;
400117404Skan	tree bb_fn_struct_pointer_type;
401117404Skan	tree field_value, field_value_chain;
40218334Speter
403117404Skan	bb_fn_struct_type = make_node (RECORD_TYPE);
40450503Sobrien
405117404Skan	checksum_field = build_decl (FIELD_DECL, get_identifier ("checksum"),
406117404Skan				     long_integer_type_node);
40718334Speter
408117404Skan	arc_count_field
409117404Skan	  = build_decl (FIELD_DECL, get_identifier ("arc_count"),
410117404Skan		        integer_type_node);
411117404Skan	TREE_CHAIN (checksum_field) = arc_count_field;
412117404Skan
413117404Skan	name_field
414117404Skan	  = build_decl (FIELD_DECL, get_identifier ("name"), string_type);
415117404Skan	TREE_CHAIN (arc_count_field) = name_field;
416117404Skan
417117404Skan	TYPE_FIELDS (bb_fn_struct_type) = checksum_field;
418117404Skan
419117404Skan	num_nodes = 0;
420117404Skan
421117404Skan	for (item = functions_head; item != 0; item = item->next)
422117404Skan	  num_nodes++;
423117404Skan
424117404Skan	/* Note that the array contains a terminator, hence no - 1.  */
425117404Skan	domain = build_index_type (build_int_2 (num_nodes, 0));
426117404Skan
427117404Skan	bb_fn_struct_pointer_type = build_pointer_type (bb_fn_struct_type);
428117404Skan	bb_fn_struct_array_type
429117404Skan	  = build_array_type (bb_fn_struct_type, domain);
430117404Skan	bb_fn_struct_array_pointer_type
431117404Skan	  = build_pointer_type (bb_fn_struct_array_type);
432117404Skan
433117404Skan	layout_type (bb_fn_struct_type);
434117404Skan	layout_type (bb_fn_struct_pointer_type);
435117404Skan	layout_type (bb_fn_struct_array_type);
436117404Skan	layout_type (bb_fn_struct_array_pointer_type);
437117404Skan
438117404Skan	for (item = functions_head; item != 0; item = item->next)
439117404Skan	  {
440117404Skan	    size_t name_len;
441117404Skan
442117404Skan	    /* create constructor for structure.  */
443117404Skan	    field_value_chain
444117404Skan	      = build_tree_list (checksum_field,
445117404Skan				 convert (long_integer_type_node,
446117404Skan					  build_int_2 (item->cfg_checksum, 0)));
447117404Skan	    field_value_chain
448117404Skan	      = tree_cons (arc_count_field,
449117404Skan			   convert (integer_type_node,
450117404Skan				    build_int_2 (item->count_edges, 0)),
451117404Skan			   field_value_chain);
452117404Skan
453117404Skan	    name_len = strlen (item->name);
454117404Skan	    string_cst = build_string (name_len + 1, item->name);
455117404Skan	    domain_type = build_index_type (build_int_2 (name_len, 0));
456117404Skan	    TREE_TYPE (string_cst)
457117404Skan	      = build_array_type (char_type_node, domain_type);
458117404Skan	    field_value_chain = tree_cons (name_field,
459117404Skan					   build1 (ADDR_EXPR, string_type,
460117404Skan						   string_cst),
461117404Skan					   field_value_chain);
462117404Skan
463117404Skan	    /* Add to chain.  */
464117404Skan	    array_value_chain
465117404Skan	      = tree_cons (NULL_TREE, build (CONSTRUCTOR,
466117404Skan					     bb_fn_struct_type, NULL_TREE,
467117404Skan					     nreverse (field_value_chain)),
468117404Skan			   array_value_chain);
469117404Skan	  }
470117404Skan
471117404Skan	/* Add terminator.  */
472117404Skan	field_value = build_tree_list (arc_count_field,
473117404Skan				       convert (integer_type_node,
474117404Skan						build_int_2 (-1, 0)));
475117404Skan
476117404Skan	array_value_chain = tree_cons (NULL_TREE,
477117404Skan				       build (CONSTRUCTOR, bb_fn_struct_type,
478117404Skan					      NULL_TREE, field_value),
479117404Skan				       array_value_chain);
480117404Skan
481117404Skan
482117404Skan	/* Create constructor for array.  */
483117404Skan	field_decl
484117404Skan	  = build_decl (FIELD_DECL, get_identifier ("function_infos"),
485117404Skan		        bb_fn_struct_pointer_type);
486117404Skan	value_chain = tree_cons (field_decl,
487117404Skan				 build1 (ADDR_EXPR,
488117404Skan					 bb_fn_struct_array_pointer_type,
489117404Skan					 build (CONSTRUCTOR,
490117404Skan						bb_fn_struct_array_type,
491117404Skan						NULL_TREE,
492117404Skan						nreverse
493117404Skan						(array_value_chain))),
494117404Skan				 value_chain);
495117404Skan	TREE_CHAIN (field_decl) = decl_chain;
496117404Skan	decl_chain = field_decl;
49718334Speter      }
49818334Speter
499117404Skan      /* Finish structure.  */
500117404Skan      TYPE_FIELDS (structure_decl) = nreverse (decl_chain);
501117404Skan      layout_type (structure_decl);
502117404Skan
503117404Skan      structure_value
504117404Skan	= build (VAR_DECL, structure_decl, NULL_TREE, NULL_TREE);
505117404Skan      DECL_INITIAL (structure_value)
506117404Skan	= build (CONSTRUCTOR, structure_decl, NULL_TREE,
507117404Skan	         nreverse (value_chain));
508117404Skan      TREE_STATIC (structure_value) = 1;
509117404Skan      ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0);
510117404Skan      DECL_NAME (structure_value) = get_identifier (name);
511117404Skan
512117404Skan      /* Size of this structure.  */
513117404Skan      TREE_VALUE (sizeof_field_value)
514117404Skan	= convert (long_integer_type_node,
515117404Skan		   build_int_2 (int_size_in_bytes (structure_decl), 0));
516117404Skan
517117404Skan      /* Build structure.  */
518117404Skan      assemble_variable (structure_value, 0, 0, 0);
51990087Sobrien    }
52090087Sobrien}
52118334Speter
52290087Sobrien/* Default target function prologue and epilogue assembler output.
52318334Speter
52490087Sobrien   If not overridden for epilogue code, then the function body itself
52590087Sobrien   contains return instructions wherever needed.  */
52690087Sobrienvoid
52790087Sobriendefault_function_pro_epilogue (file, size)
52890087Sobrien     FILE *file ATTRIBUTE_UNUSED;
52990087Sobrien     HOST_WIDE_INT size ATTRIBUTE_UNUSED;
53090087Sobrien{
53190087Sobrien}
53218334Speter
53390087Sobrien/* Default target hook that outputs nothing to a stream.  */
53490087Sobrienvoid
53590087Sobrienno_asm_to_stream (file)
53690087Sobrien     FILE *file ATTRIBUTE_UNUSED;
53790087Sobrien{
53818334Speter}
53918334Speter
54018334Speter/* Enable APP processing of subsequent output.
54118334Speter   Used before the output from an `asm' statement.  */
54218334Speter
54318334Spetervoid
54418334Speterapp_enable ()
54518334Speter{
54618334Speter  if (! app_on)
54718334Speter    {
54850503Sobrien      fputs (ASM_APP_ON, asm_out_file);
54918334Speter      app_on = 1;
55018334Speter    }
55118334Speter}
55218334Speter
55318334Speter/* Disable APP processing of subsequent output.
55418334Speter   Called from varasm.c before most kinds of output.  */
55518334Speter
55618334Spetervoid
55718334Speterapp_disable ()
55818334Speter{
55918334Speter  if (app_on)
56018334Speter    {
56150503Sobrien      fputs (ASM_APP_OFF, asm_out_file);
56218334Speter      app_on = 0;
56318334Speter    }
56418334Speter}
56518334Speter
56690087Sobrien/* Return the number of slots filled in the current
56718334Speter   delayed branch sequence (we don't count the insn needing the
56818334Speter   delay slot).   Zero if not in a delayed branch sequence.  */
56918334Speter
57018334Speter#ifdef DELAY_SLOTS
57118334Speterint
57218334Speterdbr_sequence_length ()
57318334Speter{
57418334Speter  if (final_sequence != 0)
57518334Speter    return XVECLEN (final_sequence, 0) - 1;
57618334Speter  else
57718334Speter    return 0;
57818334Speter}
57918334Speter#endif
58018334Speter
58118334Speter/* The next two pages contain routines used to compute the length of an insn
58218334Speter   and to shorten branches.  */
58318334Speter
58418334Speter/* Arrays for insn lengths, and addresses.  The latter is referenced by
58518334Speter   `insn_current_length'.  */
58618334Speter
58790087Sobrienstatic int *insn_lengths;
58818334Speter
58990087Sobrienvarray_type insn_addresses_;
59090087Sobrien
59152515Sobrien/* Max uid for which the above arrays are valid.  */
59252515Sobrienstatic int insn_lengths_max_uid;
59352515Sobrien
59418334Speter/* Address of insn being processed.  Used by `insn_current_length'.  */
59518334Speterint insn_current_address;
59618334Speter
59750503Sobrien/* Address of insn being processed in previous iteration.  */
59850503Sobrienint insn_last_address;
59950503Sobrien
60090087Sobrien/* known invariant alignment of insn being processed.  */
60150503Sobrienint insn_current_align;
60250503Sobrien
60350503Sobrien/* After shorten_branches, for any insn, uid_align[INSN_UID (insn)]
60450503Sobrien   gives the next following alignment insn that increases the known
60550503Sobrien   alignment, or NULL_RTX if there is no such insn.
60650503Sobrien   For any alignment obtained this way, we can again index uid_align with
60750503Sobrien   its uid to obtain the next following align that in turn increases the
60850503Sobrien   alignment, till we reach NULL_RTX; the sequence obtained this way
60950503Sobrien   for each insn we'll call the alignment chain of this insn in the following
61050503Sobrien   comments.  */
61150503Sobrien
61290087Sobrienstruct label_alignment
61390087Sobrien{
61450503Sobrien  short alignment;
61550503Sobrien  short max_skip;
61650503Sobrien};
61750503Sobrien
61850503Sobrienstatic rtx *uid_align;
61950503Sobrienstatic int *uid_shuid;
62050503Sobrienstatic struct label_alignment *label_align;
62150503Sobrien
62218334Speter/* Indicate that branch shortening hasn't yet been done.  */
62318334Speter
62418334Spetervoid
62518334Speterinit_insn_lengths ()
62618334Speter{
62750503Sobrien  if (uid_shuid)
62850503Sobrien    {
62950503Sobrien      free (uid_shuid);
63050503Sobrien      uid_shuid = 0;
63150503Sobrien    }
63250503Sobrien  if (insn_lengths)
63350503Sobrien    {
63450503Sobrien      free (insn_lengths);
63550503Sobrien      insn_lengths = 0;
63652515Sobrien      insn_lengths_max_uid = 0;
63750503Sobrien    }
63890087Sobrien#ifdef HAVE_ATTR_length
63990087Sobrien  INSN_ADDRESSES_FREE ();
64090087Sobrien#endif
64150503Sobrien  if (uid_align)
64250503Sobrien    {
64350503Sobrien      free (uid_align);
64450503Sobrien      uid_align = 0;
64550503Sobrien    }
64618334Speter}
64718334Speter
64818334Speter/* Obtain the current length of an insn.  If branch shortening has been done,
64918334Speter   get its actual length.  Otherwise, get its maximum length.  */
65018334Speter
65118334Speterint
65218334Speterget_attr_length (insn)
65390087Sobrien     rtx insn ATTRIBUTE_UNUSED;
65418334Speter{
65518334Speter#ifdef HAVE_ATTR_length
65618334Speter  rtx body;
65718334Speter  int i;
65818334Speter  int length = 0;
65918334Speter
66052515Sobrien  if (insn_lengths_max_uid > INSN_UID (insn))
66118334Speter    return insn_lengths[INSN_UID (insn)];
66218334Speter  else
66318334Speter    switch (GET_CODE (insn))
66418334Speter      {
66518334Speter      case NOTE:
66618334Speter      case BARRIER:
66718334Speter      case CODE_LABEL:
66818334Speter	return 0;
66918334Speter
67018334Speter      case CALL_INSN:
67118334Speter	length = insn_default_length (insn);
67218334Speter	break;
67318334Speter
67418334Speter      case JUMP_INSN:
67518334Speter	body = PATTERN (insn);
676117404Skan	if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
67718334Speter	  {
67850503Sobrien	    /* Alignment is machine-dependent and should be handled by
67950503Sobrien	       ADDR_VEC_ALIGN.  */
68018334Speter	  }
68118334Speter	else
68218334Speter	  length = insn_default_length (insn);
68318334Speter	break;
68418334Speter
68518334Speter      case INSN:
68618334Speter	body = PATTERN (insn);
68718334Speter	if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER)
68818334Speter	  return 0;
68918334Speter
69018334Speter	else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
69118334Speter	  length = asm_insn_count (body) * insn_default_length (insn);
69218334Speter	else if (GET_CODE (body) == SEQUENCE)
69318334Speter	  for (i = 0; i < XVECLEN (body, 0); i++)
69418334Speter	    length += get_attr_length (XVECEXP (body, 0, i));
69518334Speter	else
69618334Speter	  length = insn_default_length (insn);
69750503Sobrien	break;
69850503Sobrien
69950503Sobrien      default:
70050503Sobrien	break;
70118334Speter      }
70218334Speter
70318334Speter#ifdef ADJUST_INSN_LENGTH
70418334Speter  ADJUST_INSN_LENGTH (insn, length);
70518334Speter#endif
70618334Speter  return length;
70718334Speter#else /* not HAVE_ATTR_length */
70818334Speter  return 0;
70918334Speter#endif /* not HAVE_ATTR_length */
71018334Speter}
71118334Speter
71250503Sobrien/* Code to handle alignment inside shorten_branches.  */
71350503Sobrien
71450503Sobrien/* Here is an explanation how the algorithm in align_fuzz can give
71550503Sobrien   proper results:
71650503Sobrien
71750503Sobrien   Call a sequence of instructions beginning with alignment point X
71850503Sobrien   and continuing until the next alignment point `block X'.  When `X'
71990087Sobrien   is used in an expression, it means the alignment value of the
72050503Sobrien   alignment point.
72190087Sobrien
72250503Sobrien   Call the distance between the start of the first insn of block X, and
72350503Sobrien   the end of the last insn of block X `IX', for the `inner size of X'.
72450503Sobrien   This is clearly the sum of the instruction lengths.
72590087Sobrien
72650503Sobrien   Likewise with the next alignment-delimited block following X, which we
72750503Sobrien   shall call block Y.
72890087Sobrien
72950503Sobrien   Call the distance between the start of the first insn of block X, and
73050503Sobrien   the start of the first insn of block Y `OX', for the `outer size of X'.
73190087Sobrien
73250503Sobrien   The estimated padding is then OX - IX.
73390087Sobrien
73450503Sobrien   OX can be safely estimated as
73590087Sobrien
73650503Sobrien           if (X >= Y)
73750503Sobrien                   OX = round_up(IX, Y)
73850503Sobrien           else
73950503Sobrien                   OX = round_up(IX, X) + Y - X
74090087Sobrien
74150503Sobrien   Clearly est(IX) >= real(IX), because that only depends on the
74250503Sobrien   instruction lengths, and those being overestimated is a given.
74390087Sobrien
74450503Sobrien   Clearly round_up(foo, Z) >= round_up(bar, Z) if foo >= bar, so
74550503Sobrien   we needn't worry about that when thinking about OX.
74690087Sobrien
74750503Sobrien   When X >= Y, the alignment provided by Y adds no uncertainty factor
74850503Sobrien   for branch ranges starting before X, so we can just round what we have.
74950503Sobrien   But when X < Y, we don't know anything about the, so to speak,
75050503Sobrien   `middle bits', so we have to assume the worst when aligning up from an
75150503Sobrien   address mod X to one mod Y, which is Y - X.  */
75250503Sobrien
75350503Sobrien#ifndef LABEL_ALIGN
75490087Sobrien#define LABEL_ALIGN(LABEL) align_labels_log
75550503Sobrien#endif
75650503Sobrien
75750503Sobrien#ifndef LABEL_ALIGN_MAX_SKIP
75890087Sobrien#define LABEL_ALIGN_MAX_SKIP align_labels_max_skip
75950503Sobrien#endif
76050503Sobrien
76150503Sobrien#ifndef LOOP_ALIGN
76290087Sobrien#define LOOP_ALIGN(LABEL) align_loops_log
76350503Sobrien#endif
76450503Sobrien
76550503Sobrien#ifndef LOOP_ALIGN_MAX_SKIP
76690087Sobrien#define LOOP_ALIGN_MAX_SKIP align_loops_max_skip
76750503Sobrien#endif
76850503Sobrien
76950503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER
77050503Sobrien#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0
77150503Sobrien#endif
77250503Sobrien
77350503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP
77450503Sobrien#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0
77550503Sobrien#endif
77650503Sobrien
77790087Sobrien#ifndef JUMP_ALIGN
77890087Sobrien#define JUMP_ALIGN(LABEL) align_jumps_log
77990087Sobrien#endif
78090087Sobrien
78190087Sobrien#ifndef JUMP_ALIGN_MAX_SKIP
78290087Sobrien#define JUMP_ALIGN_MAX_SKIP align_jumps_max_skip
78390087Sobrien#endif
78490087Sobrien
78550503Sobrien#ifndef ADDR_VEC_ALIGN
78690087Sobrienstatic int
78750503Sobrienfinal_addr_vec_align (addr_vec)
78850503Sobrien     rtx addr_vec;
78950503Sobrien{
79090087Sobrien  int align = GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec)));
79150503Sobrien
79250503Sobrien  if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
79350503Sobrien    align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
79490087Sobrien  return exact_log2 (align);
79550503Sobrien
79650503Sobrien}
79790087Sobrien
79850503Sobrien#define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC)
79950503Sobrien#endif
80050503Sobrien
80150503Sobrien#ifndef INSN_LENGTH_ALIGNMENT
80250503Sobrien#define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log
80350503Sobrien#endif
80450503Sobrien
80550503Sobrien#define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)])
80650503Sobrien
80750503Sobrienstatic int min_labelno, max_labelno;
80850503Sobrien
80950503Sobrien#define LABEL_TO_ALIGNMENT(LABEL) \
81050503Sobrien  (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].alignment)
81150503Sobrien
81250503Sobrien#define LABEL_TO_MAX_SKIP(LABEL) \
81350503Sobrien  (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].max_skip)
81450503Sobrien
81550503Sobrien/* For the benefit of port specific code do this also as a function.  */
81690087Sobrien
81750503Sobrienint
81850503Sobrienlabel_to_alignment (label)
81950503Sobrien     rtx label;
82050503Sobrien{
82150503Sobrien  return LABEL_TO_ALIGNMENT (label);
82250503Sobrien}
82350503Sobrien
82450503Sobrien#ifdef HAVE_ATTR_length
82550503Sobrien/* The differences in addresses
82650503Sobrien   between a branch and its target might grow or shrink depending on
82750503Sobrien   the alignment the start insn of the range (the branch for a forward
82850503Sobrien   branch or the label for a backward branch) starts out on; if these
82950503Sobrien   differences are used naively, they can even oscillate infinitely.
83050503Sobrien   We therefore want to compute a 'worst case' address difference that
83150503Sobrien   is independent of the alignment the start insn of the range end
83250503Sobrien   up on, and that is at least as large as the actual difference.
83350503Sobrien   The function align_fuzz calculates the amount we have to add to the
83450503Sobrien   naively computed difference, by traversing the part of the alignment
83550503Sobrien   chain of the start insn of the range that is in front of the end insn
83650503Sobrien   of the range, and considering for each alignment the maximum amount
83750503Sobrien   that it might contribute to a size increase.
83850503Sobrien
83950503Sobrien   For casesi tables, we also want to know worst case minimum amounts of
84050503Sobrien   address difference, in case a machine description wants to introduce
84150503Sobrien   some common offset that is added to all offsets in a table.
84290087Sobrien   For this purpose, align_fuzz with a growth argument of 0 computes the
84350503Sobrien   appropriate adjustment.  */
84450503Sobrien
84550503Sobrien/* Compute the maximum delta by which the difference of the addresses of
84650503Sobrien   START and END might grow / shrink due to a different address for start
84750503Sobrien   which changes the size of alignment insns between START and END.
84850503Sobrien   KNOWN_ALIGN_LOG is the alignment known for START.
84950503Sobrien   GROWTH should be ~0 if the objective is to compute potential code size
85050503Sobrien   increase, and 0 if the objective is to compute potential shrink.
85150503Sobrien   The return value is undefined for any other value of GROWTH.  */
85290087Sobrien
85390087Sobrienstatic int
85450503Sobrienalign_fuzz (start, end, known_align_log, growth)
85550503Sobrien     rtx start, end;
85650503Sobrien     int known_align_log;
85750503Sobrien     unsigned growth;
85850503Sobrien{
85950503Sobrien  int uid = INSN_UID (start);
86050503Sobrien  rtx align_label;
86150503Sobrien  int known_align = 1 << known_align_log;
86250503Sobrien  int end_shuid = INSN_SHUID (end);
86350503Sobrien  int fuzz = 0;
86450503Sobrien
86550503Sobrien  for (align_label = uid_align[uid]; align_label; align_label = uid_align[uid])
86650503Sobrien    {
86750503Sobrien      int align_addr, new_align;
86850503Sobrien
86950503Sobrien      uid = INSN_UID (align_label);
87090087Sobrien      align_addr = INSN_ADDRESSES (uid) - insn_lengths[uid];
87150503Sobrien      if (uid_shuid[uid] > end_shuid)
87250503Sobrien	break;
87350503Sobrien      known_align_log = LABEL_TO_ALIGNMENT (align_label);
87450503Sobrien      new_align = 1 << known_align_log;
87550503Sobrien      if (new_align < known_align)
87650503Sobrien	continue;
87750503Sobrien      fuzz += (-align_addr ^ growth) & (new_align - known_align);
87850503Sobrien      known_align = new_align;
87950503Sobrien    }
88050503Sobrien  return fuzz;
88150503Sobrien}
88250503Sobrien
88350503Sobrien/* Compute a worst-case reference address of a branch so that it
88450503Sobrien   can be safely used in the presence of aligned labels.  Since the
88550503Sobrien   size of the branch itself is unknown, the size of the branch is
88650503Sobrien   not included in the range.  I.e. for a forward branch, the reference
88750503Sobrien   address is the end address of the branch as known from the previous
88850503Sobrien   branch shortening pass, minus a value to account for possible size
88950503Sobrien   increase due to alignment.  For a backward branch, it is the start
89050503Sobrien   address of the branch as known from the current pass, plus a value
89150503Sobrien   to account for possible size increase due to alignment.
89250503Sobrien   NB.: Therefore, the maximum offset allowed for backward branches needs
89350503Sobrien   to exclude the branch size.  */
89490087Sobrien
89550503Sobrienint
89650503Sobrieninsn_current_reference_address (branch)
89750503Sobrien     rtx branch;
89850503Sobrien{
89990087Sobrien  rtx dest, seq;
90090087Sobrien  int seq_uid;
90190087Sobrien
90290087Sobrien  if (! INSN_ADDRESSES_SET_P ())
90390087Sobrien    return 0;
90490087Sobrien
90590087Sobrien  seq = NEXT_INSN (PREV_INSN (branch));
90690087Sobrien  seq_uid = INSN_UID (seq);
90750503Sobrien  if (GET_CODE (branch) != JUMP_INSN)
90850503Sobrien    /* This can happen for example on the PA; the objective is to know the
90950503Sobrien       offset to address something in front of the start of the function.
91050503Sobrien       Thus, we can treat it like a backward branch.
91150503Sobrien       We assume here that FUNCTION_BOUNDARY / BITS_PER_UNIT is larger than
91250503Sobrien       any alignment we'd encounter, so we skip the call to align_fuzz.  */
91350503Sobrien    return insn_current_address;
91450503Sobrien  dest = JUMP_LABEL (branch);
91590087Sobrien
91690087Sobrien  /* BRANCH has no proper alignment chain set, so use SEQ.
91790087Sobrien     BRANCH also has no INSN_SHUID.  */
91890087Sobrien  if (INSN_SHUID (seq) < INSN_SHUID (dest))
91950503Sobrien    {
92090087Sobrien      /* Forward branch.  */
92150503Sobrien      return (insn_last_address + insn_lengths[seq_uid]
92250503Sobrien	      - align_fuzz (seq, dest, length_unit_log, ~0));
92350503Sobrien    }
92450503Sobrien  else
92550503Sobrien    {
92690087Sobrien      /* Backward branch.  */
92750503Sobrien      return (insn_current_address
92850503Sobrien	      + align_fuzz (dest, seq, length_unit_log, ~0));
92950503Sobrien    }
93050503Sobrien}
93150503Sobrien#endif /* HAVE_ATTR_length */
93250503Sobrien
93390087Sobrienvoid
93490087Sobriencompute_alignments ()
93590087Sobrien{
93690087Sobrien  int log, max_skip, max_log;
937117404Skan  basic_block bb;
93890087Sobrien
93990087Sobrien  if (label_align)
94090087Sobrien    {
94190087Sobrien      free (label_align);
94290087Sobrien      label_align = 0;
94390087Sobrien    }
94490087Sobrien
94590087Sobrien  max_labelno = max_label_num ();
94690087Sobrien  min_labelno = get_first_label_num ();
94790087Sobrien  label_align = (struct label_alignment *)
94890087Sobrien    xcalloc (max_labelno - min_labelno + 1, sizeof (struct label_alignment));
94990087Sobrien
95090087Sobrien  /* If not optimizing or optimizing for size, don't assign any alignments.  */
95190087Sobrien  if (! optimize || optimize_size)
95290087Sobrien    return;
95390087Sobrien
954117404Skan  FOR_EACH_BB (bb)
95590087Sobrien    {
95690087Sobrien      rtx label = bb->head;
95790087Sobrien      int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0;
95890087Sobrien      edge e;
95990087Sobrien
96090087Sobrien      if (GET_CODE (label) != CODE_LABEL)
96190087Sobrien	continue;
96290087Sobrien      max_log = LABEL_ALIGN (label);
96390087Sobrien      max_skip = LABEL_ALIGN_MAX_SKIP;
96490087Sobrien
96590087Sobrien      for (e = bb->pred; e; e = e->pred_next)
96690087Sobrien	{
96790087Sobrien	  if (e->flags & EDGE_FALLTHRU)
96890087Sobrien	    has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e);
96990087Sobrien	  else
97090087Sobrien	    branch_frequency += EDGE_FREQUENCY (e);
97190087Sobrien	}
97290087Sobrien
97390087Sobrien      /* There are two purposes to align block with no fallthru incoming edge:
97490087Sobrien	 1) to avoid fetch stalls when branch destination is near cache boundary
97590087Sobrien	 2) to improve cache efficiency in case the previous block is not executed
97690087Sobrien	    (so it does not need to be in the cache).
97790087Sobrien
97890087Sobrien	 We to catch first case, we align frequently executed blocks.
97990087Sobrien	 To catch the second, we align blocks that are executed more frequently
98090087Sobrien	 than the predecessor and the predecessor is likely to not be executed
98190087Sobrien	 when function is called.  */
98290087Sobrien
98390087Sobrien      if (!has_fallthru
98490087Sobrien	  && (branch_frequency > BB_FREQ_MAX / 10
985117404Skan	      || (bb->frequency > bb->prev_bb->frequency * 10
986117404Skan		  && (bb->prev_bb->frequency
98790087Sobrien		      <= ENTRY_BLOCK_PTR->frequency / 2))))
98890087Sobrien	{
98990087Sobrien	  log = JUMP_ALIGN (label);
99090087Sobrien	  if (max_log < log)
99190087Sobrien	    {
99290087Sobrien	      max_log = log;
99390087Sobrien	      max_skip = JUMP_ALIGN_MAX_SKIP;
99490087Sobrien	    }
99590087Sobrien	}
99690087Sobrien      /* In case block is frequent and reached mostly by non-fallthru edge,
997117404Skan	 align it.  It is most likely a first block of loop.  */
99890087Sobrien      if (has_fallthru
99990087Sobrien	  && branch_frequency + fallthru_frequency > BB_FREQ_MAX / 10
1000117404Skan	  && branch_frequency > fallthru_frequency * 2)
100190087Sobrien	{
100290087Sobrien	  log = LOOP_ALIGN (label);
100390087Sobrien	  if (max_log < log)
100490087Sobrien	    {
100590087Sobrien	      max_log = log;
100690087Sobrien	      max_skip = LOOP_ALIGN_MAX_SKIP;
100790087Sobrien	    }
100890087Sobrien	}
100990087Sobrien      LABEL_TO_ALIGNMENT (label) = max_log;
101090087Sobrien      LABEL_TO_MAX_SKIP (label) = max_skip;
101190087Sobrien    }
101290087Sobrien}
101390087Sobrien
101418334Speter/* Make a pass over all insns and compute their actual lengths by shortening
101518334Speter   any branches of variable length if possible.  */
101618334Speter
101718334Speter/* Give a default value for the lowest address in a function.  */
101818334Speter
101918334Speter#ifndef FIRST_INSN_ADDRESS
102018334Speter#define FIRST_INSN_ADDRESS 0
102118334Speter#endif
102218334Speter
102350503Sobrien/* shorten_branches might be called multiple times:  for example, the SH
102450503Sobrien   port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG.
102550503Sobrien   In order to do this, it needs proper length information, which it obtains
102650503Sobrien   by calling shorten_branches.  This cannot be collapsed with
102790087Sobrien   shorten_branches itself into a single pass unless we also want to integrate
102850503Sobrien   reorg.c, since the branch splitting exposes new instructions with delay
102950503Sobrien   slots.  */
103050503Sobrien
103118334Spetervoid
103218334Spetershorten_branches (first)
103390087Sobrien     rtx first ATTRIBUTE_UNUSED;
103418334Speter{
103550503Sobrien  rtx insn;
103650503Sobrien  int max_uid;
103750503Sobrien  int i;
103850503Sobrien  int max_log;
103950503Sobrien  int max_skip;
104018334Speter#ifdef HAVE_ATTR_length
104150503Sobrien#define MAX_CODE_ALIGN 16
104250503Sobrien  rtx seq;
104318334Speter  int something_changed = 1;
104418334Speter  char *varying_length;
104518334Speter  rtx body;
104618334Speter  int uid;
104750503Sobrien  rtx align_tab[MAX_CODE_ALIGN];
104818334Speter
104950503Sobrien#endif
105018334Speter
105150503Sobrien  /* Compute maximum UID and allocate label_align / uid_shuid.  */
105250503Sobrien  max_uid = get_max_uid ();
105350503Sobrien
105450503Sobrien  uid_shuid = (int *) xmalloc (max_uid * sizeof *uid_shuid);
105550503Sobrien
105690087Sobrien  if (max_labelno != max_label_num ())
105790087Sobrien    {
105890087Sobrien      int old = max_labelno;
105990087Sobrien      int n_labels;
106090087Sobrien      int n_old_labels;
106190087Sobrien
106290087Sobrien      max_labelno = max_label_num ();
106390087Sobrien
106490087Sobrien      n_labels = max_labelno - min_labelno + 1;
106590087Sobrien      n_old_labels = old - min_labelno + 1;
106690087Sobrien
106790087Sobrien      label_align = (struct label_alignment *) xrealloc
106890087Sobrien	(label_align, n_labels * sizeof (struct label_alignment));
106990087Sobrien
107090087Sobrien      /* Range of labels grows monotonically in the function.  Abort here
107190087Sobrien         means that the initialization of array got lost.  */
107290087Sobrien      if (n_old_labels > n_labels)
107390087Sobrien	abort ();
107490087Sobrien
107590087Sobrien      memset (label_align + n_old_labels, 0,
107690087Sobrien	      (n_labels - n_old_labels) * sizeof (struct label_alignment));
107790087Sobrien    }
107890087Sobrien
107950503Sobrien  /* Initialize label_align and set up uid_shuid to be strictly
108050503Sobrien     monotonically rising with insn order.  */
108150503Sobrien  /* We use max_log here to keep track of the maximum alignment we want to
108250503Sobrien     impose on the next CODE_LABEL (or the current one if we are processing
108350503Sobrien     the CODE_LABEL itself).  */
108490087Sobrien
108550503Sobrien  max_log = 0;
108650503Sobrien  max_skip = 0;
108750503Sobrien
108850503Sobrien  for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn))
108950503Sobrien    {
109050503Sobrien      int log;
109150503Sobrien
109250503Sobrien      INSN_SHUID (insn) = i++;
109390087Sobrien      if (INSN_P (insn))
109450503Sobrien	{
109550503Sobrien	  /* reorg might make the first insn of a loop being run once only,
109650503Sobrien             and delete the label in front of it.  Then we want to apply
109750503Sobrien             the loop alignment to the new label created by reorg, which
109850503Sobrien             is separated by the former loop start insn from the
109950503Sobrien	     NOTE_INSN_LOOP_BEG.  */
110050503Sobrien	}
110150503Sobrien      else if (GET_CODE (insn) == CODE_LABEL)
110250503Sobrien	{
110350503Sobrien	  rtx next;
110450503Sobrien
110590087Sobrien	  /* Merge in alignments computed by compute_alignments.  */
110690087Sobrien	  log = LABEL_TO_ALIGNMENT (insn);
110790087Sobrien	  if (max_log < log)
110890087Sobrien	    {
110990087Sobrien	      max_log = log;
111090087Sobrien	      max_skip = LABEL_TO_MAX_SKIP (insn);
111190087Sobrien	    }
111290087Sobrien
111350503Sobrien	  log = LABEL_ALIGN (insn);
111450503Sobrien	  if (max_log < log)
111550503Sobrien	    {
111650503Sobrien	      max_log = log;
111750503Sobrien	      max_skip = LABEL_ALIGN_MAX_SKIP;
111850503Sobrien	    }
111950503Sobrien	  next = NEXT_INSN (insn);
112050503Sobrien	  /* ADDR_VECs only take room if read-only data goes into the text
112150503Sobrien	     section.  */
1122117404Skan	  if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
112350503Sobrien	    if (next && GET_CODE (next) == JUMP_INSN)
112450503Sobrien	      {
112550503Sobrien		rtx nextbody = PATTERN (next);
112650503Sobrien		if (GET_CODE (nextbody) == ADDR_VEC
112750503Sobrien		    || GET_CODE (nextbody) == ADDR_DIFF_VEC)
112850503Sobrien		  {
112950503Sobrien		    log = ADDR_VEC_ALIGN (next);
113050503Sobrien		    if (max_log < log)
113150503Sobrien		      {
113250503Sobrien			max_log = log;
113350503Sobrien			max_skip = LABEL_ALIGN_MAX_SKIP;
113450503Sobrien		      }
113550503Sobrien		  }
113650503Sobrien	      }
113750503Sobrien	  LABEL_TO_ALIGNMENT (insn) = max_log;
113850503Sobrien	  LABEL_TO_MAX_SKIP (insn) = max_skip;
113950503Sobrien	  max_log = 0;
114050503Sobrien	  max_skip = 0;
114150503Sobrien	}
114250503Sobrien      else if (GET_CODE (insn) == BARRIER)
114350503Sobrien	{
114450503Sobrien	  rtx label;
114550503Sobrien
114690087Sobrien	  for (label = insn; label && ! INSN_P (label);
114750503Sobrien	       label = NEXT_INSN (label))
114850503Sobrien	    if (GET_CODE (label) == CODE_LABEL)
114950503Sobrien	      {
115050503Sobrien		log = LABEL_ALIGN_AFTER_BARRIER (insn);
115150503Sobrien		if (max_log < log)
115250503Sobrien		  {
115350503Sobrien		    max_log = log;
115450503Sobrien		    max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP;
115550503Sobrien		  }
115650503Sobrien		break;
115750503Sobrien	      }
115850503Sobrien	}
115950503Sobrien    }
116050503Sobrien#ifdef HAVE_ATTR_length
116150503Sobrien
116250503Sobrien  /* Allocate the rest of the arrays.  */
116390087Sobrien  insn_lengths = (int *) xmalloc (max_uid * sizeof (*insn_lengths));
116452515Sobrien  insn_lengths_max_uid = max_uid;
116550503Sobrien  /* Syntax errors can lead to labels being outside of the main insn stream.
116650503Sobrien     Initialize insn_addresses, so that we get reproducible results.  */
116790087Sobrien  INSN_ADDRESSES_ALLOC (max_uid);
116850503Sobrien
116990087Sobrien  varying_length = (char *) xcalloc (max_uid, sizeof (char));
117050503Sobrien
117150503Sobrien  /* Initialize uid_align.  We scan instructions
117250503Sobrien     from end to start, and keep in align_tab[n] the last seen insn
117350503Sobrien     that does an alignment of at least n+1, i.e. the successor
117450503Sobrien     in the alignment chain for an insn that does / has a known
117550503Sobrien     alignment of n.  */
117690087Sobrien  uid_align = (rtx *) xcalloc (max_uid, sizeof *uid_align);
117750503Sobrien
117890087Sobrien  for (i = MAX_CODE_ALIGN; --i >= 0;)
117950503Sobrien    align_tab[i] = NULL_RTX;
118050503Sobrien  seq = get_last_insn ();
118150503Sobrien  for (; seq; seq = PREV_INSN (seq))
118250503Sobrien    {
118350503Sobrien      int uid = INSN_UID (seq);
118450503Sobrien      int log;
118550503Sobrien      log = (GET_CODE (seq) == CODE_LABEL ? LABEL_TO_ALIGNMENT (seq) : 0);
118650503Sobrien      uid_align[uid] = align_tab[0];
118750503Sobrien      if (log)
118850503Sobrien	{
118950503Sobrien	  /* Found an alignment label.  */
119050503Sobrien	  uid_align[uid] = align_tab[log];
119150503Sobrien	  for (i = log - 1; i >= 0; i--)
119250503Sobrien	    align_tab[i] = seq;
119350503Sobrien	}
119450503Sobrien    }
119550503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE
119650503Sobrien  if (optimize)
119750503Sobrien    {
119850503Sobrien      /* Look for ADDR_DIFF_VECs, and initialize their minimum and maximum
119950503Sobrien         label fields.  */
120050503Sobrien
120150503Sobrien      int min_shuid = INSN_SHUID (get_insns ()) - 1;
120250503Sobrien      int max_shuid = INSN_SHUID (get_last_insn ()) + 1;
120350503Sobrien      int rel;
120450503Sobrien
120550503Sobrien      for (insn = first; insn != 0; insn = NEXT_INSN (insn))
120650503Sobrien	{
120750503Sobrien	  rtx min_lab = NULL_RTX, max_lab = NULL_RTX, pat;
120850503Sobrien	  int len, i, min, max, insn_shuid;
120950503Sobrien	  int min_align;
121050503Sobrien	  addr_diff_vec_flags flags;
121150503Sobrien
121250503Sobrien	  if (GET_CODE (insn) != JUMP_INSN
121350503Sobrien	      || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
121450503Sobrien	    continue;
121550503Sobrien	  pat = PATTERN (insn);
121650503Sobrien	  len = XVECLEN (pat, 1);
121750503Sobrien	  if (len <= 0)
121850503Sobrien	    abort ();
121950503Sobrien	  min_align = MAX_CODE_ALIGN;
122050503Sobrien	  for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--)
122150503Sobrien	    {
122250503Sobrien	      rtx lab = XEXP (XVECEXP (pat, 1, i), 0);
122350503Sobrien	      int shuid = INSN_SHUID (lab);
122450503Sobrien	      if (shuid < min)
122550503Sobrien		{
122650503Sobrien		  min = shuid;
122750503Sobrien		  min_lab = lab;
122850503Sobrien		}
122950503Sobrien	      if (shuid > max)
123050503Sobrien		{
123150503Sobrien		  max = shuid;
123250503Sobrien		  max_lab = lab;
123350503Sobrien		}
123450503Sobrien	      if (min_align > LABEL_TO_ALIGNMENT (lab))
123550503Sobrien		min_align = LABEL_TO_ALIGNMENT (lab);
123650503Sobrien	    }
123750503Sobrien	  XEXP (pat, 2) = gen_rtx_LABEL_REF (VOIDmode, min_lab);
123850503Sobrien	  XEXP (pat, 3) = gen_rtx_LABEL_REF (VOIDmode, max_lab);
123950503Sobrien	  insn_shuid = INSN_SHUID (insn);
124050503Sobrien	  rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0));
124150503Sobrien	  flags.min_align = min_align;
124250503Sobrien	  flags.base_after_vec = rel > insn_shuid;
124350503Sobrien	  flags.min_after_vec  = min > insn_shuid;
124450503Sobrien	  flags.max_after_vec  = max > insn_shuid;
124550503Sobrien	  flags.min_after_base = min > rel;
124650503Sobrien	  flags.max_after_base = max > rel;
124750503Sobrien	  ADDR_DIFF_VEC_FLAGS (pat) = flags;
124850503Sobrien	}
124950503Sobrien    }
125050503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */
125150503Sobrien
125218334Speter  /* Compute initial lengths, addresses, and varying flags for each insn.  */
125318334Speter  for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
125418334Speter       insn != 0;
125518334Speter       insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
125618334Speter    {
125718334Speter      uid = INSN_UID (insn);
125850503Sobrien
125950503Sobrien      insn_lengths[uid] = 0;
126050503Sobrien
126150503Sobrien      if (GET_CODE (insn) == CODE_LABEL)
126250503Sobrien	{
126350503Sobrien	  int log = LABEL_TO_ALIGNMENT (insn);
126450503Sobrien	  if (log)
126550503Sobrien	    {
126650503Sobrien	      int align = 1 << log;
126750503Sobrien	      int new_address = (insn_current_address + align - 1) & -align;
126850503Sobrien	      insn_lengths[uid] = new_address - insn_current_address;
126950503Sobrien	    }
127050503Sobrien	}
127150503Sobrien
1272117404Skan      INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid];
127390087Sobrien
127418334Speter      if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER
127518334Speter	  || GET_CODE (insn) == CODE_LABEL)
127618334Speter	continue;
127750503Sobrien      if (INSN_DELETED_P (insn))
127850503Sobrien	continue;
127918334Speter
128018334Speter      body = PATTERN (insn);
128118334Speter      if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
128218334Speter	{
128318334Speter	  /* This only takes room if read-only data goes into the text
128418334Speter	     section.  */
1285117404Skan	  if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
128650503Sobrien	    insn_lengths[uid] = (XVECLEN (body,
128750503Sobrien					  GET_CODE (body) == ADDR_DIFF_VEC)
128850503Sobrien				 * GET_MODE_SIZE (GET_MODE (body)));
128950503Sobrien	  /* Alignment is handled by ADDR_VEC_ALIGN.  */
129018334Speter	}
129190087Sobrien      else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
129218334Speter	insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn);
129318334Speter      else if (GET_CODE (body) == SEQUENCE)
129418334Speter	{
129518334Speter	  int i;
129618334Speter	  int const_delay_slots;
129718334Speter#ifdef DELAY_SLOTS
129818334Speter	  const_delay_slots = const_num_delay_slots (XVECEXP (body, 0, 0));
129918334Speter#else
130018334Speter	  const_delay_slots = 0;
130118334Speter#endif
130218334Speter	  /* Inside a delay slot sequence, we do not do any branch shortening
130318334Speter	     if the shortening could change the number of delay slots
130450503Sobrien	     of the branch.  */
130518334Speter	  for (i = 0; i < XVECLEN (body, 0); i++)
130618334Speter	    {
130718334Speter	      rtx inner_insn = XVECEXP (body, 0, i);
130818334Speter	      int inner_uid = INSN_UID (inner_insn);
130918334Speter	      int inner_length;
131018334Speter
131190087Sobrien	      if (GET_CODE (body) == ASM_INPUT
131290087Sobrien		  || asm_noperands (PATTERN (XVECEXP (body, 0, i))) >= 0)
131318334Speter		inner_length = (asm_insn_count (PATTERN (inner_insn))
131418334Speter				* insn_default_length (inner_insn));
131518334Speter	      else
131618334Speter		inner_length = insn_default_length (inner_insn);
131790087Sobrien
131818334Speter	      insn_lengths[inner_uid] = inner_length;
131918334Speter	      if (const_delay_slots)
132018334Speter		{
132118334Speter		  if ((varying_length[inner_uid]
132218334Speter		       = insn_variable_length_p (inner_insn)) != 0)
132318334Speter		    varying_length[uid] = 1;
132490087Sobrien		  INSN_ADDRESSES (inner_uid) = (insn_current_address
132590087Sobrien						+ insn_lengths[uid]);
132618334Speter		}
132718334Speter	      else
132818334Speter		varying_length[inner_uid] = 0;
132918334Speter	      insn_lengths[uid] += inner_length;
133018334Speter	    }
133118334Speter	}
133218334Speter      else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER)
133318334Speter	{
133418334Speter	  insn_lengths[uid] = insn_default_length (insn);
133518334Speter	  varying_length[uid] = insn_variable_length_p (insn);
133618334Speter	}
133718334Speter
133818334Speter      /* If needed, do any adjustment.  */
133918334Speter#ifdef ADJUST_INSN_LENGTH
134018334Speter      ADJUST_INSN_LENGTH (insn, insn_lengths[uid]);
134152515Sobrien      if (insn_lengths[uid] < 0)
134290087Sobrien	fatal_insn ("negative insn length", insn);
134318334Speter#endif
134418334Speter    }
134518334Speter
134618334Speter  /* Now loop over all the insns finding varying length insns.  For each,
134718334Speter     get the current insn length.  If it has changed, reflect the change.
134818334Speter     When nothing changes for a full pass, we are done.  */
134918334Speter
135018334Speter  while (something_changed)
135118334Speter    {
135218334Speter      something_changed = 0;
135350503Sobrien      insn_current_align = MAX_CODE_ALIGN - 1;
135418334Speter      for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
135518334Speter	   insn != 0;
135618334Speter	   insn = NEXT_INSN (insn))
135718334Speter	{
135818334Speter	  int new_length;
135950503Sobrien#ifdef ADJUST_INSN_LENGTH
136018334Speter	  int tmp_length;
136150503Sobrien#endif
136250503Sobrien	  int length_align;
136318334Speter
136418334Speter	  uid = INSN_UID (insn);
136550503Sobrien
136650503Sobrien	  if (GET_CODE (insn) == CODE_LABEL)
136750503Sobrien	    {
136850503Sobrien	      int log = LABEL_TO_ALIGNMENT (insn);
136950503Sobrien	      if (log > insn_current_align)
137050503Sobrien		{
137150503Sobrien		  int align = 1 << log;
137250503Sobrien		  int new_address= (insn_current_address + align - 1) & -align;
137350503Sobrien		  insn_lengths[uid] = new_address - insn_current_address;
137450503Sobrien		  insn_current_align = log;
137550503Sobrien		  insn_current_address = new_address;
137650503Sobrien		}
137750503Sobrien	      else
137850503Sobrien		insn_lengths[uid] = 0;
137990087Sobrien	      INSN_ADDRESSES (uid) = insn_current_address;
138050503Sobrien	      continue;
138150503Sobrien	    }
138250503Sobrien
138350503Sobrien	  length_align = INSN_LENGTH_ALIGNMENT (insn);
138450503Sobrien	  if (length_align < insn_current_align)
138550503Sobrien	    insn_current_align = length_align;
138650503Sobrien
138790087Sobrien	  insn_last_address = INSN_ADDRESSES (uid);
138890087Sobrien	  INSN_ADDRESSES (uid) = insn_current_address;
138950503Sobrien
139050503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE
139150503Sobrien	  if (optimize && GET_CODE (insn) == JUMP_INSN
139250503Sobrien	      && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
139318334Speter	    {
139450503Sobrien	      rtx body = PATTERN (insn);
139550503Sobrien	      int old_length = insn_lengths[uid];
139650503Sobrien	      rtx rel_lab = XEXP (XEXP (body, 0), 0);
139750503Sobrien	      rtx min_lab = XEXP (XEXP (body, 2), 0);
139850503Sobrien	      rtx max_lab = XEXP (XEXP (body, 3), 0);
139990087Sobrien	      int rel_addr = INSN_ADDRESSES (INSN_UID (rel_lab));
140090087Sobrien	      int min_addr = INSN_ADDRESSES (INSN_UID (min_lab));
140190087Sobrien	      int max_addr = INSN_ADDRESSES (INSN_UID (max_lab));
140250503Sobrien	      rtx prev;
140350503Sobrien	      int rel_align = 0;
140490087Sobrien	      addr_diff_vec_flags flags;
140550503Sobrien
140690087Sobrien	      /* Avoid automatic aggregate initialization.  */
140790087Sobrien	      flags = ADDR_DIFF_VEC_FLAGS (body);
140890087Sobrien
140950503Sobrien	      /* Try to find a known alignment for rel_lab.  */
141050503Sobrien	      for (prev = rel_lab;
141150503Sobrien		   prev
141250503Sobrien		   && ! insn_lengths[INSN_UID (prev)]
141350503Sobrien		   && ! (varying_length[INSN_UID (prev)] & 1);
141450503Sobrien		   prev = PREV_INSN (prev))
141550503Sobrien		if (varying_length[INSN_UID (prev)] & 2)
141650503Sobrien		  {
141750503Sobrien		    rel_align = LABEL_TO_ALIGNMENT (prev);
141850503Sobrien		    break;
141950503Sobrien		  }
142050503Sobrien
142150503Sobrien	      /* See the comment on addr_diff_vec_flags in rtl.h for the
142250503Sobrien		 meaning of the flags values.  base: REL_LAB   vec: INSN  */
142350503Sobrien	      /* Anything after INSN has still addresses from the last
142450503Sobrien		 pass; adjust these so that they reflect our current
142550503Sobrien		 estimate for this pass.  */
142650503Sobrien	      if (flags.base_after_vec)
142750503Sobrien		rel_addr += insn_current_address - insn_last_address;
142850503Sobrien	      if (flags.min_after_vec)
142950503Sobrien		min_addr += insn_current_address - insn_last_address;
143050503Sobrien	      if (flags.max_after_vec)
143150503Sobrien		max_addr += insn_current_address - insn_last_address;
143250503Sobrien	      /* We want to know the worst case, i.e. lowest possible value
143350503Sobrien		 for the offset of MIN_LAB.  If MIN_LAB is after REL_LAB,
143450503Sobrien		 its offset is positive, and we have to be wary of code shrink;
143550503Sobrien		 otherwise, it is negative, and we have to be vary of code
143650503Sobrien		 size increase.  */
143750503Sobrien	      if (flags.min_after_base)
143850503Sobrien		{
143950503Sobrien		  /* If INSN is between REL_LAB and MIN_LAB, the size
144050503Sobrien		     changes we are about to make can change the alignment
144150503Sobrien		     within the observed offset, therefore we have to break
144250503Sobrien		     it up into two parts that are independent.  */
144350503Sobrien		  if (! flags.base_after_vec && flags.min_after_vec)
144450503Sobrien		    {
144550503Sobrien		      min_addr -= align_fuzz (rel_lab, insn, rel_align, 0);
144650503Sobrien		      min_addr -= align_fuzz (insn, min_lab, 0, 0);
144750503Sobrien		    }
144850503Sobrien		  else
144950503Sobrien		    min_addr -= align_fuzz (rel_lab, min_lab, rel_align, 0);
145050503Sobrien		}
145150503Sobrien	      else
145250503Sobrien		{
145350503Sobrien		  if (flags.base_after_vec && ! flags.min_after_vec)
145450503Sobrien		    {
145550503Sobrien		      min_addr -= align_fuzz (min_lab, insn, 0, ~0);
145650503Sobrien		      min_addr -= align_fuzz (insn, rel_lab, 0, ~0);
145750503Sobrien		    }
145850503Sobrien		  else
145950503Sobrien		    min_addr -= align_fuzz (min_lab, rel_lab, 0, ~0);
146050503Sobrien		}
146150503Sobrien	      /* Likewise, determine the highest lowest possible value
146250503Sobrien		 for the offset of MAX_LAB.  */
146350503Sobrien	      if (flags.max_after_base)
146450503Sobrien		{
146550503Sobrien		  if (! flags.base_after_vec && flags.max_after_vec)
146650503Sobrien		    {
146750503Sobrien		      max_addr += align_fuzz (rel_lab, insn, rel_align, ~0);
146850503Sobrien		      max_addr += align_fuzz (insn, max_lab, 0, ~0);
146950503Sobrien		    }
147050503Sobrien		  else
147150503Sobrien		    max_addr += align_fuzz (rel_lab, max_lab, rel_align, ~0);
147250503Sobrien		}
147350503Sobrien	      else
147450503Sobrien		{
147550503Sobrien		  if (flags.base_after_vec && ! flags.max_after_vec)
147650503Sobrien		    {
147750503Sobrien		      max_addr += align_fuzz (max_lab, insn, 0, 0);
147850503Sobrien		      max_addr += align_fuzz (insn, rel_lab, 0, 0);
147950503Sobrien		    }
148050503Sobrien		  else
148150503Sobrien		    max_addr += align_fuzz (max_lab, rel_lab, 0, 0);
148250503Sobrien		}
148350503Sobrien	      PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
148450503Sobrien							max_addr - rel_addr,
148550503Sobrien							body));
1486117404Skan	      if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
148750503Sobrien		{
148850503Sobrien		  insn_lengths[uid]
148950503Sobrien		    = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body)));
149050503Sobrien		  insn_current_address += insn_lengths[uid];
149150503Sobrien		  if (insn_lengths[uid] != old_length)
149250503Sobrien		    something_changed = 1;
149350503Sobrien		}
149450503Sobrien
149550503Sobrien	      continue;
149650503Sobrien	    }
149750503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */
149850503Sobrien
149950503Sobrien	  if (! (varying_length[uid]))
150050503Sobrien	    {
150190087Sobrien	      if (GET_CODE (insn) == INSN
150290087Sobrien		  && GET_CODE (PATTERN (insn)) == SEQUENCE)
150390087Sobrien		{
150490087Sobrien		  int i;
150590087Sobrien
150690087Sobrien		  body = PATTERN (insn);
150790087Sobrien		  for (i = 0; i < XVECLEN (body, 0); i++)
150890087Sobrien		    {
150990087Sobrien		      rtx inner_insn = XVECEXP (body, 0, i);
151090087Sobrien		      int inner_uid = INSN_UID (inner_insn);
151190087Sobrien
151290087Sobrien		      INSN_ADDRESSES (inner_uid) = insn_current_address;
151390087Sobrien
151490087Sobrien		      insn_current_address += insn_lengths[inner_uid];
151590087Sobrien		    }
1516117404Skan		}
151790087Sobrien	      else
151890087Sobrien		insn_current_address += insn_lengths[uid];
151990087Sobrien
152018334Speter	      continue;
152118334Speter	    }
152290087Sobrien
152318334Speter	  if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
152418334Speter	    {
152518334Speter	      int i;
152690087Sobrien
152718334Speter	      body = PATTERN (insn);
152818334Speter	      new_length = 0;
152918334Speter	      for (i = 0; i < XVECLEN (body, 0); i++)
153018334Speter		{
153118334Speter		  rtx inner_insn = XVECEXP (body, 0, i);
153218334Speter		  int inner_uid = INSN_UID (inner_insn);
153318334Speter		  int inner_length;
153418334Speter
153590087Sobrien		  INSN_ADDRESSES (inner_uid) = insn_current_address;
153618334Speter
153718334Speter		  /* insn_current_length returns 0 for insns with a
153818334Speter		     non-varying length.  */
153918334Speter		  if (! varying_length[inner_uid])
154018334Speter		    inner_length = insn_lengths[inner_uid];
154118334Speter		  else
154218334Speter		    inner_length = insn_current_length (inner_insn);
154318334Speter
154418334Speter		  if (inner_length != insn_lengths[inner_uid])
154518334Speter		    {
154618334Speter		      insn_lengths[inner_uid] = inner_length;
154718334Speter		      something_changed = 1;
154818334Speter		    }
154918334Speter		  insn_current_address += insn_lengths[inner_uid];
155018334Speter		  new_length += inner_length;
155118334Speter		}
155218334Speter	    }
155318334Speter	  else
155418334Speter	    {
155518334Speter	      new_length = insn_current_length (insn);
155618334Speter	      insn_current_address += new_length;
155718334Speter	    }
155818334Speter
155918334Speter#ifdef ADJUST_INSN_LENGTH
156018334Speter	  /* If needed, do any adjustment.  */
156118334Speter	  tmp_length = new_length;
156218334Speter	  ADJUST_INSN_LENGTH (insn, new_length);
156318334Speter	  insn_current_address += (new_length - tmp_length);
156418334Speter#endif
156518334Speter
156618334Speter	  if (new_length != insn_lengths[uid])
156718334Speter	    {
156818334Speter	      insn_lengths[uid] = new_length;
156918334Speter	      something_changed = 1;
157018334Speter	    }
157118334Speter	}
157218334Speter      /* For a non-optimizing compile, do only a single pass.  */
157318334Speter      if (!optimize)
157418334Speter	break;
157518334Speter    }
157650503Sobrien
157750503Sobrien  free (varying_length);
157850503Sobrien
157918334Speter#endif /* HAVE_ATTR_length */
158018334Speter}
158118334Speter
158218334Speter#ifdef HAVE_ATTR_length
158318334Speter/* Given the body of an INSN known to be generated by an ASM statement, return
158418334Speter   the number of machine instructions likely to be generated for this insn.
158518334Speter   This is used to compute its length.  */
158618334Speter
158718334Speterstatic int
158818334Speterasm_insn_count (body)
158918334Speter     rtx body;
159018334Speter{
159190087Sobrien  const char *template;
159218334Speter  int count = 1;
159318334Speter
159418334Speter  if (GET_CODE (body) == ASM_INPUT)
159518334Speter    template = XSTR (body, 0);
159618334Speter  else
159790087Sobrien    template = decode_asm_operands (body, NULL, NULL, NULL, NULL);
159818334Speter
159990087Sobrien  for (; *template; template++)
160090087Sobrien    if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n')
160118334Speter      count++;
160218334Speter
160318334Speter  return count;
160418334Speter}
160518334Speter#endif
160618334Speter
160718334Speter/* Output assembler code for the start of a function,
160818334Speter   and initialize some of the variables in this file
160918334Speter   for the new function.  The label for the function and associated
161018334Speter   assembler pseudo-ops have already been output in `assemble_start_function'.
161118334Speter
161218334Speter   FIRST is the first insn of the rtl for the function being compiled.
161318334Speter   FILE is the file to write assembler code to.
161418334Speter   OPTIMIZE is nonzero if we should eliminate redundant
161518334Speter     test and compare insns.  */
161618334Speter
161718334Spetervoid
161818334Speterfinal_start_function (first, file, optimize)
161918334Speter     rtx first;
162018334Speter     FILE *file;
162190087Sobrien     int optimize ATTRIBUTE_UNUSED;
162218334Speter{
162318334Speter  block_depth = 0;
162418334Speter
162518334Speter  this_is_asm_operands = 0;
162618334Speter
162718334Speter#ifdef NON_SAVING_SETJMP
162818334Speter  /* A function that calls setjmp should save and restore all the
162918334Speter     call-saved registers on a system where longjmp clobbers them.  */
163018334Speter  if (NON_SAVING_SETJMP && current_function_calls_setjmp)
163118334Speter    {
163218334Speter      int i;
163318334Speter
163418334Speter      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
163552515Sobrien	if (!call_used_regs[i])
163618334Speter	  regs_ever_live[i] = 1;
163718334Speter    }
163818334Speter#endif
163990087Sobrien
164018334Speter  if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED)
164190087Sobrien    notice_source_line (first);
164290087Sobrien  high_block_linenum = high_function_linenum = last_linenum;
164318334Speter
164490087Sobrien  (*debug_hooks->begin_prologue) (last_linenum, last_filename);
164550503Sobrien
164690087Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (IA64_UNWIND_INFO)
164790087Sobrien  if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG)
164890087Sobrien    dwarf2out_begin_prologue (0, NULL);
164918334Speter#endif
165018334Speter
165118334Speter#ifdef LEAF_REG_REMAP
165252515Sobrien  if (current_function_uses_only_leaf_regs)
165318334Speter    leaf_renumber_regs (first);
165418334Speter#endif
165518334Speter
165618334Speter  /* The Sun386i and perhaps other machines don't work right
165718334Speter     if the profiling code comes after the prologue.  */
165818334Speter#ifdef PROFILE_BEFORE_PROLOGUE
165990087Sobrien  if (current_function_profile)
166018334Speter    profile_function (file);
166118334Speter#endif /* PROFILE_BEFORE_PROLOGUE */
166218334Speter
166350503Sobrien#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
166450503Sobrien  if (dwarf2out_do_frame ())
166550503Sobrien    dwarf2out_frame_debug (NULL_RTX);
166650503Sobrien#endif
166750503Sobrien
166890087Sobrien  /* If debugging, assign block numbers to all of the blocks in this
166990087Sobrien     function.  */
167090087Sobrien  if (write_symbols)
167190087Sobrien    {
167290087Sobrien      remove_unnecessary_notes ();
1673117404Skan      scope_to_insns_finalize ();
167490087Sobrien      number_blocks (current_function_decl);
167590087Sobrien      /* We never actually put out begin/end notes for the top-level
167690087Sobrien	 block in the function.  But, conceptually, that block is
167790087Sobrien	 always needed.  */
167890087Sobrien      TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
167990087Sobrien    }
168090087Sobrien
168118334Speter  /* First output the function prologue: code to set up the stack frame.  */
168290087Sobrien  (*targetm.asm_out.function_prologue) (file, get_frame_size ());
168318334Speter
168418334Speter  /* If the machine represents the prologue as RTL, the profiling code must
168518334Speter     be emitted when NOTE_INSN_PROLOGUE_END is scanned.  */
168618334Speter#ifdef HAVE_prologue
168718334Speter  if (! HAVE_prologue)
168818334Speter#endif
168918334Speter    profile_after_prologue (file);
169018334Speter}
169118334Speter
169218334Speterstatic void
169318334Speterprofile_after_prologue (file)
169490087Sobrien     FILE *file ATTRIBUTE_UNUSED;
169518334Speter{
169618334Speter#ifndef PROFILE_BEFORE_PROLOGUE
169790087Sobrien  if (current_function_profile)
169818334Speter    profile_function (file);
169918334Speter#endif /* not PROFILE_BEFORE_PROLOGUE */
170018334Speter}
170118334Speter
170218334Speterstatic void
170318334Speterprofile_function (file)
170490087Sobrien     FILE *file ATTRIBUTE_UNUSED;
170518334Speter{
170674478Sobrien#ifndef NO_PROFILE_COUNTERS
170750503Sobrien  int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
170874478Sobrien#endif
170950503Sobrien#if defined(ASM_OUTPUT_REG_PUSH)
171050503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) || defined(STRUCT_VALUE_REGNUM)
171118334Speter  int sval = current_function_returns_struct;
171250503Sobrien#endif
171350503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM)
171418334Speter  int cxt = current_function_needs_context;
171550503Sobrien#endif
171650503Sobrien#endif /* ASM_OUTPUT_REG_PUSH */
171718334Speter
171874478Sobrien#ifndef NO_PROFILE_COUNTERS
171918334Speter  data_section ();
172018334Speter  ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
1721117404Skan  ASM_OUTPUT_INTERNAL_LABEL (file, "LP", current_function_funcdef_no);
172290087Sobrien  assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
172374478Sobrien#endif
172418334Speter
172550503Sobrien  function_section (current_function_decl);
172618334Speter
172750503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
172818334Speter  if (sval)
172918334Speter    ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_INCOMING_REGNUM);
173018334Speter#else
173150503Sobrien#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
173218334Speter  if (sval)
173350503Sobrien    {
173450503Sobrien      ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_REGNUM);
173550503Sobrien    }
173618334Speter#endif
173718334Speter#endif
173818334Speter
173950503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
174018334Speter  if (cxt)
174118334Speter    ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM);
174218334Speter#else
174350503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
174418334Speter  if (cxt)
174550503Sobrien    {
174650503Sobrien      ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM);
174750503Sobrien    }
174818334Speter#endif
174918334Speter#endif
175018334Speter
1751117404Skan  FUNCTION_PROFILER (file, current_function_funcdef_no);
175218334Speter
175350503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
175418334Speter  if (cxt)
175518334Speter    ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM);
175618334Speter#else
175750503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
175818334Speter  if (cxt)
175950503Sobrien    {
176050503Sobrien      ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM);
176150503Sobrien    }
176218334Speter#endif
176318334Speter#endif
176418334Speter
176550503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
176618334Speter  if (sval)
176718334Speter    ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_INCOMING_REGNUM);
176818334Speter#else
176950503Sobrien#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
177018334Speter  if (sval)
177150503Sobrien    {
177250503Sobrien      ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_REGNUM);
177350503Sobrien    }
177418334Speter#endif
177518334Speter#endif
177618334Speter}
177718334Speter
177818334Speter/* Output assembler code for the end of a function.
177918334Speter   For clarity, args are same as those of `final_start_function'
178018334Speter   even though not all of them are needed.  */
178118334Speter
178218334Spetervoid
178390087Sobrienfinal_end_function ()
178418334Speter{
178590087Sobrien  app_disable ();
178618334Speter
178790087Sobrien  (*debug_hooks->end_function) (high_function_linenum);
178818334Speter
178918334Speter  /* Finally, output the function epilogue:
179018334Speter     code to restore the stack frame and return to the caller.  */
179190087Sobrien  (*targetm.asm_out.function_epilogue) (asm_out_file, get_frame_size ());
179218334Speter
179390087Sobrien  /* And debug output.  */
1794117404Skan  (*debug_hooks->end_epilogue) (last_linenum, last_filename);
179590087Sobrien
179690087Sobrien#if defined (DWARF2_UNWIND_INFO)
179790087Sobrien  if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG
179890087Sobrien      && dwarf2out_do_frame ())
1799117404Skan    dwarf2out_end_epilogue (last_linenum, last_filename);
180050503Sobrien#endif
180118334Speter}
180218334Speter
180318334Speter/* Output assembler code for some insns: all or part of a function.
180418334Speter   For description of args, see `final_start_function', above.
180518334Speter
180618334Speter   PRESCAN is 1 if we are not really outputting,
180718334Speter     just scanning as if we were outputting.
180818334Speter   Prescanning deletes and rearranges insns just like ordinary output.
180918334Speter   PRESCAN is -2 if we are outputting after having prescanned.
181018334Speter   In this case, don't try to delete or rearrange insns
181118334Speter   because that has already been done.
181218334Speter   Prescanning is done only on certain machines.  */
181318334Speter
181418334Spetervoid
181518334Speterfinal (first, file, optimize, prescan)
181618334Speter     rtx first;
181718334Speter     FILE *file;
181818334Speter     int optimize;
181918334Speter     int prescan;
182018334Speter{
182190087Sobrien  rtx insn;
182218334Speter  int max_line = 0;
182350503Sobrien  int max_uid = 0;
182418334Speter
182518334Speter  last_ignored_compare = 0;
182618334Speter  new_block = 1;
182718334Speter
182818334Speter  /* Make a map indicating which line numbers appear in this function.
182918334Speter     When producing SDB debugging info, delete troublesome line number
183018334Speter     notes from inlined functions in other files as well as duplicate
183118334Speter     line number notes.  */
183218334Speter#ifdef SDB_DEBUGGING_INFO
183318334Speter  if (write_symbols == SDB_DEBUG)
183418334Speter    {
183518334Speter      rtx last = 0;
183618334Speter      for (insn = first; insn; insn = NEXT_INSN (insn))
183718334Speter	if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
183818334Speter	  {
183918334Speter	    if ((RTX_INTEGRATED_P (insn)
184018334Speter		 && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0)
184118334Speter		 || (last != 0
184218334Speter		     && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
184318334Speter		     && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)))
184418334Speter	      {
184590087Sobrien		delete_insn (insn);	/* Use delete_note.  */
184618334Speter		continue;
184718334Speter	      }
184818334Speter	    last = insn;
184918334Speter	    if (NOTE_LINE_NUMBER (insn) > max_line)
185018334Speter	      max_line = NOTE_LINE_NUMBER (insn);
185118334Speter	  }
185218334Speter    }
185318334Speter  else
185418334Speter#endif
185518334Speter    {
185618334Speter      for (insn = first; insn; insn = NEXT_INSN (insn))
185718334Speter	if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > max_line)
185818334Speter	  max_line = NOTE_LINE_NUMBER (insn);
185918334Speter    }
186018334Speter
186190087Sobrien  line_note_exists = (char *) xcalloc (max_line + 1, sizeof (char));
186218334Speter
186318334Speter  for (insn = first; insn; insn = NEXT_INSN (insn))
186450503Sobrien    {
186550503Sobrien      if (INSN_UID (insn) > max_uid)       /* find largest UID */
186690087Sobrien	max_uid = INSN_UID (insn);
186750503Sobrien      if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
186890087Sobrien	line_note_exists[NOTE_LINE_NUMBER (insn)] = 1;
186952515Sobrien#ifdef HAVE_cc0
187052515Sobrien      /* If CC tracking across branches is enabled, record the insn which
187152515Sobrien	 jumps to each branch only reached from one place.  */
187252515Sobrien      if (optimize && GET_CODE (insn) == JUMP_INSN)
187352515Sobrien	{
187452515Sobrien	  rtx lab = JUMP_LABEL (insn);
187552515Sobrien	  if (lab && LABEL_NUSES (lab) == 1)
187652515Sobrien	    {
187752515Sobrien	      LABEL_REFS (lab) = insn;
187852515Sobrien	    }
187952515Sobrien	}
188052515Sobrien#endif
188150503Sobrien    }
188218334Speter
188318334Speter  init_recog ();
188418334Speter
188518334Speter  CC_STATUS_INIT;
188618334Speter
188718334Speter  /* Output the insns.  */
188818334Speter  for (insn = NEXT_INSN (first); insn;)
188950503Sobrien    {
189050503Sobrien#ifdef HAVE_ATTR_length
189190087Sobrien      if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ())
189290087Sobrien	{
189390087Sobrien	  /* This can be triggered by bugs elsewhere in the compiler if
189490087Sobrien	     new insns are created after init_insn_lengths is called.  */
1895117404Skan	  if (GET_CODE (insn) == NOTE)
1896117404Skan	    insn_current_address = -1;
1897117404Skan	  else
1898117404Skan	    abort ();
189990087Sobrien	}
190090087Sobrien      else
190190087Sobrien	insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
190290087Sobrien#endif /* HAVE_ATTR_length */
190390087Sobrien
190450503Sobrien      insn = final_scan_insn (insn, file, optimize, prescan, 0);
190550503Sobrien    }
190618334Speter
1907117404Skan  /* Store function names for edge-profiling.  */
1908117404Skan  /* ??? Probably should re-use the existing struct function.  */
1909117404Skan
1910117404Skan  if (cfun->arc_profile)
1911117404Skan    {
1912117404Skan      struct function_list *new_item = xmalloc (sizeof (struct function_list));
1913117404Skan
1914117404Skan      *functions_tail = new_item;
1915117404Skan      functions_tail = &new_item->next;
1916117404Skan
1917117404Skan      new_item->next = 0;
1918117404Skan      new_item->name = xstrdup (IDENTIFIER_POINTER
1919117404Skan				 (DECL_ASSEMBLER_NAME (current_function_decl)));
1920117404Skan      new_item->cfg_checksum = profile_info.current_function_cfg_checksum;
1921117404Skan      new_item->count_edges = profile_info.count_edges_instrumented_now;
1922117404Skan    }
1923117404Skan
192490087Sobrien  free (line_note_exists);
192590087Sobrien  line_note_exists = NULL;
192690087Sobrien}
192790087Sobrien
192890087Sobrienconst char *
192990087Sobrienget_insn_template (code, insn)
193090087Sobrien     int code;
193190087Sobrien     rtx insn;
193290087Sobrien{
193390087Sobrien  const void *output = insn_data[code].output;
193490087Sobrien  switch (insn_data[code].output_format)
193590087Sobrien    {
193690087Sobrien    case INSN_OUTPUT_FORMAT_SINGLE:
193790087Sobrien      return (const char *) output;
193890087Sobrien    case INSN_OUTPUT_FORMAT_MULTI:
193990087Sobrien      return ((const char *const *) output)[which_alternative];
194090087Sobrien    case INSN_OUTPUT_FORMAT_FUNCTION:
194190087Sobrien      if (insn == NULL)
194290087Sobrien	abort ();
194390087Sobrien      return (*(insn_output_fn) output) (recog_data.operand, insn);
194450503Sobrien
194590087Sobrien    default:
194690087Sobrien      abort ();
194790087Sobrien    }
194818334Speter}
194990087Sobrien
1950117404Skan/* Emit the appropriate declaration for an alternate-entry-point
1951117404Skan   symbol represented by INSN, to FILE.  INSN is a CODE_LABEL with
1952117404Skan   LABEL_KIND != LABEL_NORMAL.
1953117404Skan
1954117404Skan   The case fall-through in this function is intentional.  */
1955117404Skanstatic void
1956117404Skanoutput_alternate_entry_point (file, insn)
1957117404Skan     FILE *file;
1958117404Skan     rtx insn;
1959117404Skan{
1960117404Skan  const char *name = LABEL_NAME (insn);
1961117404Skan
1962117404Skan  switch (LABEL_KIND (insn))
1963117404Skan    {
1964117404Skan    case LABEL_WEAK_ENTRY:
1965117404Skan#ifdef ASM_WEAKEN_LABEL
1966117404Skan      ASM_WEAKEN_LABEL (file, name);
1967117404Skan#endif
1968117404Skan    case LABEL_GLOBAL_ENTRY:
1969117404Skan      (*targetm.asm_out.globalize_label) (file, name);
1970117404Skan    case LABEL_STATIC_ENTRY:
1971117404Skan#ifdef ASM_OUTPUT_TYPE_DIRECTIVE
1972117404Skan      ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
1973117404Skan#endif
1974117404Skan      ASM_OUTPUT_LABEL (file, name);
1975117404Skan      break;
1976117404Skan
1977117404Skan    case LABEL_NORMAL:
1978117404Skan    default:
1979117404Skan      abort ();
1980117404Skan    }
1981117404Skan}
1982117404Skan
198318334Speter/* The final scan for one insn, INSN.
198418334Speter   Args are same as in `final', except that INSN
198518334Speter   is the insn being scanned.
198618334Speter   Value returned is the next insn to be scanned.
198718334Speter
198818334Speter   NOPEEPHOLES is the flag to disallow peephole processing (currently
198918334Speter   used for within delayed branch sequence output).  */
199018334Speter
199118334Speterrtx
199218334Speterfinal_scan_insn (insn, file, optimize, prescan, nopeepholes)
199318334Speter     rtx insn;
199418334Speter     FILE *file;
199590087Sobrien     int optimize ATTRIBUTE_UNUSED;
199618334Speter     int prescan;
199790087Sobrien     int nopeepholes ATTRIBUTE_UNUSED;
199818334Speter{
199950503Sobrien#ifdef HAVE_cc0
200050503Sobrien  rtx set;
200150503Sobrien#endif
200250503Sobrien
200318334Speter  insn_counter++;
200418334Speter
200518334Speter  /* Ignore deleted insns.  These can occur when we split insns (due to a
200618334Speter     template of "#") while not optimizing.  */
200718334Speter  if (INSN_DELETED_P (insn))
200818334Speter    return NEXT_INSN (insn);
200918334Speter
201018334Speter  switch (GET_CODE (insn))
201118334Speter    {
201218334Speter    case NOTE:
201318334Speter      if (prescan > 0)
201418334Speter	break;
201518334Speter
201690087Sobrien      switch (NOTE_LINE_NUMBER (insn))
201718334Speter	{
201890087Sobrien	case NOTE_INSN_DELETED:
201990087Sobrien	case NOTE_INSN_LOOP_BEG:
202090087Sobrien	case NOTE_INSN_LOOP_END:
202196281Sobrien	case NOTE_INSN_LOOP_END_TOP_COND:
202290087Sobrien	case NOTE_INSN_LOOP_CONT:
202390087Sobrien	case NOTE_INSN_LOOP_VTOP:
202490087Sobrien	case NOTE_INSN_FUNCTION_END:
202590087Sobrien	case NOTE_INSN_REPEATED_LINE_NUMBER:
202690087Sobrien	case NOTE_INSN_EXPECTED_VALUE:
202718334Speter	  break;
202818334Speter
202990087Sobrien	case NOTE_INSN_BASIC_BLOCK:
203090087Sobrien#ifdef IA64_UNWIND_INFO
203190087Sobrien	  IA64_UNWIND_EMIT (asm_out_file, insn);
203250503Sobrien#endif
203390087Sobrien	  if (flag_debug_asm)
203490087Sobrien	    fprintf (asm_out_file, "\t%s basic block %d\n",
203590087Sobrien		     ASM_COMMENT_START, NOTE_BASIC_BLOCK (insn)->index);
203650503Sobrien	  break;
203750503Sobrien
203890087Sobrien	case NOTE_INSN_EH_REGION_BEG:
203990087Sobrien	  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHB",
204090087Sobrien				  NOTE_EH_HANDLER (insn));
204190087Sobrien	  break;
204290087Sobrien
204390087Sobrien	case NOTE_INSN_EH_REGION_END:
204490087Sobrien	  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHE",
204590087Sobrien				  NOTE_EH_HANDLER (insn));
204690087Sobrien	  break;
204790087Sobrien
204890087Sobrien	case NOTE_INSN_PROLOGUE_END:
204990087Sobrien	  (*targetm.asm_out.function_end_prologue) (file);
205018334Speter	  profile_after_prologue (file);
205118334Speter	  break;
205218334Speter
205390087Sobrien	case NOTE_INSN_EPILOGUE_BEG:
205490087Sobrien	  (*targetm.asm_out.function_begin_epilogue) (file);
205518334Speter	  break;
205618334Speter
205790087Sobrien	case NOTE_INSN_FUNCTION_BEG:
205890087Sobrien	  app_disable ();
2059117404Skan	  (*debug_hooks->end_prologue) (last_linenum, last_filename);
206018334Speter	  break;
206190087Sobrien
206290087Sobrien	case NOTE_INSN_BLOCK_BEG:
206390087Sobrien	  if (debug_info_level == DINFO_LEVEL_NORMAL
206418334Speter	      || debug_info_level == DINFO_LEVEL_VERBOSE
206518334Speter	      || write_symbols == DWARF_DEBUG
206690087Sobrien	      || write_symbols == DWARF2_DEBUG
206790087Sobrien	      || write_symbols == VMS_AND_DWARF2_DEBUG
206890087Sobrien	      || write_symbols == VMS_DEBUG)
206990087Sobrien	    {
207090087Sobrien	      int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
207118334Speter
207290087Sobrien	      app_disable ();
207390087Sobrien	      ++block_depth;
207490087Sobrien	      high_block_linenum = last_linenum;
207590087Sobrien
207690087Sobrien	      /* Output debugging info about the symbol-block beginning.  */
207790087Sobrien	      (*debug_hooks->begin_block) (last_linenum, n);
207890087Sobrien
207990087Sobrien	      /* Mark this block as output.  */
208090087Sobrien	      TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
208118334Speter	    }
208290087Sobrien	  break;
208318334Speter
208490087Sobrien	case NOTE_INSN_BLOCK_END:
208590087Sobrien	  if (debug_info_level == DINFO_LEVEL_NORMAL
208690087Sobrien	      || debug_info_level == DINFO_LEVEL_VERBOSE
208790087Sobrien	      || write_symbols == DWARF_DEBUG
208890087Sobrien	      || write_symbols == DWARF2_DEBUG
208990087Sobrien	      || write_symbols == VMS_AND_DWARF2_DEBUG
209090087Sobrien	      || write_symbols == VMS_DEBUG)
209190087Sobrien	    {
209290087Sobrien	      int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
209318334Speter
209490087Sobrien	      app_disable ();
209518334Speter
209690087Sobrien	      /* End of a symbol-block.  */
209790087Sobrien	      --block_depth;
209890087Sobrien	      if (block_depth < 0)
209990087Sobrien		abort ();
210018334Speter
210190087Sobrien	      (*debug_hooks->end_block) (high_block_linenum, n);
210290087Sobrien	    }
210390087Sobrien	  break;
210418334Speter
210590087Sobrien	case NOTE_INSN_DELETED_LABEL:
210690087Sobrien	  /* Emit the label.  We may have deleted the CODE_LABEL because
210790087Sobrien	     the label could be proved to be unreachable, though still
210890087Sobrien	     referenced (in the form of having its address taken.  */
210990087Sobrien	  ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
211090087Sobrien	  break;
211118334Speter
211290087Sobrien	case 0:
211390087Sobrien	  break;
211418334Speter
211590087Sobrien	default:
211690087Sobrien	  if (NOTE_LINE_NUMBER (insn) <= 0)
211790087Sobrien	    abort ();
211818334Speter
211990087Sobrien	  /* This note is a line-number.  */
212090087Sobrien	  {
212190087Sobrien	    rtx note;
212290087Sobrien	    int note_after = 0;
212318334Speter
212490087Sobrien	    /* If there is anything real after this note, output it.
212590087Sobrien	       If another line note follows, omit this one.  */
212690087Sobrien	    for (note = NEXT_INSN (insn); note; note = NEXT_INSN (note))
212790087Sobrien	      {
212890087Sobrien		if (GET_CODE (note) != NOTE && GET_CODE (note) != CODE_LABEL)
212918334Speter		  break;
213018334Speter
213190087Sobrien		/* These types of notes can be significant
213290087Sobrien		   so make sure the preceding line number stays.  */
213390087Sobrien		else if (GET_CODE (note) == NOTE
213490087Sobrien			 && (NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_BEG
213590087Sobrien			     || NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_END
213690087Sobrien			     || NOTE_LINE_NUMBER (note) == NOTE_INSN_FUNCTION_BEG))
213790087Sobrien		  break;
213890087Sobrien		else if (GET_CODE (note) == NOTE && NOTE_LINE_NUMBER (note) > 0)
213990087Sobrien		  {
214090087Sobrien		    /* Another line note follows; we can delete this note
214190087Sobrien		       if no intervening line numbers have notes elsewhere.  */
214290087Sobrien		    int num;
214390087Sobrien		    for (num = NOTE_LINE_NUMBER (insn) + 1;
214490087Sobrien		         num < NOTE_LINE_NUMBER (note);
214590087Sobrien		         num++)
214690087Sobrien		      if (line_note_exists[num])
214790087Sobrien			break;
214890087Sobrien
214990087Sobrien		    if (num >= NOTE_LINE_NUMBER (note))
215090087Sobrien		      note_after = 1;
215190087Sobrien		    break;
215290087Sobrien		  }
215390087Sobrien	      }
215490087Sobrien
215590087Sobrien	    /* Output this line note if it is the first or the last line
215690087Sobrien	       note in a row.  */
215790087Sobrien	    if (!note_after)
215890087Sobrien	      {
215990087Sobrien		notice_source_line (insn);
216090087Sobrien		(*debug_hooks->source_line) (last_linenum, last_filename);
216190087Sobrien	      }
216290087Sobrien	  }
216390087Sobrien	  break;
216418334Speter	}
216518334Speter      break;
216618334Speter
216718334Speter    case BARRIER:
216890087Sobrien#if defined (DWARF2_UNWIND_INFO)
216990087Sobrien      if (dwarf2out_do_frame ())
217090087Sobrien	dwarf2out_frame_debug (insn);
217118334Speter#endif
217218334Speter      break;
217318334Speter
217418334Speter    case CODE_LABEL:
217550503Sobrien      /* The target port might emit labels in the output function for
217650503Sobrien	 some insn, e.g. sh.c output_branchy_insn.  */
217750503Sobrien      if (CODE_LABEL_NUMBER (insn) <= max_labelno)
217850503Sobrien	{
217950503Sobrien	  int align = LABEL_TO_ALIGNMENT (insn);
218050503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
218150503Sobrien	  int max_skip = LABEL_TO_MAX_SKIP (insn);
218250503Sobrien#endif
218350503Sobrien
218450503Sobrien	  if (align && NEXT_INSN (insn))
218590087Sobrien	    {
218650503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
218790087Sobrien	      ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip);
218850503Sobrien#else
2189117404Skan#ifdef ASM_OUTPUT_ALIGN_WITH_NOP
2190117404Skan              ASM_OUTPUT_ALIGN_WITH_NOP (file, align);
2191117404Skan#else
219290087Sobrien	      ASM_OUTPUT_ALIGN (file, align);
219350503Sobrien#endif
2194117404Skan#endif
219590087Sobrien	    }
219650503Sobrien	}
219752515Sobrien#ifdef HAVE_cc0
219818334Speter      CC_STATUS_INIT;
219952515Sobrien      /* If this label is reached from only one place, set the condition
220052515Sobrien	 codes from the instruction just before the branch.  */
220152515Sobrien
220252515Sobrien      /* Disabled because some insns set cc_status in the C output code
220352515Sobrien	 and NOTICE_UPDATE_CC alone can set incorrect status.  */
220452515Sobrien      if (0 /* optimize && LABEL_NUSES (insn) == 1*/)
220552515Sobrien	{
220652515Sobrien	  rtx jump = LABEL_REFS (insn);
220752515Sobrien	  rtx barrier = prev_nonnote_insn (insn);
220852515Sobrien	  rtx prev;
220952515Sobrien	  /* If the LABEL_REFS field of this label has been set to point
221052515Sobrien	     at a branch, the predecessor of the branch is a regular
221152515Sobrien	     insn, and that branch is the only way to reach this label,
221252515Sobrien	     set the condition codes based on the branch and its
221352515Sobrien	     predecessor.  */
221452515Sobrien	  if (barrier && GET_CODE (barrier) == BARRIER
221552515Sobrien	      && jump && GET_CODE (jump) == JUMP_INSN
221652515Sobrien	      && (prev = prev_nonnote_insn (jump))
221752515Sobrien	      && GET_CODE (prev) == INSN)
221852515Sobrien	    {
221952515Sobrien	      NOTICE_UPDATE_CC (PATTERN (prev), prev);
222052515Sobrien	      NOTICE_UPDATE_CC (PATTERN (jump), jump);
222152515Sobrien	    }
222252515Sobrien	}
222352515Sobrien#endif
222418334Speter      if (prescan > 0)
222518334Speter	break;
222618334Speter      new_block = 1;
222750503Sobrien
222850503Sobrien#ifdef FINAL_PRESCAN_LABEL
222990087Sobrien      FINAL_PRESCAN_INSN (insn, NULL, 0);
223050503Sobrien#endif
223150503Sobrien
223290087Sobrien      if (LABEL_NAME (insn))
223390087Sobrien	(*debug_hooks->label) (insn);
223490087Sobrien
223518334Speter      if (app_on)
223618334Speter	{
223750503Sobrien	  fputs (ASM_APP_OFF, file);
223818334Speter	  app_on = 0;
223918334Speter	}
224018334Speter      if (NEXT_INSN (insn) != 0
224118334Speter	  && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN)
224218334Speter	{
224318334Speter	  rtx nextbody = PATTERN (NEXT_INSN (insn));
224418334Speter
224518334Speter	  /* If this label is followed by a jump-table,
224618334Speter	     make sure we put the label in the read-only section.  Also
224718334Speter	     possibly write the label and jump table together.  */
224818334Speter
224918334Speter	  if (GET_CODE (nextbody) == ADDR_VEC
225018334Speter	      || GET_CODE (nextbody) == ADDR_DIFF_VEC)
225118334Speter	    {
225252515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
225352515Sobrien	      /* In this case, the case vector is being moved by the
225452515Sobrien		 target, so don't output the label at all.  Leave that
225552515Sobrien		 to the back end macros.  */
225652515Sobrien#else
225750503Sobrien	      if (! JUMP_TABLES_IN_TEXT_SECTION)
225850503Sobrien		{
225990087Sobrien		  int log_align;
226090087Sobrien
226150503Sobrien		  readonly_data_section ();
226290087Sobrien
226390087Sobrien#ifdef ADDR_VEC_ALIGN
226490087Sobrien		  log_align = ADDR_VEC_ALIGN (NEXT_INSN (insn));
226590087Sobrien#else
226690087Sobrien		  log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
226790087Sobrien#endif
226890087Sobrien		  ASM_OUTPUT_ALIGN (file, log_align);
226950503Sobrien		}
227050503Sobrien	      else
227150503Sobrien		function_section (current_function_decl);
227250503Sobrien
227318334Speter#ifdef ASM_OUTPUT_CASE_LABEL
227418334Speter	      ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
227518334Speter				     NEXT_INSN (insn));
227618334Speter#else
2277117404Skan	      ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
227818334Speter#endif
227952515Sobrien#endif
228018334Speter	      break;
228118334Speter	    }
228218334Speter	}
2283117404Skan      if (LABEL_ALT_ENTRY_P (insn))
2284117404Skan	output_alternate_entry_point (file, insn);
228590087Sobrien      else
228690087Sobrien	ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
228718334Speter      break;
228818334Speter
228918334Speter    default:
229018334Speter      {
229190087Sobrien	rtx body = PATTERN (insn);
229218334Speter	int insn_code_number;
229352515Sobrien	const char *template;
229418334Speter	rtx note;
229518334Speter
229618334Speter	/* An INSN, JUMP_INSN or CALL_INSN.
229718334Speter	   First check for special kinds that recog doesn't recognize.  */
229818334Speter
229918334Speter	if (GET_CODE (body) == USE /* These are just declarations */
230018334Speter	    || GET_CODE (body) == CLOBBER)
230118334Speter	  break;
230218334Speter
230318334Speter#ifdef HAVE_cc0
230418334Speter	/* If there is a REG_CC_SETTER note on this insn, it means that
230518334Speter	   the setting of the condition code was done in the delay slot
230618334Speter	   of the insn that branched here.  So recover the cc status
230718334Speter	   from the insn that set it.  */
230818334Speter
230918334Speter	note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
231018334Speter	if (note)
231118334Speter	  {
231218334Speter	    NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0));
231318334Speter	    cc_prev_status = cc_status;
231418334Speter	  }
231518334Speter#endif
231618334Speter
231718334Speter	/* Detect insns that are really jump-tables
231818334Speter	   and output them as such.  */
231918334Speter
232018334Speter	if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
232118334Speter	  {
232252515Sobrien#if !(defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC))
232390087Sobrien	    int vlen, idx;
232452515Sobrien#endif
232518334Speter
232618334Speter	    if (prescan > 0)
232718334Speter	      break;
232818334Speter
232918334Speter	    if (app_on)
233018334Speter	      {
233150503Sobrien		fputs (ASM_APP_OFF, file);
233218334Speter		app_on = 0;
233318334Speter	      }
233418334Speter
233552515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
233652515Sobrien	    if (GET_CODE (body) == ADDR_VEC)
233752515Sobrien	      {
233852515Sobrien#ifdef ASM_OUTPUT_ADDR_VEC
233952515Sobrien		ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body);
234052515Sobrien#else
234190087Sobrien		abort ();
234252515Sobrien#endif
234352515Sobrien	      }
234452515Sobrien	    else
234552515Sobrien	      {
234652515Sobrien#ifdef ASM_OUTPUT_ADDR_DIFF_VEC
234752515Sobrien		ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body);
234852515Sobrien#else
234990087Sobrien		abort ();
235052515Sobrien#endif
235152515Sobrien	      }
235252515Sobrien#else
235318334Speter	    vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC);
235418334Speter	    for (idx = 0; idx < vlen; idx++)
235518334Speter	      {
235618334Speter		if (GET_CODE (body) == ADDR_VEC)
235718334Speter		  {
235818334Speter#ifdef ASM_OUTPUT_ADDR_VEC_ELT
235918334Speter		    ASM_OUTPUT_ADDR_VEC_ELT
236018334Speter		      (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
236118334Speter#else
236218334Speter		    abort ();
236318334Speter#endif
236418334Speter		  }
236518334Speter		else
236618334Speter		  {
236718334Speter#ifdef ASM_OUTPUT_ADDR_DIFF_ELT
236818334Speter		    ASM_OUTPUT_ADDR_DIFF_ELT
236918334Speter		      (file,
237050503Sobrien		       body,
237118334Speter		       CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
237218334Speter		       CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
237318334Speter#else
237418334Speter		    abort ();
237518334Speter#endif
237618334Speter		  }
237718334Speter	      }
237818334Speter#ifdef ASM_OUTPUT_CASE_END
237918334Speter	    ASM_OUTPUT_CASE_END (file,
238018334Speter				 CODE_LABEL_NUMBER (PREV_INSN (insn)),
238118334Speter				 insn);
238218334Speter#endif
238352515Sobrien#endif
238418334Speter
238518334Speter	    function_section (current_function_decl);
238618334Speter
238718334Speter	    break;
238818334Speter	  }
238918334Speter
239018334Speter	if (GET_CODE (body) == ASM_INPUT)
239118334Speter	  {
239290087Sobrien	    const char *string = XSTR (body, 0);
239390087Sobrien
239418334Speter	    /* There's no telling what that did to the condition codes.  */
239518334Speter	    CC_STATUS_INIT;
239618334Speter	    if (prescan > 0)
239718334Speter	      break;
239890087Sobrien
239990087Sobrien	    if (string[0])
240018334Speter	      {
240190087Sobrien		if (! app_on)
240290087Sobrien		  {
240390087Sobrien		    fputs (ASM_APP_ON, file);
240490087Sobrien		    app_on = 1;
240590087Sobrien		  }
240690087Sobrien		fprintf (asm_out_file, "\t%s\n", string);
240718334Speter	      }
240818334Speter	    break;
240918334Speter	  }
241018334Speter
241118334Speter	/* Detect `asm' construct with operands.  */
241218334Speter	if (asm_noperands (body) >= 0)
241318334Speter	  {
241450503Sobrien	    unsigned int noperands = asm_noperands (body);
241518334Speter	    rtx *ops = (rtx *) alloca (noperands * sizeof (rtx));
241690087Sobrien	    const char *string;
241718334Speter
241818334Speter	    /* There's no telling what that did to the condition codes.  */
241918334Speter	    CC_STATUS_INIT;
242018334Speter	    if (prescan > 0)
242118334Speter	      break;
242218334Speter
242318334Speter	    /* Get out the operand values.  */
242490087Sobrien	    string = decode_asm_operands (body, ops, NULL, NULL, NULL);
242518334Speter	    /* Inhibit aborts on what would otherwise be compiler bugs.  */
242618334Speter	    insn_noperands = noperands;
242718334Speter	    this_is_asm_operands = insn;
242818334Speter
242918334Speter	    /* Output the insn using them.  */
243090087Sobrien	    if (string[0])
243190087Sobrien	      {
243290087Sobrien		if (! app_on)
243390087Sobrien		  {
243490087Sobrien		    fputs (ASM_APP_ON, file);
243590087Sobrien		    app_on = 1;
243690087Sobrien		  }
243790087Sobrien	        output_asm_insn (string, ops);
243890087Sobrien	      }
243990087Sobrien
244018334Speter	    this_is_asm_operands = 0;
244118334Speter	    break;
244218334Speter	  }
244318334Speter
244418334Speter	if (prescan <= 0 && app_on)
244518334Speter	  {
244650503Sobrien	    fputs (ASM_APP_OFF, file);
244718334Speter	    app_on = 0;
244818334Speter	  }
244918334Speter
245018334Speter	if (GET_CODE (body) == SEQUENCE)
245118334Speter	  {
245218334Speter	    /* A delayed-branch sequence */
245390087Sobrien	    int i;
245418334Speter	    rtx next;
245518334Speter
245618334Speter	    if (prescan > 0)
245718334Speter	      break;
245818334Speter	    final_sequence = body;
245918334Speter
246018334Speter	    /* The first insn in this SEQUENCE might be a JUMP_INSN that will
246118334Speter	       force the restoration of a comparison that was previously
246218334Speter	       thought unnecessary.  If that happens, cancel this sequence
246318334Speter	       and cause that insn to be restored.  */
246418334Speter
246518334Speter	    next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1);
246618334Speter	    if (next != XVECEXP (body, 0, 1))
246718334Speter	      {
246818334Speter		final_sequence = 0;
246918334Speter		return next;
247018334Speter	      }
247118334Speter
247218334Speter	    for (i = 1; i < XVECLEN (body, 0); i++)
247318334Speter	      {
247418334Speter		rtx insn = XVECEXP (body, 0, i);
247518334Speter		rtx next = NEXT_INSN (insn);
247618334Speter		/* We loop in case any instruction in a delay slot gets
247718334Speter		   split.  */
247818334Speter		do
247918334Speter		  insn = final_scan_insn (insn, file, 0, prescan, 1);
248018334Speter		while (insn != next);
248118334Speter	      }
248218334Speter#ifdef DBR_OUTPUT_SEQEND
248318334Speter	    DBR_OUTPUT_SEQEND (file);
248418334Speter#endif
248518334Speter	    final_sequence = 0;
248618334Speter
248718334Speter	    /* If the insn requiring the delay slot was a CALL_INSN, the
248818334Speter	       insns in the delay slot are actually executed before the
248918334Speter	       called function.  Hence we don't preserve any CC-setting
249018334Speter	       actions in these insns and the CC must be marked as being
249118334Speter	       clobbered by the function.  */
249218334Speter	    if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN)
249350503Sobrien	      {
249450503Sobrien		CC_STATUS_INIT;
249550503Sobrien	      }
249618334Speter	    break;
249718334Speter	  }
249818334Speter
249918334Speter	/* We have a real machine instruction as rtl.  */
250018334Speter
250118334Speter	body = PATTERN (insn);
250218334Speter
250318334Speter#ifdef HAVE_cc0
250490087Sobrien	set = single_set (insn);
250550503Sobrien
250618334Speter	/* Check for redundant test and compare instructions
250718334Speter	   (when the condition codes are already set up as desired).
250818334Speter	   This is done only when optimizing; if not optimizing,
250918334Speter	   it should be possible for the user to alter a variable
251018334Speter	   with the debugger in between statements
251118334Speter	   and the next statement should reexamine the variable
251218334Speter	   to compute the condition codes.  */
251318334Speter
251450503Sobrien	if (optimize)
251518334Speter	  {
251650503Sobrien#if 0
251790087Sobrien	    rtx set = single_set (insn);
251850503Sobrien#endif
251950503Sobrien
252050503Sobrien	    if (set
252150503Sobrien		&& GET_CODE (SET_DEST (set)) == CC0
252250503Sobrien		&& insn != last_ignored_compare)
252318334Speter	      {
252450503Sobrien		if (GET_CODE (SET_SRC (set)) == SUBREG)
252590087Sobrien		  SET_SRC (set) = alter_subreg (&SET_SRC (set));
252650503Sobrien		else if (GET_CODE (SET_SRC (set)) == COMPARE)
252718334Speter		  {
252850503Sobrien		    if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
252950503Sobrien		      XEXP (SET_SRC (set), 0)
253090087Sobrien			= alter_subreg (&XEXP (SET_SRC (set), 0));
253150503Sobrien		    if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG)
253250503Sobrien		      XEXP (SET_SRC (set), 1)
253390087Sobrien			= alter_subreg (&XEXP (SET_SRC (set), 1));
253418334Speter		  }
253550503Sobrien		if ((cc_status.value1 != 0
253650503Sobrien		     && rtx_equal_p (SET_SRC (set), cc_status.value1))
253750503Sobrien		    || (cc_status.value2 != 0
253850503Sobrien			&& rtx_equal_p (SET_SRC (set), cc_status.value2)))
253950503Sobrien		  {
254050503Sobrien		    /* Don't delete insn if it has an addressing side-effect.  */
254190087Sobrien		    if (! FIND_REG_INC_NOTE (insn, NULL_RTX)
254250503Sobrien			/* or if anything in it is volatile.  */
254350503Sobrien			&& ! volatile_refs_p (PATTERN (insn)))
254450503Sobrien		      {
254550503Sobrien			/* We don't really delete the insn; just ignore it.  */
254650503Sobrien			last_ignored_compare = insn;
254750503Sobrien			break;
254850503Sobrien		      }
254950503Sobrien		  }
255018334Speter	      }
255118334Speter	  }
255218334Speter#endif
255318334Speter
255418334Speter#ifndef STACK_REGS
255518334Speter	/* Don't bother outputting obvious no-ops, even without -O.
255618334Speter	   This optimization is fast and doesn't interfere with debugging.
255718334Speter	   Don't do this if the insn is in a delay slot, since this
255818334Speter	   will cause an improper number of delay insns to be written.  */
255918334Speter	if (final_sequence == 0
256018334Speter	    && prescan >= 0
256118334Speter	    && GET_CODE (insn) == INSN && GET_CODE (body) == SET
256218334Speter	    && GET_CODE (SET_SRC (body)) == REG
256318334Speter	    && GET_CODE (SET_DEST (body)) == REG
256418334Speter	    && REGNO (SET_SRC (body)) == REGNO (SET_DEST (body)))
256518334Speter	  break;
256618334Speter#endif
256718334Speter
256818334Speter#ifdef HAVE_cc0
256918334Speter	/* If this is a conditional branch, maybe modify it
257018334Speter	   if the cc's are in a nonstandard state
257118334Speter	   so that it accomplishes the same thing that it would
257218334Speter	   do straightforwardly if the cc's were set up normally.  */
257318334Speter
257418334Speter	if (cc_status.flags != 0
257518334Speter	    && GET_CODE (insn) == JUMP_INSN
257618334Speter	    && GET_CODE (body) == SET
257718334Speter	    && SET_DEST (body) == pc_rtx
257818334Speter	    && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
257918334Speter	    && GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (body), 0))) == '<'
258018334Speter	    && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx
258118334Speter	    /* This is done during prescan; it is not done again
258218334Speter	       in final scan when prescan has been done.  */
258318334Speter	    && prescan >= 0)
258418334Speter	  {
258518334Speter	    /* This function may alter the contents of its argument
258618334Speter	       and clear some of the cc_status.flags bits.
258718334Speter	       It may also return 1 meaning condition now always true
258818334Speter	       or -1 meaning condition now always false
258918334Speter	       or 2 meaning condition nontrivial but altered.  */
259090087Sobrien	    int result = alter_cond (XEXP (SET_SRC (body), 0));
259118334Speter	    /* If condition now has fixed value, replace the IF_THEN_ELSE
259218334Speter	       with its then-operand or its else-operand.  */
259318334Speter	    if (result == 1)
259418334Speter	      SET_SRC (body) = XEXP (SET_SRC (body), 1);
259518334Speter	    if (result == -1)
259618334Speter	      SET_SRC (body) = XEXP (SET_SRC (body), 2);
259718334Speter
259818334Speter	    /* The jump is now either unconditional or a no-op.
259918334Speter	       If it has become a no-op, don't try to output it.
260018334Speter	       (It would not be recognized.)  */
260118334Speter	    if (SET_SRC (body) == pc_rtx)
260218334Speter	      {
260390087Sobrien	        delete_insn (insn);
260418334Speter		break;
260518334Speter	      }
260618334Speter	    else if (GET_CODE (SET_SRC (body)) == RETURN)
260718334Speter	      /* Replace (set (pc) (return)) with (return).  */
260818334Speter	      PATTERN (insn) = body = SET_SRC (body);
260918334Speter
261018334Speter	    /* Rerecognize the instruction if it has changed.  */
261118334Speter	    if (result != 0)
261218334Speter	      INSN_CODE (insn) = -1;
261318334Speter	  }
261418334Speter
261518334Speter	/* Make same adjustments to instructions that examine the
261650503Sobrien	   condition codes without jumping and instructions that
261750503Sobrien	   handle conditional moves (if this machine has either one).  */
261818334Speter
261918334Speter	if (cc_status.flags != 0
262050503Sobrien	    && set != 0)
262118334Speter	  {
262250503Sobrien	    rtx cond_rtx, then_rtx, else_rtx;
262390087Sobrien
262450503Sobrien	    if (GET_CODE (insn) != JUMP_INSN
262550503Sobrien		&& GET_CODE (SET_SRC (set)) == IF_THEN_ELSE)
262618334Speter	      {
262750503Sobrien		cond_rtx = XEXP (SET_SRC (set), 0);
262850503Sobrien		then_rtx = XEXP (SET_SRC (set), 1);
262950503Sobrien		else_rtx = XEXP (SET_SRC (set), 2);
263050503Sobrien	      }
263150503Sobrien	    else
263250503Sobrien	      {
263350503Sobrien		cond_rtx = SET_SRC (set);
263450503Sobrien		then_rtx = const_true_rtx;
263550503Sobrien		else_rtx = const0_rtx;
263650503Sobrien	      }
263790087Sobrien
263850503Sobrien	    switch (GET_CODE (cond_rtx))
263950503Sobrien	      {
264018334Speter	      case GTU:
264118334Speter	      case GT:
264218334Speter	      case LTU:
264318334Speter	      case LT:
264418334Speter	      case GEU:
264518334Speter	      case GE:
264618334Speter	      case LEU:
264718334Speter	      case LE:
264818334Speter	      case EQ:
264918334Speter	      case NE:
265018334Speter		{
265190087Sobrien		  int result;
265250503Sobrien		  if (XEXP (cond_rtx, 0) != cc0_rtx)
265318334Speter		    break;
265450503Sobrien		  result = alter_cond (cond_rtx);
265518334Speter		  if (result == 1)
265650503Sobrien		    validate_change (insn, &SET_SRC (set), then_rtx, 0);
265718334Speter		  else if (result == -1)
265850503Sobrien		    validate_change (insn, &SET_SRC (set), else_rtx, 0);
265918334Speter		  else if (result == 2)
266018334Speter		    INSN_CODE (insn) = -1;
266150503Sobrien		  if (SET_DEST (set) == SET_SRC (set))
266290087Sobrien		    delete_insn (insn);
266318334Speter		}
266450503Sobrien		break;
266550503Sobrien
266650503Sobrien	      default:
266750503Sobrien		break;
266818334Speter	      }
266918334Speter	  }
267050503Sobrien
267118334Speter#endif
267218334Speter
267390087Sobrien#ifdef HAVE_peephole
267418334Speter	/* Do machine-specific peephole optimizations if desired.  */
267518334Speter
267618334Speter	if (optimize && !flag_no_peephole && !nopeepholes)
267718334Speter	  {
267818334Speter	    rtx next = peephole (insn);
267918334Speter	    /* When peepholing, if there were notes within the peephole,
268018334Speter	       emit them before the peephole.  */
268118334Speter	    if (next != 0 && next != NEXT_INSN (insn))
268218334Speter	      {
268318334Speter		rtx prev = PREV_INSN (insn);
268418334Speter
268518334Speter		for (note = NEXT_INSN (insn); note != next;
268618334Speter		     note = NEXT_INSN (note))
268718334Speter		  final_scan_insn (note, file, optimize, prescan, nopeepholes);
268818334Speter
268918334Speter		/* In case this is prescan, put the notes
269018334Speter		   in proper position for later rescan.  */
269118334Speter		note = NEXT_INSN (insn);
269218334Speter		PREV_INSN (note) = prev;
269318334Speter		NEXT_INSN (prev) = note;
269418334Speter		NEXT_INSN (PREV_INSN (next)) = insn;
269518334Speter		PREV_INSN (insn) = PREV_INSN (next);
269618334Speter		NEXT_INSN (insn) = next;
269718334Speter		PREV_INSN (next) = insn;
269818334Speter	      }
269918334Speter
270018334Speter	    /* PEEPHOLE might have changed this.  */
270118334Speter	    body = PATTERN (insn);
270218334Speter	  }
270390087Sobrien#endif
270418334Speter
270518334Speter	/* Try to recognize the instruction.
270618334Speter	   If successful, verify that the operands satisfy the
270718334Speter	   constraints for the instruction.  Crash if they don't,
270818334Speter	   since `reload' should have changed them so that they do.  */
270918334Speter
271018334Speter	insn_code_number = recog_memoized (insn);
271152515Sobrien	cleanup_subreg_operands (insn);
271218334Speter
2713117404Skan	/* Dump the insn in the assembly for debugging.  */
2714117404Skan	if (flag_dump_rtl_in_asm)
2715117404Skan	  {
2716117404Skan	    print_rtx_head = ASM_COMMENT_START;
2717117404Skan	    print_rtl_single (asm_out_file, insn);
2718117404Skan	    print_rtx_head = "";
2719117404Skan	  }
272090087Sobrien
272190087Sobrien	if (! constrain_operands_cached (1))
272218334Speter	  fatal_insn_not_found (insn);
272318334Speter
272418334Speter	/* Some target machines need to prescan each insn before
272518334Speter	   it is output.  */
272618334Speter
272718334Speter#ifdef FINAL_PRESCAN_INSN
272890087Sobrien	FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands);
272918334Speter#endif
273018334Speter
273190087Sobrien#ifdef HAVE_conditional_execution
273290087Sobrien	if (GET_CODE (PATTERN (insn)) == COND_EXEC)
273390087Sobrien	  current_insn_predicate = COND_EXEC_TEST (PATTERN (insn));
273490087Sobrien	else
273590087Sobrien	  current_insn_predicate = NULL_RTX;
273690087Sobrien#endif
273790087Sobrien
273818334Speter#ifdef HAVE_cc0
273918334Speter	cc_prev_status = cc_status;
274018334Speter
274118334Speter	/* Update `cc_status' for this instruction.
274218334Speter	   The instruction's output routine may change it further.
274318334Speter	   If the output routine for a jump insn needs to depend
274418334Speter	   on the cc status, it should look at cc_prev_status.  */
274518334Speter
274618334Speter	NOTICE_UPDATE_CC (body, insn);
274718334Speter#endif
274818334Speter
274990087Sobrien	current_output_insn = debug_insn = insn;
275018334Speter
275190087Sobrien#if defined (DWARF2_UNWIND_INFO)
275250503Sobrien	if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ())
275350503Sobrien	  dwarf2out_frame_debug (insn);
275450503Sobrien#endif
275550503Sobrien
275690087Sobrien	/* Find the proper template for this insn.  */
275790087Sobrien	template = get_insn_template (insn_code_number, insn);
275818334Speter
275990087Sobrien	/* If the C code returns 0, it means that it is a jump insn
276090087Sobrien	   which follows a deleted test insn, and that test insn
276190087Sobrien	   needs to be reinserted.  */
276218334Speter	if (template == 0)
276318334Speter	  {
276490087Sobrien	    rtx prev;
276518334Speter
276690087Sobrien	    if (prev_nonnote_insn (insn) != last_ignored_compare)
276790087Sobrien	      abort ();
276890087Sobrien	    new_block = 0;
276990087Sobrien
277090087Sobrien	    /* We have already processed the notes between the setter and
277190087Sobrien	       the user.  Make sure we don't process them again, this is
277290087Sobrien	       particularly important if one of the notes is a block
277390087Sobrien	       scope note or an EH note.  */
277490087Sobrien	    for (prev = insn;
277590087Sobrien		 prev != last_ignored_compare;
277690087Sobrien		 prev = PREV_INSN (prev))
277718334Speter	      {
277890087Sobrien		if (GET_CODE (prev) == NOTE)
277990087Sobrien		  delete_insn (prev);	/* Use delete_note.  */
278018334Speter	      }
278190087Sobrien
278290087Sobrien	    return prev;
278318334Speter	  }
278418334Speter
278518334Speter	/* If the template is the string "#", it means that this insn must
278618334Speter	   be split.  */
278718334Speter	if (template[0] == '#' && template[1] == '\0')
278818334Speter	  {
278918334Speter	    rtx new = try_split (body, insn, 0);
279018334Speter
279118334Speter	    /* If we didn't split the insn, go away.  */
279218334Speter	    if (new == insn && PATTERN (new) == body)
279390087Sobrien	      fatal_insn ("could not split insn", insn);
279490087Sobrien
279550503Sobrien#ifdef HAVE_ATTR_length
279650503Sobrien	    /* This instruction should have been split in shorten_branches,
279750503Sobrien	       to ensure that we would have valid length info for the
279850503Sobrien	       splitees.  */
279950503Sobrien	    abort ();
280050503Sobrien#endif
280150503Sobrien
280218334Speter	    new_block = 0;
280318334Speter	    return new;
280418334Speter	  }
280590087Sobrien
280618334Speter	if (prescan > 0)
280718334Speter	  break;
280818334Speter
280990087Sobrien#ifdef IA64_UNWIND_INFO
281090087Sobrien	IA64_UNWIND_EMIT (asm_out_file, insn);
281190087Sobrien#endif
281218334Speter	/* Output assembler code from the template.  */
281318334Speter
281490087Sobrien	output_asm_insn (template, recog_data.operand);
281518334Speter
281650503Sobrien#if defined (DWARF2_UNWIND_INFO)
281790087Sobrien#if defined (HAVE_prologue)
281850503Sobrien	if (GET_CODE (insn) == INSN && dwarf2out_do_frame ())
281950503Sobrien	  dwarf2out_frame_debug (insn);
282050503Sobrien#else
282190087Sobrien	if (!ACCUMULATE_OUTGOING_ARGS
282290087Sobrien	    && GET_CODE (insn) == INSN
282390087Sobrien	    && dwarf2out_do_frame ())
282450503Sobrien	  dwarf2out_frame_debug (insn);
282550503Sobrien#endif
282650503Sobrien#endif
282750503Sobrien
282818334Speter#if 0
282918334Speter	/* It's not at all clear why we did this and doing so interferes
283018334Speter	   with tests we'd like to do to use REG_WAS_0 notes, so let's try
283118334Speter	   with this out.  */
283218334Speter
283318334Speter	/* Mark this insn as having been output.  */
283418334Speter	INSN_DELETED_P (insn) = 1;
283518334Speter#endif
283618334Speter
283790087Sobrien	/* Emit information for vtable gc.  */
283890087Sobrien	note = find_reg_note (insn, REG_VTABLE_REF, NULL_RTX);
283990087Sobrien	if (note)
284090087Sobrien	  assemble_vtable_entry (XEXP (XEXP (note, 0), 0),
284190087Sobrien				 INTVAL (XEXP (XEXP (note, 0), 1)));
284290087Sobrien
284390087Sobrien	current_output_insn = debug_insn = 0;
284418334Speter      }
284518334Speter    }
284618334Speter  return NEXT_INSN (insn);
284718334Speter}
284818334Speter
284918334Speter/* Output debugging info to the assembler file FILE
285018334Speter   based on the NOTE-insn INSN, assumed to be a line number.  */
285118334Speter
285218334Speterstatic void
285390087Sobriennotice_source_line (insn)
285418334Speter     rtx insn;
285518334Speter{
285690087Sobrien  const char *filename = NOTE_SOURCE_FILE (insn);
285718334Speter
285818334Speter  last_filename = filename;
285918334Speter  last_linenum = NOTE_LINE_NUMBER (insn);
286018334Speter  high_block_linenum = MAX (last_linenum, high_block_linenum);
286118334Speter  high_function_linenum = MAX (last_linenum, high_function_linenum);
286218334Speter}
286318334Speter
286452515Sobrien/* For each operand in INSN, simplify (subreg (reg)) so that it refers
286552515Sobrien   directly to the desired hard register.  */
286690087Sobrien
286752515Sobrienvoid
286852515Sobriencleanup_subreg_operands (insn)
286952515Sobrien     rtx insn;
287052515Sobrien{
287152515Sobrien  int i;
287290087Sobrien  extract_insn_cached (insn);
287390087Sobrien  for (i = 0; i < recog_data.n_operands; i++)
287452515Sobrien    {
287590087Sobrien      /* The following test cannot use recog_data.operand when tesing
287690087Sobrien	 for a SUBREG: the underlying object might have been changed
287790087Sobrien	 already if we are inside a match_operator expression that
287890087Sobrien	 matches the else clause.  Instead we test the underlying
287990087Sobrien	 expression directly.  */
288090087Sobrien      if (GET_CODE (*recog_data.operand_loc[i]) == SUBREG)
288190087Sobrien	recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]);
288290087Sobrien      else if (GET_CODE (recog_data.operand[i]) == PLUS
288390087Sobrien	       || GET_CODE (recog_data.operand[i]) == MULT
288490087Sobrien	       || GET_CODE (recog_data.operand[i]) == MEM)
288590087Sobrien	recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i]);
288652515Sobrien    }
288752515Sobrien
288890087Sobrien  for (i = 0; i < recog_data.n_dups; i++)
288952515Sobrien    {
289090087Sobrien      if (GET_CODE (*recog_data.dup_loc[i]) == SUBREG)
289190087Sobrien	*recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]);
289290087Sobrien      else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS
289390087Sobrien	       || GET_CODE (*recog_data.dup_loc[i]) == MULT
289490087Sobrien	       || GET_CODE (*recog_data.dup_loc[i]) == MEM)
289590087Sobrien	*recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]);
289652515Sobrien    }
289752515Sobrien}
289852515Sobrien
289918334Speter/* If X is a SUBREG, replace it with a REG or a MEM,
290018334Speter   based on the thing it is a subreg of.  */
290118334Speter
290218334Speterrtx
290390087Sobrienalter_subreg (xp)
290490087Sobrien     rtx *xp;
290518334Speter{
290690087Sobrien  rtx x = *xp;
290790087Sobrien  rtx y = SUBREG_REG (x);
290850503Sobrien
290990087Sobrien  /* simplify_subreg does not remove subreg from volatile references.
291090087Sobrien     We are required to.  */
291190087Sobrien  if (GET_CODE (y) == MEM)
291290087Sobrien    *xp = adjust_address (y, GET_MODE (x), SUBREG_BYTE (x));
291390087Sobrien  else
291418334Speter    {
291590087Sobrien      rtx new = simplify_subreg (GET_MODE (x), y, GET_MODE (y),
291690087Sobrien				 SUBREG_BYTE (x));
291750503Sobrien
291890087Sobrien      if (new != 0)
291990087Sobrien	*xp = new;
292090087Sobrien      /* Simplify_subreg can't handle some REG cases, but we have to.  */
292190087Sobrien      else if (GET_CODE (y) == REG)
292290087Sobrien	{
292390087Sobrien	  unsigned int regno = subreg_hard_regno (x, 1);
292490087Sobrien	  PUT_CODE (x, REG);
292590087Sobrien	  REGNO (x) = regno;
292690087Sobrien	  ORIGINAL_REGNO (x) = ORIGINAL_REGNO (y);
292790087Sobrien	  /* This field has a different meaning for REGs and SUBREGs.  Make
292890087Sobrien	     sure to clear it!  */
2929117404Skan	  RTX_FLAG (x, used) = 0;
293090087Sobrien	}
293190087Sobrien      else
293290087Sobrien	abort ();
293318334Speter    }
293418334Speter
293590087Sobrien  return *xp;
293618334Speter}
293718334Speter
293818334Speter/* Do alter_subreg on all the SUBREGs contained in X.  */
293918334Speter
294018334Speterstatic rtx
294190087Sobrienwalk_alter_subreg (xp)
294290087Sobrien     rtx *xp;
294318334Speter{
294490087Sobrien  rtx x = *xp;
294518334Speter  switch (GET_CODE (x))
294618334Speter    {
294718334Speter    case PLUS:
294818334Speter    case MULT:
294990087Sobrien      XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
295090087Sobrien      XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1));
295118334Speter      break;
295218334Speter
295318334Speter    case MEM:
295490087Sobrien      XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
295518334Speter      break;
295618334Speter
295718334Speter    case SUBREG:
295890087Sobrien      return alter_subreg (xp);
295990087Sobrien
296050503Sobrien    default:
296150503Sobrien      break;
296218334Speter    }
296318334Speter
296490087Sobrien  return *xp;
296518334Speter}
296618334Speter
296718334Speter#ifdef HAVE_cc0
296818334Speter
296918334Speter/* Given BODY, the body of a jump instruction, alter the jump condition
297018334Speter   as required by the bits that are set in cc_status.flags.
297118334Speter   Not all of the bits there can be handled at this level in all cases.
297218334Speter
297318334Speter   The value is normally 0.
297418334Speter   1 means that the condition has become always true.
297518334Speter   -1 means that the condition has become always false.
297618334Speter   2 means that COND has been altered.  */
297718334Speter
297818334Speterstatic int
297918334Speteralter_cond (cond)
298090087Sobrien     rtx cond;
298118334Speter{
298218334Speter  int value = 0;
298318334Speter
298418334Speter  if (cc_status.flags & CC_REVERSED)
298518334Speter    {
298618334Speter      value = 2;
298718334Speter      PUT_CODE (cond, swap_condition (GET_CODE (cond)));
298818334Speter    }
298918334Speter
299018334Speter  if (cc_status.flags & CC_INVERTED)
299118334Speter    {
299218334Speter      value = 2;
299318334Speter      PUT_CODE (cond, reverse_condition (GET_CODE (cond)));
299418334Speter    }
299518334Speter
299618334Speter  if (cc_status.flags & CC_NOT_POSITIVE)
299718334Speter    switch (GET_CODE (cond))
299818334Speter      {
299918334Speter      case LE:
300018334Speter      case LEU:
300118334Speter      case GEU:
300218334Speter	/* Jump becomes unconditional.  */
300318334Speter	return 1;
300418334Speter
300518334Speter      case GT:
300618334Speter      case GTU:
300718334Speter      case LTU:
300818334Speter	/* Jump becomes no-op.  */
300918334Speter	return -1;
301018334Speter
301118334Speter      case GE:
301218334Speter	PUT_CODE (cond, EQ);
301318334Speter	value = 2;
301418334Speter	break;
301518334Speter
301618334Speter      case LT:
301718334Speter	PUT_CODE (cond, NE);
301818334Speter	value = 2;
301918334Speter	break;
302090087Sobrien
302150503Sobrien      default:
302250503Sobrien	break;
302318334Speter      }
302418334Speter
302518334Speter  if (cc_status.flags & CC_NOT_NEGATIVE)
302618334Speter    switch (GET_CODE (cond))
302718334Speter      {
302818334Speter      case GE:
302918334Speter      case GEU:
303018334Speter	/* Jump becomes unconditional.  */
303118334Speter	return 1;
303218334Speter
303318334Speter      case LT:
303418334Speter      case LTU:
303518334Speter	/* Jump becomes no-op.  */
303618334Speter	return -1;
303718334Speter
303818334Speter      case LE:
303918334Speter      case LEU:
304018334Speter	PUT_CODE (cond, EQ);
304118334Speter	value = 2;
304218334Speter	break;
304318334Speter
304418334Speter      case GT:
304518334Speter      case GTU:
304618334Speter	PUT_CODE (cond, NE);
304718334Speter	value = 2;
304818334Speter	break;
304990087Sobrien
305050503Sobrien      default:
305150503Sobrien	break;
305218334Speter      }
305318334Speter
305418334Speter  if (cc_status.flags & CC_NO_OVERFLOW)
305518334Speter    switch (GET_CODE (cond))
305618334Speter      {
305718334Speter      case GEU:
305818334Speter	/* Jump becomes unconditional.  */
305918334Speter	return 1;
306018334Speter
306118334Speter      case LEU:
306218334Speter	PUT_CODE (cond, EQ);
306318334Speter	value = 2;
306418334Speter	break;
306518334Speter
306618334Speter      case GTU:
306718334Speter	PUT_CODE (cond, NE);
306818334Speter	value = 2;
306918334Speter	break;
307018334Speter
307118334Speter      case LTU:
307218334Speter	/* Jump becomes no-op.  */
307318334Speter	return -1;
307490087Sobrien
307550503Sobrien      default:
307650503Sobrien	break;
307718334Speter      }
307818334Speter
307918334Speter  if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N))
308018334Speter    switch (GET_CODE (cond))
308118334Speter      {
308250503Sobrien      default:
308318334Speter	abort ();
308418334Speter
308518334Speter      case NE:
308618334Speter	PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT);
308718334Speter	value = 2;
308818334Speter	break;
308918334Speter
309018334Speter      case EQ:
309118334Speter	PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE);
309218334Speter	value = 2;
309318334Speter	break;
309418334Speter      }
309518334Speter
309618334Speter  if (cc_status.flags & CC_NOT_SIGNED)
309718334Speter    /* The flags are valid if signed condition operators are converted
309818334Speter       to unsigned.  */
309918334Speter    switch (GET_CODE (cond))
310018334Speter      {
310118334Speter      case LE:
310218334Speter	PUT_CODE (cond, LEU);
310318334Speter	value = 2;
310418334Speter	break;
310518334Speter
310618334Speter      case LT:
310718334Speter	PUT_CODE (cond, LTU);
310818334Speter	value = 2;
310918334Speter	break;
311018334Speter
311118334Speter      case GT:
311218334Speter	PUT_CODE (cond, GTU);
311318334Speter	value = 2;
311418334Speter	break;
311518334Speter
311618334Speter      case GE:
311718334Speter	PUT_CODE (cond, GEU);
311818334Speter	value = 2;
311918334Speter	break;
312050503Sobrien
312150503Sobrien      default:
312250503Sobrien	break;
312318334Speter      }
312418334Speter
312518334Speter  return value;
312618334Speter}
312718334Speter#endif
312818334Speter
312918334Speter/* Report inconsistency between the assembler template and the operands.
313018334Speter   In an `asm', it's the user's fault; otherwise, the compiler's fault.  */
313118334Speter
313218334Spetervoid
313396281Sobrienoutput_operand_lossage VPARAMS ((const char *msgid, ...))
313418334Speter{
313596281Sobrien  char *fmt_string;
313696281Sobrien  char *new_message;
313796281Sobrien  const char *pfx_str;
313896281Sobrien  VA_OPEN (ap, msgid);
313996281Sobrien  VA_FIXEDARG (ap, const char *, msgid);
314096281Sobrien
314196281Sobrien  pfx_str = this_is_asm_operands ? _("invalid `asm': ") : "output_operand: ";
314296281Sobrien  asprintf (&fmt_string, "%s%s", pfx_str, _(msgid));
314396281Sobrien  vasprintf (&new_message, fmt_string, ap);
3144117404Skan
314518334Speter  if (this_is_asm_operands)
314696281Sobrien    error_for_asm (this_is_asm_operands, "%s", new_message);
314718334Speter  else
314896281Sobrien    internal_error ("%s", new_message);
314996281Sobrien
315096281Sobrien  free (fmt_string);
315196281Sobrien  free (new_message);
315296281Sobrien  VA_CLOSE (ap);
315318334Speter}
315418334Speter
315518334Speter/* Output of assembler code from a template, and its subroutines.  */
315618334Speter
315790087Sobrien/* Annotate the assembly with a comment describing the pattern and
315890087Sobrien   alternative used.  */
315990087Sobrien
316090087Sobrienstatic void
316190087Sobrienoutput_asm_name ()
316290087Sobrien{
316390087Sobrien  if (debug_insn)
316490087Sobrien    {
316590087Sobrien      int num = INSN_CODE (debug_insn);
316690087Sobrien      fprintf (asm_out_file, "\t%s %d\t%s",
316790087Sobrien	       ASM_COMMENT_START, INSN_UID (debug_insn),
316890087Sobrien	       insn_data[num].name);
316990087Sobrien      if (insn_data[num].n_alternatives > 1)
317090087Sobrien	fprintf (asm_out_file, "/%d", which_alternative + 1);
317190087Sobrien#ifdef HAVE_ATTR_length
317290087Sobrien      fprintf (asm_out_file, "\t[length = %d]",
317390087Sobrien	       get_attr_length (debug_insn));
317490087Sobrien#endif
317590087Sobrien      /* Clear this so only the first assembler insn
317690087Sobrien	 of any rtl insn will get the special comment for -dp.  */
317790087Sobrien      debug_insn = 0;
317890087Sobrien    }
317990087Sobrien}
318090087Sobrien
318190087Sobrien/* If OP is a REG or MEM and we can find a MEM_EXPR corresponding to it
318290087Sobrien   or its address, return that expr .  Set *PADDRESSP to 1 if the expr
318390087Sobrien   corresponds to the address of the object and 0 if to the object.  */
318490087Sobrien
318590087Sobrienstatic tree
318690087Sobrienget_mem_expr_from_op (op, paddressp)
318790087Sobrien     rtx op;
318890087Sobrien     int *paddressp;
318990087Sobrien{
319090087Sobrien  tree expr;
319190087Sobrien  int inner_addressp;
319290087Sobrien
319390087Sobrien  *paddressp = 0;
319490087Sobrien
3195102798Skan  if (op == NULL)
3196102798Skan    return 0;
3197102798Skan
319890087Sobrien  if (GET_CODE (op) == REG && ORIGINAL_REGNO (op) >= FIRST_PSEUDO_REGISTER)
319990087Sobrien    return REGNO_DECL (ORIGINAL_REGNO (op));
320090087Sobrien  else if (GET_CODE (op) != MEM)
320190087Sobrien    return 0;
320290087Sobrien
320390087Sobrien  if (MEM_EXPR (op) != 0)
320490087Sobrien    return MEM_EXPR (op);
320590087Sobrien
320690087Sobrien  /* Otherwise we have an address, so indicate it and look at the address.  */
320790087Sobrien  *paddressp = 1;
320890087Sobrien  op = XEXP (op, 0);
320990087Sobrien
321090087Sobrien  /* First check if we have a decl for the address, then look at the right side
321190087Sobrien     if it is a PLUS.  Otherwise, strip off arithmetic and keep looking.
321290087Sobrien     But don't allow the address to itself be indirect.  */
321390087Sobrien  if ((expr = get_mem_expr_from_op (op, &inner_addressp)) && ! inner_addressp)
321490087Sobrien    return expr;
321590087Sobrien  else if (GET_CODE (op) == PLUS
321690087Sobrien	   && (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp)))
321790087Sobrien    return expr;
321890087Sobrien
321990087Sobrien  while (GET_RTX_CLASS (GET_CODE (op)) == '1'
322090087Sobrien	 || GET_RTX_CLASS (GET_CODE (op)) == '2')
322190087Sobrien    op = XEXP (op, 0);
322290087Sobrien
322390087Sobrien  expr = get_mem_expr_from_op (op, &inner_addressp);
322490087Sobrien  return inner_addressp ? 0 : expr;
322590087Sobrien}
322690087Sobrien
322790087Sobrien/* Output operand names for assembler instructions.  OPERANDS is the
322890087Sobrien   operand vector, OPORDER is the order to write the operands, and NOPS
322990087Sobrien   is the number of operands to write.  */
323090087Sobrien
323190087Sobrienstatic void
323290087Sobrienoutput_asm_operand_names (operands, oporder, nops)
323390087Sobrien     rtx *operands;
323490087Sobrien     int *oporder;
323590087Sobrien     int nops;
323690087Sobrien{
323790087Sobrien  int wrote = 0;
323890087Sobrien  int i;
323990087Sobrien
324090087Sobrien  for (i = 0; i < nops; i++)
324190087Sobrien    {
324290087Sobrien      int addressp;
324390087Sobrien      tree expr = get_mem_expr_from_op (operands[oporder[i]], &addressp);
324490087Sobrien
324590087Sobrien      if (expr)
324690087Sobrien	{
324790087Sobrien	  fprintf (asm_out_file, "%c%s %s",
324890087Sobrien		   wrote ? ',' : '\t', wrote ? "" : ASM_COMMENT_START,
324990087Sobrien		   addressp ? "*" : "");
325090087Sobrien	  print_mem_expr (asm_out_file, expr);
325190087Sobrien	  wrote = 1;
325290087Sobrien	}
325390087Sobrien    }
325490087Sobrien}
325590087Sobrien
325618334Speter/* Output text from TEMPLATE to the assembler output file,
325718334Speter   obeying %-directions to substitute operands taken from
325818334Speter   the vector OPERANDS.
325918334Speter
326018334Speter   %N (for N a digit) means print operand N in usual manner.
326118334Speter   %lN means require operand N to be a CODE_LABEL or LABEL_REF
326218334Speter      and print the label name with no punctuation.
326318334Speter   %cN means require operand N to be a constant
326418334Speter      and print the constant expression with no punctuation.
326518334Speter   %aN means expect operand N to be a memory address
326618334Speter      (not a memory reference!) and print a reference
326718334Speter      to that address.
326818334Speter   %nN means expect operand N to be a constant
326918334Speter      and print a constant expression for minus the value
327018334Speter      of the operand, with no other punctuation.  */
327118334Speter
327218334Spetervoid
327318334Speteroutput_asm_insn (template, operands)
327452515Sobrien     const char *template;
327518334Speter     rtx *operands;
327618334Speter{
327790087Sobrien  const char *p;
327890087Sobrien  int c;
327990087Sobrien#ifdef ASSEMBLER_DIALECT
328090087Sobrien  int dialect = 0;
328190087Sobrien#endif
328290087Sobrien  int oporder[MAX_RECOG_OPERANDS];
328390087Sobrien  char opoutput[MAX_RECOG_OPERANDS];
328490087Sobrien  int ops = 0;
328518334Speter
328618334Speter  /* An insn may return a null string template
328718334Speter     in a case where no assembler code is needed.  */
328818334Speter  if (*template == 0)
328918334Speter    return;
329018334Speter
329190087Sobrien  memset (opoutput, 0, sizeof opoutput);
329218334Speter  p = template;
329318334Speter  putc ('\t', asm_out_file);
329418334Speter
329518334Speter#ifdef ASM_OUTPUT_OPCODE
329618334Speter  ASM_OUTPUT_OPCODE (asm_out_file, p);
329718334Speter#endif
329818334Speter
329950503Sobrien  while ((c = *p++))
330018334Speter    switch (c)
330118334Speter      {
330218334Speter      case '\n':
330390087Sobrien	if (flag_verbose_asm)
330490087Sobrien	  output_asm_operand_names (operands, oporder, ops);
330590087Sobrien	if (flag_print_asm_name)
330690087Sobrien	  output_asm_name ();
330790087Sobrien
330890087Sobrien	ops = 0;
330990087Sobrien	memset (opoutput, 0, sizeof opoutput);
331090087Sobrien
331118334Speter	putc (c, asm_out_file);
331218334Speter#ifdef ASM_OUTPUT_OPCODE
331318334Speter	while ((c = *p) == '\t')
331418334Speter	  {
331518334Speter	    putc (c, asm_out_file);
331618334Speter	    p++;
331718334Speter	  }
331818334Speter	ASM_OUTPUT_OPCODE (asm_out_file, p);
331918334Speter#endif
332018334Speter	break;
332118334Speter
332218334Speter#ifdef ASSEMBLER_DIALECT
332318334Speter      case '{':
332450503Sobrien	{
332590087Sobrien	  int i;
332690087Sobrien
332790087Sobrien	  if (dialect)
332890087Sobrien	    output_operand_lossage ("nested assembly dialect alternatives");
332990087Sobrien	  else
333090087Sobrien	    dialect = 1;
333190087Sobrien
333250503Sobrien	  /* If we want the first dialect, do nothing.  Otherwise, skip
333350503Sobrien	     DIALECT_NUMBER of strings ending with '|'.  */
333450503Sobrien	  for (i = 0; i < dialect_number; i++)
333550503Sobrien	    {
333690087Sobrien	      while (*p && *p != '}' && *p++ != '|')
333750503Sobrien		;
333890087Sobrien	      if (*p == '}')
333990087Sobrien		break;
334050503Sobrien	      if (*p == '|')
334150503Sobrien		p++;
334250503Sobrien	    }
334390087Sobrien
334490087Sobrien	  if (*p == '\0')
334590087Sobrien	    output_operand_lossage ("unterminated assembly dialect alternative");
334650503Sobrien	}
334718334Speter	break;
334818334Speter
334918334Speter      case '|':
335090087Sobrien	if (dialect)
335190087Sobrien	  {
335290087Sobrien	    /* Skip to close brace.  */
335390087Sobrien	    do
335490087Sobrien	      {
335590087Sobrien		if (*p == '\0')
335690087Sobrien		  {
335790087Sobrien		    output_operand_lossage ("unterminated assembly dialect alternative");
335890087Sobrien		    break;
335990087Sobrien		  }
336090087Sobrien	      }
336190087Sobrien	    while (*p++ != '}');
336290087Sobrien	    dialect = 0;
336390087Sobrien	  }
336490087Sobrien	else
336590087Sobrien	  putc (c, asm_out_file);
336618334Speter	break;
336718334Speter
336818334Speter      case '}':
336990087Sobrien	if (! dialect)
337090087Sobrien	  putc (c, asm_out_file);
337190087Sobrien	dialect = 0;
337218334Speter	break;
337318334Speter#endif
337418334Speter
337518334Speter      case '%':
337618334Speter	/* %% outputs a single %.  */
337718334Speter	if (*p == '%')
337818334Speter	  {
337918334Speter	    p++;
338018334Speter	    putc (c, asm_out_file);
338118334Speter	  }
338218334Speter	/* %= outputs a number which is unique to each insn in the entire
338318334Speter	   compilation.  This is useful for making local labels that are
338418334Speter	   referred to more than once in a given insn.  */
338518334Speter	else if (*p == '=')
338618334Speter	  {
338718334Speter	    p++;
338818334Speter	    fprintf (asm_out_file, "%d", insn_counter);
338918334Speter	  }
339018334Speter	/* % followed by a letter and some digits
339118334Speter	   outputs an operand in a special way depending on the letter.
339218334Speter	   Letters `acln' are implemented directly.
339318334Speter	   Other letters are passed to `output_operand' so that
339418334Speter	   the PRINT_OPERAND macro can define them.  */
339590087Sobrien	else if (ISALPHA (*p))
339618334Speter	  {
339718334Speter	    int letter = *p++;
339818334Speter	    c = atoi (p);
339918334Speter
340090087Sobrien	    if (! ISDIGIT (*p))
340196281Sobrien	      output_operand_lossage ("operand number missing after %%-letter");
340290087Sobrien	    else if (this_is_asm_operands
340390087Sobrien		     && (c < 0 || (unsigned int) c >= insn_noperands))
340418334Speter	      output_operand_lossage ("operand number out of range");
340518334Speter	    else if (letter == 'l')
340618334Speter	      output_asm_label (operands[c]);
340718334Speter	    else if (letter == 'a')
340818334Speter	      output_address (operands[c]);
340918334Speter	    else if (letter == 'c')
341018334Speter	      {
341118334Speter		if (CONSTANT_ADDRESS_P (operands[c]))
341218334Speter		  output_addr_const (asm_out_file, operands[c]);
341318334Speter		else
341418334Speter		  output_operand (operands[c], 'c');
341518334Speter	      }
341618334Speter	    else if (letter == 'n')
341718334Speter	      {
341818334Speter		if (GET_CODE (operands[c]) == CONST_INT)
341950503Sobrien		  fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
342018334Speter			   - INTVAL (operands[c]));
342118334Speter		else
342218334Speter		  {
342318334Speter		    putc ('-', asm_out_file);
342418334Speter		    output_addr_const (asm_out_file, operands[c]);
342518334Speter		  }
342618334Speter	      }
342718334Speter	    else
342818334Speter	      output_operand (operands[c], letter);
342990087Sobrien
343090087Sobrien	    if (!opoutput[c])
343190087Sobrien	      oporder[ops++] = c;
343290087Sobrien	    opoutput[c] = 1;
343390087Sobrien
343490087Sobrien	    while (ISDIGIT (c = *p))
343590087Sobrien	      p++;
343618334Speter	  }
343718334Speter	/* % followed by a digit outputs an operand the default way.  */
343890087Sobrien	else if (ISDIGIT (*p))
343918334Speter	  {
344018334Speter	    c = atoi (p);
344190087Sobrien	    if (this_is_asm_operands
344290087Sobrien		&& (c < 0 || (unsigned int) c >= insn_noperands))
344318334Speter	      output_operand_lossage ("operand number out of range");
344418334Speter	    else
344518334Speter	      output_operand (operands[c], 0);
344690087Sobrien
344790087Sobrien	    if (!opoutput[c])
344890087Sobrien	      oporder[ops++] = c;
344990087Sobrien	    opoutput[c] = 1;
345090087Sobrien
345190087Sobrien	    while (ISDIGIT (c = *p))
345290087Sobrien	      p++;
345318334Speter	  }
345418334Speter	/* % followed by punctuation: output something for that
345518334Speter	   punctuation character alone, with no operand.
345618334Speter	   The PRINT_OPERAND macro decides what is actually done.  */
345718334Speter#ifdef PRINT_OPERAND_PUNCT_VALID_P
345890087Sobrien	else if (PRINT_OPERAND_PUNCT_VALID_P ((unsigned char) *p))
345918334Speter	  output_operand (NULL_RTX, *p++);
346018334Speter#endif
346118334Speter	else
346218334Speter	  output_operand_lossage ("invalid %%-code");
346318334Speter	break;
346418334Speter
346518334Speter      default:
346618334Speter	putc (c, asm_out_file);
346718334Speter      }
346818334Speter
346990087Sobrien  /* Write out the variable names for operands, if we know them.  */
347090087Sobrien  if (flag_verbose_asm)
347190087Sobrien    output_asm_operand_names (operands, oporder, ops);
347290087Sobrien  if (flag_print_asm_name)
347390087Sobrien    output_asm_name ();
347418334Speter
347518334Speter  putc ('\n', asm_out_file);
347618334Speter}
347718334Speter
347818334Speter/* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol.  */
347918334Speter
348018334Spetervoid
348118334Speteroutput_asm_label (x)
348218334Speter     rtx x;
348318334Speter{
348418334Speter  char buf[256];
348518334Speter
348618334Speter  if (GET_CODE (x) == LABEL_REF)
348790087Sobrien    x = XEXP (x, 0);
348890087Sobrien  if (GET_CODE (x) == CODE_LABEL
348990087Sobrien      || (GET_CODE (x) == NOTE
349090087Sobrien	  && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL))
349118334Speter    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
349218334Speter  else
349396281Sobrien    output_operand_lossage ("`%%l' operand isn't a label");
349418334Speter
349518334Speter  assemble_name (asm_out_file, buf);
349618334Speter}
349718334Speter
349818334Speter/* Print operand X using machine-dependent assembler syntax.
349918334Speter   The macro PRINT_OPERAND is defined just to control this function.
350018334Speter   CODE is a non-digit that preceded the operand-number in the % spec,
350118334Speter   such as 'z' if the spec was `%z3'.  CODE is 0 if there was no char
350218334Speter   between the % and the digits.
350318334Speter   When CODE is a non-letter, X is 0.
350418334Speter
350518334Speter   The meanings of the letters are machine-dependent and controlled
350618334Speter   by PRINT_OPERAND.  */
350718334Speter
350818334Speterstatic void
350918334Speteroutput_operand (x, code)
351018334Speter     rtx x;
351190087Sobrien     int code ATTRIBUTE_UNUSED;
351218334Speter{
351318334Speter  if (x && GET_CODE (x) == SUBREG)
351490087Sobrien    x = alter_subreg (&x);
351518334Speter
351618334Speter  /* If X is a pseudo-register, abort now rather than writing trash to the
351718334Speter     assembler file.  */
351818334Speter
351918334Speter  if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
352018334Speter    abort ();
352118334Speter
352218334Speter  PRINT_OPERAND (asm_out_file, x, code);
352318334Speter}
352418334Speter
352518334Speter/* Print a memory reference operand for address X
352618334Speter   using machine-dependent assembler syntax.
352718334Speter   The macro PRINT_OPERAND_ADDRESS exists just to control this function.  */
352818334Speter
352918334Spetervoid
353018334Speteroutput_address (x)
353118334Speter     rtx x;
353218334Speter{
353390087Sobrien  walk_alter_subreg (&x);
353418334Speter  PRINT_OPERAND_ADDRESS (asm_out_file, x);
353518334Speter}
353618334Speter
353718334Speter/* Print an integer constant expression in assembler syntax.
353818334Speter   Addition and subtraction are the only arithmetic
353918334Speter   that may appear in these expressions.  */
354018334Speter
354118334Spetervoid
354218334Speteroutput_addr_const (file, x)
354318334Speter     FILE *file;
354418334Speter     rtx x;
354518334Speter{
354618334Speter  char buf[256];
354718334Speter
354818334Speter restart:
354918334Speter  switch (GET_CODE (x))
355018334Speter    {
355118334Speter    case PC:
355290087Sobrien      putc ('.', file);
355318334Speter      break;
355418334Speter
355518334Speter    case SYMBOL_REF:
355690087Sobrien#ifdef ASM_OUTPUT_SYMBOL_REF
355790087Sobrien      ASM_OUTPUT_SYMBOL_REF (file, x);
355890087Sobrien#else
355918334Speter      assemble_name (file, XSTR (x, 0));
356090087Sobrien#endif
356118334Speter      break;
356218334Speter
356318334Speter    case LABEL_REF:
356490087Sobrien      x = XEXP (x, 0);
356590087Sobrien      /* Fall through.  */
356618334Speter    case CODE_LABEL:
356718334Speter      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
356890087Sobrien#ifdef ASM_OUTPUT_LABEL_REF
356990087Sobrien      ASM_OUTPUT_LABEL_REF (file, buf);
357090087Sobrien#else
357118334Speter      assemble_name (file, buf);
357290087Sobrien#endif
357318334Speter      break;
357418334Speter
357518334Speter    case CONST_INT:
357650503Sobrien      fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
357718334Speter      break;
357818334Speter
357918334Speter    case CONST:
358018334Speter      /* This used to output parentheses around the expression,
358118334Speter	 but that does not work on the 386 (either ATT or BSD assembler).  */
358218334Speter      output_addr_const (file, XEXP (x, 0));
358318334Speter      break;
358418334Speter
358518334Speter    case CONST_DOUBLE:
358618334Speter      if (GET_MODE (x) == VOIDmode)
358718334Speter	{
358818334Speter	  /* We can use %d if the number is one word and positive.  */
358918334Speter	  if (CONST_DOUBLE_HIGH (x))
359050503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
359118334Speter		     CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
359290087Sobrien	  else if (CONST_DOUBLE_LOW (x) < 0)
359350503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
359418334Speter	  else
359550503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
359618334Speter	}
359718334Speter      else
359818334Speter	/* We can't handle floating point constants;
359918334Speter	   PRINT_OPERAND must handle them.  */
360018334Speter	output_operand_lossage ("floating constant misused");
360118334Speter      break;
360218334Speter
360318334Speter    case PLUS:
360418334Speter      /* Some assemblers need integer constants to appear last (eg masm).  */
360518334Speter      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
360618334Speter	{
360718334Speter	  output_addr_const (file, XEXP (x, 1));
360818334Speter	  if (INTVAL (XEXP (x, 0)) >= 0)
360918334Speter	    fprintf (file, "+");
361018334Speter	  output_addr_const (file, XEXP (x, 0));
361118334Speter	}
361218334Speter      else
361318334Speter	{
361418334Speter	  output_addr_const (file, XEXP (x, 0));
361590087Sobrien	  if (GET_CODE (XEXP (x, 1)) != CONST_INT
361690087Sobrien	      || INTVAL (XEXP (x, 1)) >= 0)
361718334Speter	    fprintf (file, "+");
361818334Speter	  output_addr_const (file, XEXP (x, 1));
361918334Speter	}
362018334Speter      break;
362118334Speter
362218334Speter    case MINUS:
362318334Speter      /* Avoid outputting things like x-x or x+5-x,
362418334Speter	 since some assemblers can't handle that.  */
362518334Speter      x = simplify_subtraction (x);
362618334Speter      if (GET_CODE (x) != MINUS)
362718334Speter	goto restart;
362818334Speter
362918334Speter      output_addr_const (file, XEXP (x, 0));
363018334Speter      fprintf (file, "-");
363190087Sobrien      if ((GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0)
363290087Sobrien	  || GET_CODE (XEXP (x, 1)) == PC
363390087Sobrien	  || GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
363490087Sobrien	output_addr_const (file, XEXP (x, 1));
363590087Sobrien      else
363618334Speter	{
363790087Sobrien	  fputs (targetm.asm_out.open_paren, file);
363818334Speter	  output_addr_const (file, XEXP (x, 1));
363990087Sobrien	  fputs (targetm.asm_out.close_paren, file);
364018334Speter	}
364118334Speter      break;
364218334Speter
364318334Speter    case ZERO_EXTEND:
364418334Speter    case SIGN_EXTEND:
364596281Sobrien    case SUBREG:
364618334Speter      output_addr_const (file, XEXP (x, 0));
364718334Speter      break;
364818334Speter
364918334Speter    default:
365090087Sobrien#ifdef OUTPUT_ADDR_CONST_EXTRA
365190087Sobrien      OUTPUT_ADDR_CONST_EXTRA (file, x, fail);
365290087Sobrien      break;
365390087Sobrien
365490087Sobrien    fail:
365590087Sobrien#endif
365618334Speter      output_operand_lossage ("invalid expression as operand");
365718334Speter    }
365818334Speter}
365918334Speter
366018334Speter/* A poor man's fprintf, with the added features of %I, %R, %L, and %U.
366118334Speter   %R prints the value of REGISTER_PREFIX.
366218334Speter   %L prints the value of LOCAL_LABEL_PREFIX.
366318334Speter   %U prints the value of USER_LABEL_PREFIX.
366418334Speter   %I prints the value of IMMEDIATE_PREFIX.
366518334Speter   %O runs ASM_OUTPUT_OPCODE to transform what follows in the string.
366618334Speter   Also supported are %d, %x, %s, %e, %f, %g and %%.
366718334Speter
366818334Speter   We handle alternate assembler dialects here, just like output_asm_insn.  */
366918334Speter
367018334Spetervoid
367190087Sobrienasm_fprintf VPARAMS ((FILE *file, const char *p, ...))
367218334Speter{
367318334Speter  char buf[10];
367418334Speter  char *q, c;
367518334Speter
367690087Sobrien  VA_OPEN (argptr, p);
367790087Sobrien  VA_FIXEDARG (argptr, FILE *, file);
367890087Sobrien  VA_FIXEDARG (argptr, const char *, p);
367918334Speter
368018334Speter  buf[0] = '%';
368118334Speter
368250503Sobrien  while ((c = *p++))
368318334Speter    switch (c)
368418334Speter      {
368518334Speter#ifdef ASSEMBLER_DIALECT
368618334Speter      case '{':
368750503Sobrien	{
368850503Sobrien	  int i;
368918334Speter
369050503Sobrien	  /* If we want the first dialect, do nothing.  Otherwise, skip
369150503Sobrien	     DIALECT_NUMBER of strings ending with '|'.  */
369250503Sobrien	  for (i = 0; i < dialect_number; i++)
369350503Sobrien	    {
369450503Sobrien	      while (*p && *p++ != '|')
369550503Sobrien		;
369650503Sobrien
369750503Sobrien	      if (*p == '|')
369850503Sobrien		p++;
369990087Sobrien	    }
370050503Sobrien	}
370118334Speter	break;
370218334Speter
370318334Speter      case '|':
370418334Speter	/* Skip to close brace.  */
370518334Speter	while (*p && *p++ != '}')
370618334Speter	  ;
370718334Speter	break;
370818334Speter
370918334Speter      case '}':
371018334Speter	break;
371118334Speter#endif
371218334Speter
371318334Speter      case '%':
371418334Speter	c = *p++;
371518334Speter	q = &buf[1];
371690087Sobrien	while (ISDIGIT (c) || c == '.')
371718334Speter	  {
371818334Speter	    *q++ = c;
371918334Speter	    c = *p++;
372018334Speter	  }
372118334Speter	switch (c)
372218334Speter	  {
372318334Speter	  case '%':
372418334Speter	    fprintf (file, "%%");
372518334Speter	    break;
372618334Speter
372718334Speter	  case 'd':  case 'i':  case 'u':
372818334Speter	  case 'x':  case 'p':  case 'X':
372918334Speter	  case 'o':
373018334Speter	    *q++ = c;
373118334Speter	    *q = 0;
373218334Speter	    fprintf (file, buf, va_arg (argptr, int));
373318334Speter	    break;
373418334Speter
373518334Speter	  case 'w':
373618334Speter	    /* This is a prefix to the 'd', 'i', 'u', 'x', 'p', and 'X' cases,
373718334Speter	       but we do not check for those cases.  It means that the value
373818334Speter	       is a HOST_WIDE_INT, which may be either `int' or `long'.  */
373918334Speter
374050503Sobrien#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
374150503Sobrien#else
374250503Sobrien#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
374318334Speter	    *q++ = 'l';
374450503Sobrien#else
374550503Sobrien	    *q++ = 'l';
374650503Sobrien	    *q++ = 'l';
374718334Speter#endif
374850503Sobrien#endif
374918334Speter
375018334Speter	    *q++ = *p++;
375118334Speter	    *q = 0;
375218334Speter	    fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT));
375318334Speter	    break;
375418334Speter
375518334Speter	  case 'l':
375618334Speter	    *q++ = c;
375718334Speter	    *q++ = *p++;
375818334Speter	    *q = 0;
375918334Speter	    fprintf (file, buf, va_arg (argptr, long));
376018334Speter	    break;
376118334Speter
376218334Speter	  case 'e':
376318334Speter	  case 'f':
376418334Speter	  case 'g':
376518334Speter	    *q++ = c;
376618334Speter	    *q = 0;
376718334Speter	    fprintf (file, buf, va_arg (argptr, double));
376818334Speter	    break;
376918334Speter
377018334Speter	  case 's':
377118334Speter	    *q++ = c;
377218334Speter	    *q = 0;
377318334Speter	    fprintf (file, buf, va_arg (argptr, char *));
377418334Speter	    break;
377518334Speter
377618334Speter	  case 'O':
377718334Speter#ifdef ASM_OUTPUT_OPCODE
377818334Speter	    ASM_OUTPUT_OPCODE (asm_out_file, p);
377918334Speter#endif
378018334Speter	    break;
378118334Speter
378218334Speter	  case 'R':
378318334Speter#ifdef REGISTER_PREFIX
378418334Speter	    fprintf (file, "%s", REGISTER_PREFIX);
378518334Speter#endif
378618334Speter	    break;
378718334Speter
378818334Speter	  case 'I':
378918334Speter#ifdef IMMEDIATE_PREFIX
379018334Speter	    fprintf (file, "%s", IMMEDIATE_PREFIX);
379118334Speter#endif
379218334Speter	    break;
379318334Speter
379418334Speter	  case 'L':
379518334Speter#ifdef LOCAL_LABEL_PREFIX
379618334Speter	    fprintf (file, "%s", LOCAL_LABEL_PREFIX);
379718334Speter#endif
379818334Speter	    break;
379918334Speter
380018334Speter	  case 'U':
380152515Sobrien	    fputs (user_label_prefix, file);
380218334Speter	    break;
380318334Speter
380490087Sobrien#ifdef ASM_FPRINTF_EXTENSIONS
380590087Sobrien	    /* Upper case letters are reserved for general use by asm_fprintf
380690087Sobrien	       and so are not available to target specific code.  In order to
380790087Sobrien	       prevent the ASM_FPRINTF_EXTENSIONS macro from using them then,
380890087Sobrien	       they are defined here.  As they get turned into real extensions
380990087Sobrien	       to asm_fprintf they should be removed from this list.  */
381090087Sobrien	  case 'A': case 'B': case 'C': case 'D': case 'E':
381190087Sobrien	  case 'F': case 'G': case 'H': case 'J': case 'K':
381290087Sobrien	  case 'M': case 'N': case 'P': case 'Q': case 'S':
381390087Sobrien	  case 'T': case 'V': case 'W': case 'Y': case 'Z':
381490087Sobrien	    break;
381590087Sobrien
381690087Sobrien	  ASM_FPRINTF_EXTENSIONS (file, argptr, p)
381790087Sobrien#endif
381818334Speter	  default:
381918334Speter	    abort ();
382018334Speter	  }
382118334Speter	break;
382218334Speter
382318334Speter      default:
382418334Speter	fputc (c, file);
382518334Speter      }
382690087Sobrien  VA_CLOSE (argptr);
382718334Speter}
382818334Speter
382918334Speter/* Split up a CONST_DOUBLE or integer constant rtx
383018334Speter   into two rtx's for single words,
383118334Speter   storing in *FIRST the word that comes first in memory in the target
383218334Speter   and in *SECOND the other.  */
383318334Speter
383418334Spetervoid
383518334Spetersplit_double (value, first, second)
383618334Speter     rtx value;
383718334Speter     rtx *first, *second;
383818334Speter{
383918334Speter  if (GET_CODE (value) == CONST_INT)
384018334Speter    {
384118334Speter      if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD))
384218334Speter	{
384318334Speter	  /* In this case the CONST_INT holds both target words.
384450503Sobrien	     Extract the bits from it into two word-sized pieces.
384550503Sobrien	     Sign extend each half to HOST_WIDE_INT.  */
384690087Sobrien	  unsigned HOST_WIDE_INT low, high;
384790087Sobrien	  unsigned HOST_WIDE_INT mask, sign_bit, sign_extend;
384818334Speter
384990087Sobrien	  /* Set sign_bit to the most significant bit of a word.  */
385090087Sobrien	  sign_bit = 1;
385190087Sobrien	  sign_bit <<= BITS_PER_WORD - 1;
385290087Sobrien
385390087Sobrien	  /* Set mask so that all bits of the word are set.  We could
385490087Sobrien	     have used 1 << BITS_PER_WORD instead of basing the
385590087Sobrien	     calculation on sign_bit.  However, on machines where
385690087Sobrien	     HOST_BITS_PER_WIDE_INT == BITS_PER_WORD, it could cause a
385790087Sobrien	     compiler warning, even though the code would never be
385890087Sobrien	     executed.  */
385990087Sobrien	  mask = sign_bit << 1;
386090087Sobrien	  mask--;
386190087Sobrien
386290087Sobrien	  /* Set sign_extend as any remaining bits.  */
386390087Sobrien	  sign_extend = ~mask;
386490087Sobrien
386590087Sobrien	  /* Pick the lower word and sign-extend it.  */
386690087Sobrien	  low = INTVAL (value);
386790087Sobrien	  low &= mask;
386890087Sobrien	  if (low & sign_bit)
386990087Sobrien	    low |= sign_extend;
387090087Sobrien
387190087Sobrien	  /* Pick the higher word, shifted to the least significant
387290087Sobrien	     bits, and sign-extend it.  */
387390087Sobrien	  high = INTVAL (value);
387490087Sobrien	  high >>= BITS_PER_WORD - 1;
387590087Sobrien	  high >>= 1;
387690087Sobrien	  high &= mask;
387790087Sobrien	  if (high & sign_bit)
387890087Sobrien	    high |= sign_extend;
387990087Sobrien
388090087Sobrien	  /* Store the words in the target machine order.  */
388118334Speter	  if (WORDS_BIG_ENDIAN)
388218334Speter	    {
388390087Sobrien	      *first = GEN_INT (high);
388490087Sobrien	      *second = GEN_INT (low);
388518334Speter	    }
388618334Speter	  else
388718334Speter	    {
388890087Sobrien	      *first = GEN_INT (low);
388990087Sobrien	      *second = GEN_INT (high);
389018334Speter	    }
389118334Speter	}
389218334Speter      else
389318334Speter	{
389418334Speter	  /* The rule for using CONST_INT for a wider mode
389518334Speter	     is that we regard the value as signed.
389618334Speter	     So sign-extend it.  */
389718334Speter	  rtx high = (INTVAL (value) < 0 ? constm1_rtx : const0_rtx);
389818334Speter	  if (WORDS_BIG_ENDIAN)
389918334Speter	    {
390018334Speter	      *first = high;
390118334Speter	      *second = value;
390218334Speter	    }
390318334Speter	  else
390418334Speter	    {
390518334Speter	      *first = value;
390618334Speter	      *second = high;
390718334Speter	    }
390818334Speter	}
390918334Speter    }
391018334Speter  else if (GET_CODE (value) != CONST_DOUBLE)
391118334Speter    {
391218334Speter      if (WORDS_BIG_ENDIAN)
391318334Speter	{
391418334Speter	  *first = const0_rtx;
391518334Speter	  *second = value;
391618334Speter	}
391718334Speter      else
391818334Speter	{
391918334Speter	  *first = value;
392018334Speter	  *second = const0_rtx;
392118334Speter	}
392218334Speter    }
392318334Speter  else if (GET_MODE (value) == VOIDmode
392418334Speter	   /* This is the old way we did CONST_DOUBLE integers.  */
392518334Speter	   || GET_MODE_CLASS (GET_MODE (value)) == MODE_INT)
392618334Speter    {
392718334Speter      /* In an integer, the words are defined as most and least significant.
392818334Speter	 So order them by the target's convention.  */
392918334Speter      if (WORDS_BIG_ENDIAN)
393018334Speter	{
393118334Speter	  *first = GEN_INT (CONST_DOUBLE_HIGH (value));
393218334Speter	  *second = GEN_INT (CONST_DOUBLE_LOW (value));
393318334Speter	}
393418334Speter      else
393518334Speter	{
393618334Speter	  *first = GEN_INT (CONST_DOUBLE_LOW (value));
393718334Speter	  *second = GEN_INT (CONST_DOUBLE_HIGH (value));
393818334Speter	}
393918334Speter    }
394018334Speter  else
394118334Speter    {
394290087Sobrien      REAL_VALUE_TYPE r;
394390087Sobrien      long l[2];
394418334Speter      REAL_VALUE_FROM_CONST_DOUBLE (r, value);
394518334Speter
394618334Speter      /* Note, this converts the REAL_VALUE_TYPE to the target's
394718334Speter	 format, splits up the floating point double and outputs
394818334Speter	 exactly 32 bits of it into each of l[0] and l[1] --
394950503Sobrien	 not necessarily BITS_PER_WORD bits.  */
395018334Speter      REAL_VALUE_TO_TARGET_DOUBLE (r, l);
395118334Speter
395252515Sobrien      /* If 32 bits is an entire word for the target, but not for the host,
395352515Sobrien	 then sign-extend on the host so that the number will look the same
395452515Sobrien	 way on the host that it would on the target.  See for instance
395552515Sobrien	 simplify_unary_operation.  The #if is needed to avoid compiler
395652515Sobrien	 warnings.  */
395752515Sobrien
395852515Sobrien#if HOST_BITS_PER_LONG > 32
395952515Sobrien      if (BITS_PER_WORD < HOST_BITS_PER_LONG && BITS_PER_WORD == 32)
396052515Sobrien	{
396152515Sobrien	  if (l[0] & ((long) 1 << 31))
396252515Sobrien	    l[0] |= ((long) (-1) << 32);
396352515Sobrien	  if (l[1] & ((long) 1 << 31))
396452515Sobrien	    l[1] |= ((long) (-1) << 32);
396552515Sobrien	}
396652515Sobrien#endif
396752515Sobrien
396818334Speter      *first = GEN_INT ((HOST_WIDE_INT) l[0]);
396918334Speter      *second = GEN_INT ((HOST_WIDE_INT) l[1]);
397018334Speter    }
397118334Speter}
397218334Speter
397318334Speter/* Return nonzero if this function has no function calls.  */
397418334Speter
397518334Speterint
397618334Speterleaf_function_p ()
397718334Speter{
397818334Speter  rtx insn;
397990087Sobrien  rtx link;
398018334Speter
398190087Sobrien  if (current_function_profile || profile_arc_flag)
398218334Speter    return 0;
398318334Speter
398418334Speter  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
398518334Speter    {
398690087Sobrien      if (GET_CODE (insn) == CALL_INSN
398790087Sobrien	  && ! SIBLING_CALL_P (insn))
398818334Speter	return 0;
398918334Speter      if (GET_CODE (insn) == INSN
399018334Speter	  && GET_CODE (PATTERN (insn)) == SEQUENCE
399190087Sobrien	  && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN
399290087Sobrien	  && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
399318334Speter	return 0;
399418334Speter    }
399590087Sobrien  for (link = current_function_epilogue_delay_list;
399690087Sobrien       link;
399790087Sobrien       link = XEXP (link, 1))
399818334Speter    {
399990087Sobrien      insn = XEXP (link, 0);
400090087Sobrien
400190087Sobrien      if (GET_CODE (insn) == CALL_INSN
400290087Sobrien	  && ! SIBLING_CALL_P (insn))
400318334Speter	return 0;
400490087Sobrien      if (GET_CODE (insn) == INSN
400590087Sobrien	  && GET_CODE (PATTERN (insn)) == SEQUENCE
400690087Sobrien	  && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN
400790087Sobrien	  && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
400818334Speter	return 0;
400918334Speter    }
401018334Speter
401118334Speter  return 1;
401218334Speter}
401318334Speter
4014117404Skan/* Return 1 if branch is a forward branch.
401590087Sobrien   Uses insn_shuid array, so it works only in the final pass.  May be used by
401690087Sobrien   output templates to customary add branch prediction hints.
401790087Sobrien */
401890087Sobrienint
401990087Sobrienfinal_forward_branch_p (insn)
402090087Sobrien     rtx insn;
402190087Sobrien{
402290087Sobrien  int insn_id, label_id;
402390087Sobrien  if (!uid_shuid)
402490087Sobrien    abort ();
402590087Sobrien  insn_id = INSN_SHUID (insn);
402690087Sobrien  label_id = INSN_SHUID (JUMP_LABEL (insn));
402790087Sobrien  /* We've hit some insns that does not have id information available.  */
402890087Sobrien  if (!insn_id || !label_id)
402990087Sobrien    abort ();
403090087Sobrien  return insn_id < label_id;
403190087Sobrien}
403290087Sobrien
403318334Speter/* On some machines, a function with no call insns
403418334Speter   can run faster if it doesn't create its own register window.
403518334Speter   When output, the leaf function should use only the "output"
403618334Speter   registers.  Ordinarily, the function would be compiled to use
403718334Speter   the "input" registers to find its arguments; it is a candidate
403818334Speter   for leaf treatment if it uses only the "input" registers.
403918334Speter   Leaf function treatment means renumbering so the function
404018334Speter   uses the "output" registers instead.  */
404118334Speter
404218334Speter#ifdef LEAF_REGISTERS
404318334Speter
404418334Speter/* Return 1 if this function uses only the registers that can be
404518334Speter   safely renumbered.  */
404618334Speter
404718334Speterint
404818334Speteronly_leaf_regs_used ()
404918334Speter{
405018334Speter  int i;
405190087Sobrien  char *permitted_reg_in_leaf_functions = LEAF_REGISTERS;
405218334Speter
405318334Speter  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
405450503Sobrien    if ((regs_ever_live[i] || global_regs[i])
405550503Sobrien	&& ! permitted_reg_in_leaf_functions[i])
405650503Sobrien      return 0;
405750503Sobrien
405850503Sobrien  if (current_function_uses_pic_offset_table
405950503Sobrien      && pic_offset_table_rtx != 0
406050503Sobrien      && GET_CODE (pic_offset_table_rtx) == REG
406150503Sobrien      && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
406250503Sobrien    return 0;
406350503Sobrien
406418334Speter  return 1;
406518334Speter}
406618334Speter
406718334Speter/* Scan all instructions and renumber all registers into those
406818334Speter   available in leaf functions.  */
406918334Speter
407018334Speterstatic void
407118334Speterleaf_renumber_regs (first)
407218334Speter     rtx first;
407318334Speter{
407418334Speter  rtx insn;
407518334Speter
407618334Speter  /* Renumber only the actual patterns.
407718334Speter     The reg-notes can contain frame pointer refs,
407818334Speter     and renumbering them could crash, and should not be needed.  */
407918334Speter  for (insn = first; insn; insn = NEXT_INSN (insn))
408090087Sobrien    if (INSN_P (insn))
408118334Speter      leaf_renumber_regs_insn (PATTERN (insn));
408290087Sobrien  for (insn = current_function_epilogue_delay_list;
408390087Sobrien       insn;
408490087Sobrien       insn = XEXP (insn, 1))
408590087Sobrien    if (INSN_P (XEXP (insn, 0)))
408618334Speter      leaf_renumber_regs_insn (PATTERN (XEXP (insn, 0)));
408718334Speter}
408818334Speter
408918334Speter/* Scan IN_RTX and its subexpressions, and renumber all regs into those
409018334Speter   available in leaf functions.  */
409118334Speter
409218334Spetervoid
409318334Speterleaf_renumber_regs_insn (in_rtx)
409490087Sobrien     rtx in_rtx;
409518334Speter{
409690087Sobrien  int i, j;
409790087Sobrien  const char *format_ptr;
409818334Speter
409918334Speter  if (in_rtx == 0)
410018334Speter    return;
410118334Speter
410218334Speter  /* Renumber all input-registers into output-registers.
410318334Speter     renumbered_regs would be 1 for an output-register;
410418334Speter     they  */
410518334Speter
410618334Speter  if (GET_CODE (in_rtx) == REG)
410718334Speter    {
410818334Speter      int newreg;
410918334Speter
411018334Speter      /* Don't renumber the same reg twice.  */
411118334Speter      if (in_rtx->used)
411218334Speter	return;
411318334Speter
411418334Speter      newreg = REGNO (in_rtx);
411518334Speter      /* Don't try to renumber pseudo regs.  It is possible for a pseudo reg
411618334Speter	 to reach here as part of a REG_NOTE.  */
411718334Speter      if (newreg >= FIRST_PSEUDO_REGISTER)
411818334Speter	{
411918334Speter	  in_rtx->used = 1;
412018334Speter	  return;
412118334Speter	}
412218334Speter      newreg = LEAF_REG_REMAP (newreg);
412318334Speter      if (newreg < 0)
412418334Speter	abort ();
412518334Speter      regs_ever_live[REGNO (in_rtx)] = 0;
412618334Speter      regs_ever_live[newreg] = 1;
412718334Speter      REGNO (in_rtx) = newreg;
412818334Speter      in_rtx->used = 1;
412918334Speter    }
413018334Speter
413190087Sobrien  if (INSN_P (in_rtx))
413218334Speter    {
413318334Speter      /* Inside a SEQUENCE, we find insns.
413418334Speter	 Renumber just the patterns of these insns,
413518334Speter	 just as we do for the top-level insns.  */
413618334Speter      leaf_renumber_regs_insn (PATTERN (in_rtx));
413718334Speter      return;
413818334Speter    }
413918334Speter
414018334Speter  format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx));
414118334Speter
414218334Speter  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++)
414318334Speter    switch (*format_ptr++)
414418334Speter      {
414518334Speter      case 'e':
414618334Speter	leaf_renumber_regs_insn (XEXP (in_rtx, i));
414718334Speter	break;
414818334Speter
414918334Speter      case 'E':
415018334Speter	if (NULL != XVEC (in_rtx, i))
415118334Speter	  {
415218334Speter	    for (j = 0; j < XVECLEN (in_rtx, i); j++)
415318334Speter	      leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j));
415418334Speter	  }
415518334Speter	break;
415618334Speter
415718334Speter      case 'S':
415818334Speter      case 's':
415918334Speter      case '0':
416018334Speter      case 'i':
416118334Speter      case 'w':
416218334Speter      case 'n':
416318334Speter      case 'u':
416418334Speter	break;
416518334Speter
416618334Speter      default:
416718334Speter	abort ();
416818334Speter      }
416918334Speter}
417018334Speter#endif
4171