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