final.c revision 50503
118334Speter/* Convert RTL to assembler code and output it, for GNU compiler. 250503Sobrien Copyright (C) 1987, 88, 89, 92-97, 1998 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 2118334Speter 2218334Speter/* This is the final pass of the compiler. 2318334Speter It looks at the rtl code for a function and outputs assembler code. 2418334Speter 2518334Speter Call `final_start_function' to output the assembler code for function entry, 2618334Speter `final' to output assembler code for some RTL code, 2718334Speter `final_end_function' to output assembler code for function exit. 2818334Speter If a function is compiled in several pieces, each piece is 2918334Speter output separately with `final'. 3018334Speter 3118334Speter Some optimizations are also done at this level. 3218334Speter Move instructions that were made unnecessary by good register allocation 3318334Speter are detected and omitted from the output. (Though most of these 3418334Speter are removed by the last jump pass.) 3518334Speter 3618334Speter Instructions to set the condition codes are omitted when it can be 3718334Speter seen that the condition codes already had the desired values. 3818334Speter 3918334Speter In some cases it is sufficient if the inherited condition codes 4018334Speter have related values, but this may require the following insn 4118334Speter (the one that tests the condition codes) to be modified. 4218334Speter 4318334Speter The code for the function prologue and epilogue are generated 4418334Speter directly as assembler code by the macros FUNCTION_PROLOGUE and 4518334Speter FUNCTION_EPILOGUE. Those instructions never exist as rtl. */ 4618334Speter 4718334Speter#include "config.h" 4818334Speter#ifdef __STDC__ 4918334Speter#include <stdarg.h> 5018334Speter#else 5118334Speter#include <varargs.h> 5218334Speter#endif 5350503Sobrien#include "system.h" 5418334Speter 5518334Speter#include "tree.h" 5618334Speter#include "rtl.h" 5718334Speter#include "regs.h" 5818334Speter#include "insn-config.h" 5918334Speter#include "insn-flags.h" 6018334Speter#include "insn-attr.h" 6118334Speter#include "insn-codes.h" 6218334Speter#include "recog.h" 6318334Speter#include "conditions.h" 6418334Speter#include "flags.h" 6518334Speter#include "real.h" 6618334Speter#include "hard-reg-set.h" 6718334Speter#include "defaults.h" 6818334Speter#include "output.h" 6950503Sobrien#include "except.h" 7050503Sobrien#include "toplev.h" 7150503Sobrien#include "reload.h" 7218334Speter 7318334Speter/* Get N_SLINE and N_SOL from stab.h if we can expect the file to exist. */ 7418334Speter#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) 7550503Sobrien#include "dbxout.h" 7650503Sobrien#if defined (USG) || !defined (HAVE_STAB_H) 7718334Speter#include "gstab.h" /* If doing DBX on sysV, use our own stab.h. */ 7818334Speter#else 7950503Sobrien#include <stab.h> 8050503Sobrien#endif 8150503Sobrien 8218334Speter#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */ 8318334Speter 8418334Speter#ifdef XCOFF_DEBUGGING_INFO 8518334Speter#include "xcoffout.h" 8618334Speter#endif 8718334Speter 8850503Sobrien#ifdef DWARF_DEBUGGING_INFO 8950503Sobrien#include "dwarfout.h" 9050503Sobrien#endif 9150503Sobrien 9250503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO) 9350503Sobrien#include "dwarf2out.h" 9450503Sobrien#endif 9550503Sobrien 9650503Sobrien#ifdef SDB_DEBUGGING_INFO 9750503Sobrien#include "sdbout.h" 9850503Sobrien#endif 9950503Sobrien 10018334Speter/* .stabd code for line number. */ 10118334Speter#ifndef N_SLINE 10218334Speter#define N_SLINE 0x44 10318334Speter#endif 10418334Speter 10518334Speter/* .stabs code for included file name. */ 10618334Speter#ifndef N_SOL 10718334Speter#define N_SOL 0x84 10818334Speter#endif 10918334Speter 11018334Speter#ifndef INT_TYPE_SIZE 11118334Speter#define INT_TYPE_SIZE BITS_PER_WORD 11218334Speter#endif 11318334Speter 11450503Sobrien#ifndef LONG_TYPE_SIZE 11550503Sobrien#define LONG_TYPE_SIZE BITS_PER_WORD 11650503Sobrien#endif 11750503Sobrien 11818334Speter/* If we aren't using cc0, CC_STATUS_INIT shouldn't exist. So define a 11918334Speter null default for it to save conditionalization later. */ 12018334Speter#ifndef CC_STATUS_INIT 12118334Speter#define CC_STATUS_INIT 12218334Speter#endif 12318334Speter 12418334Speter/* How to start an assembler comment. */ 12518334Speter#ifndef ASM_COMMENT_START 12618334Speter#define ASM_COMMENT_START ";#" 12718334Speter#endif 12818334Speter 12918334Speter/* Is the given character a logical line separator for the assembler? */ 13018334Speter#ifndef IS_ASM_LOGICAL_LINE_SEPARATOR 13118334Speter#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';') 13218334Speter#endif 13318334Speter 13450503Sobrien#ifndef JUMP_TABLES_IN_TEXT_SECTION 13550503Sobrien#define JUMP_TABLES_IN_TEXT_SECTION 0 13650503Sobrien#endif 13750503Sobrien 13818334Speter/* Nonzero means this function is a leaf function, with no function calls. 13918334Speter This variable exists to be examined in FUNCTION_PROLOGUE 14018334Speter and FUNCTION_EPILOGUE. Always zero, unless set by some action. */ 14118334Speterint leaf_function; 14218334Speter 14318334Speter/* Last insn processed by final_scan_insn. */ 14418334Speterstatic rtx debug_insn = 0; 14518334Speter 14618334Speter/* Line number of last NOTE. */ 14718334Speterstatic int last_linenum; 14818334Speter 14918334Speter/* Highest line number in current block. */ 15018334Speterstatic int high_block_linenum; 15118334Speter 15218334Speter/* Likewise for function. */ 15318334Speterstatic int high_function_linenum; 15418334Speter 15518334Speter/* Filename of last NOTE. */ 15618334Speterstatic char *last_filename; 15718334Speter 15818334Speter/* Number of basic blocks seen so far; 15918334Speter used if profile_block_flag is set. */ 16018334Speterstatic int count_basic_blocks; 16118334Speter 16250503Sobrien/* Number of instrumented arcs when profile_arc_flag is set. */ 16350503Sobrienextern int count_instrumented_arcs; 16450503Sobrien 16550503Sobrienextern int length_unit_log; /* This is defined in insn-attrtab.c. */ 16650503Sobrien 16718334Speter/* Nonzero while outputting an `asm' with operands. 16818334Speter This means that inconsistencies are the user's fault, so don't abort. 16918334Speter The precise value is the insn being output, to pass to error_for_asm. */ 17018334Speterstatic rtx this_is_asm_operands; 17118334Speter 17218334Speter/* Number of operands of this insn, for an `asm' with operands. */ 17350503Sobrienstatic unsigned int insn_noperands; 17418334Speter 17518334Speter/* Compare optimization flag. */ 17618334Speter 17718334Speterstatic rtx last_ignored_compare = 0; 17818334Speter 17918334Speter/* Flag indicating this insn is the start of a new basic block. */ 18018334Speter 18118334Speterstatic int new_block = 1; 18218334Speter 18318334Speter/* All the symbol-blocks (levels of scoping) in the compilation 18418334Speter are assigned sequence numbers in order of appearance of the 18518334Speter beginnings of the symbol-blocks. Both final and dbxout do this, 18618334Speter and assume that they will both give the same number to each block. 18718334Speter Final uses these sequence numbers to generate assembler label names 18818334Speter LBBnnn and LBEnnn for the beginning and end of the symbol-block. 18918334Speter Dbxout uses the sequence numbers to generate references to the same labels 19018334Speter from the dbx debugging information. 19118334Speter 19218334Speter Sdb records this level at the beginning of each function, 19318334Speter in order to find the current level when recursing down declarations. 19418334Speter It outputs the block beginning and endings 19518334Speter at the point in the asm file where the blocks would begin and end. */ 19618334Speter 19718334Speterint next_block_index; 19818334Speter 19918334Speter/* Assign a unique number to each insn that is output. 20018334Speter This can be used to generate unique local labels. */ 20118334Speter 20218334Speterstatic int insn_counter = 0; 20318334Speter 20418334Speter#ifdef HAVE_cc0 20518334Speter/* This variable contains machine-dependent flags (defined in tm.h) 20618334Speter set and examined by output routines 20718334Speter that describe how to interpret the condition codes properly. */ 20818334Speter 20918334SpeterCC_STATUS cc_status; 21018334Speter 21118334Speter/* During output of an insn, this contains a copy of cc_status 21218334Speter from before the insn. */ 21318334Speter 21418334SpeterCC_STATUS cc_prev_status; 21518334Speter#endif 21618334Speter 21718334Speter/* Indexed by hardware reg number, is 1 if that register is ever 21818334Speter used in the current function. 21918334Speter 22018334Speter In life_analysis, or in stupid_life_analysis, this is set 22118334Speter up to record the hard regs used explicitly. Reload adds 22218334Speter in the hard regs used for holding pseudo regs. Final uses 22318334Speter it to generate the code in the function prologue and epilogue 22418334Speter to save and restore registers as needed. */ 22518334Speter 22618334Speterchar regs_ever_live[FIRST_PSEUDO_REGISTER]; 22718334Speter 22818334Speter/* Nonzero means current function must be given a frame pointer. 22918334Speter Set in stmt.c if anything is allocated on the stack there. 23018334Speter Set in reload1.c if anything is allocated on the stack there. */ 23118334Speter 23218334Speterint frame_pointer_needed; 23318334Speter 23418334Speter/* Assign unique numbers to labels generated for profiling. */ 23518334Speter 23618334Speterint profile_label_no; 23718334Speter 23818334Speter/* Length so far allocated in PENDING_BLOCKS. */ 23918334Speter 24018334Speterstatic int max_block_depth; 24118334Speter 24218334Speter/* Stack of sequence numbers of symbol-blocks of which we have seen the 24318334Speter beginning but not yet the end. Sequence numbers are assigned at 24418334Speter the beginning; this stack allows us to find the sequence number 24518334Speter of a block that is ending. */ 24618334Speter 24718334Speterstatic int *pending_blocks; 24818334Speter 24918334Speter/* Number of elements currently in use in PENDING_BLOCKS. */ 25018334Speter 25118334Speterstatic int block_depth; 25218334Speter 25318334Speter/* Nonzero if have enabled APP processing of our assembler output. */ 25418334Speter 25518334Speterstatic int app_on; 25618334Speter 25718334Speter/* If we are outputting an insn sequence, this contains the sequence rtx. 25818334Speter Zero otherwise. */ 25918334Speter 26018334Speterrtx final_sequence; 26118334Speter 26218334Speter#ifdef ASSEMBLER_DIALECT 26318334Speter 26418334Speter/* Number of the assembler dialect to use, starting at 0. */ 26518334Speterstatic int dialect_number; 26618334Speter#endif 26718334Speter 26818334Speter/* Indexed by line number, nonzero if there is a note for that line. */ 26918334Speter 27018334Speterstatic char *line_note_exists; 27118334Speter 27218334Speter/* Linked list to hold line numbers for each basic block. */ 27318334Speter 27418334Speterstruct bb_list { 27518334Speter struct bb_list *next; /* pointer to next basic block */ 27618334Speter int line_num; /* line number */ 27718334Speter int file_label_num; /* LPBC<n> label # for stored filename */ 27818334Speter int func_label_num; /* LPBC<n> label # for stored function name */ 27918334Speter}; 28018334Speter 28118334Speterstatic struct bb_list *bb_head = 0; /* Head of basic block list */ 28218334Speterstatic struct bb_list **bb_tail = &bb_head; /* Ptr to store next bb ptr */ 28318334Speterstatic int bb_file_label_num = -1; /* Current label # for file */ 28418334Speterstatic int bb_func_label_num = -1; /* Current label # for func */ 28518334Speter 28618334Speter/* Linked list to hold the strings for each file and function name output. */ 28718334Speter 28818334Speterstruct bb_str { 28918334Speter struct bb_str *next; /* pointer to next string */ 29018334Speter char *string; /* string */ 29118334Speter int label_num; /* label number */ 29218334Speter int length; /* string length */ 29318334Speter}; 29418334Speter 29518334Speterextern rtx peephole PROTO((rtx)); 29618334Speter 29718334Speterstatic struct bb_str *sbb_head = 0; /* Head of string list. */ 29818334Speterstatic struct bb_str **sbb_tail = &sbb_head; /* Ptr to store next bb str */ 29918334Speterstatic int sbb_label_num = 0; /* Last label used */ 30018334Speter 30150503Sobrien#ifdef HAVE_ATTR_length 30218334Speterstatic int asm_insn_count PROTO((rtx)); 30350503Sobrien#endif 30418334Speterstatic void profile_function PROTO((FILE *)); 30518334Speterstatic void profile_after_prologue PROTO((FILE *)); 30618334Speterstatic void add_bb PROTO((FILE *)); 30718334Speterstatic int add_bb_string PROTO((char *, int)); 30818334Speterstatic void output_source_line PROTO((FILE *, rtx)); 30918334Speterstatic rtx walk_alter_subreg PROTO((rtx)); 31018334Speterstatic void output_asm_name PROTO((void)); 31118334Speterstatic void output_operand PROTO((rtx, int)); 31250503Sobrien#ifdef LEAF_REGISTERS 31318334Speterstatic void leaf_renumber_regs PROTO((rtx)); 31450503Sobrien#endif 31550503Sobrien#ifdef HAVE_cc0 31650503Sobrienstatic int alter_cond PROTO((rtx)); 31750503Sobrien#endif 31818334Speter 31918334Speterextern char *getpwd (); 32018334Speter 32118334Speter/* Initialize data in final at the beginning of a compilation. */ 32218334Speter 32318334Spetervoid 32418334Speterinit_final (filename) 32518334Speter char *filename; 32618334Speter{ 32718334Speter next_block_index = 2; 32818334Speter app_on = 0; 32918334Speter max_block_depth = 20; 33018334Speter pending_blocks = (int *) xmalloc (20 * sizeof *pending_blocks); 33118334Speter final_sequence = 0; 33218334Speter 33318334Speter#ifdef ASSEMBLER_DIALECT 33418334Speter dialect_number = ASSEMBLER_DIALECT; 33518334Speter#endif 33618334Speter} 33718334Speter 33818334Speter/* Called at end of source file, 33918334Speter to output the block-profiling table for this entire compilation. */ 34018334Speter 34118334Spetervoid 34218334Speterend_final (filename) 34318334Speter char *filename; 34418334Speter{ 34518334Speter int i; 34618334Speter 34750503Sobrien if (profile_block_flag || profile_arc_flag) 34818334Speter { 34918334Speter char name[20]; 35018334Speter int align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT); 35150503Sobrien int size, rounded; 35218334Speter struct bb_list *ptr; 35318334Speter struct bb_str *sptr; 35450503Sobrien int long_bytes = LONG_TYPE_SIZE / BITS_PER_UNIT; 35550503Sobrien int pointer_bytes = POINTER_SIZE / BITS_PER_UNIT; 35618334Speter 35750503Sobrien if (profile_block_flag) 35850503Sobrien size = long_bytes * count_basic_blocks; 35950503Sobrien else 36050503Sobrien size = long_bytes * count_instrumented_arcs; 36150503Sobrien rounded = size; 36250503Sobrien 36318334Speter rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1; 36418334Speter rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT) 36518334Speter * (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); 36618334Speter 36718334Speter data_section (); 36818334Speter 36950503Sobrien /* Output the main header, of 11 words: 37050503Sobrien 0: 1 if this file is initialized, else 0. 37118334Speter 1: address of file name (LPBX1). 37218334Speter 2: address of table of counts (LPBX2). 37318334Speter 3: number of counts in the table. 37418334Speter 4: always 0, for compatibility with Sun. 37518334Speter 37618334Speter The following are GNU extensions: 37718334Speter 37818334Speter 5: address of table of start addrs of basic blocks (LPBX3). 37918334Speter 6: Number of bytes in this header. 38018334Speter 7: address of table of function names (LPBX4). 38118334Speter 8: address of table of line numbers (LPBX5) or 0. 38250503Sobrien 9: address of table of file names (LPBX6) or 0. 38350503Sobrien 10: space reserved for basic block profiling. */ 38418334Speter 38518334Speter ASM_OUTPUT_ALIGN (asm_out_file, align); 38618334Speter 38718334Speter ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0); 38818334Speter /* zero word */ 38950503Sobrien assemble_integer (const0_rtx, long_bytes, 1); 39018334Speter 39118334Speter /* address of filename */ 39218334Speter ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 1); 39350503Sobrien assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1); 39418334Speter 39518334Speter /* address of count table */ 39618334Speter ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2); 39750503Sobrien assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1); 39818334Speter 39950503Sobrien /* count of the # of basic blocks or # of instrumented arcs */ 40050503Sobrien if (profile_block_flag) 40150503Sobrien assemble_integer (GEN_INT (count_basic_blocks), long_bytes, 1); 40250503Sobrien else 40350503Sobrien assemble_integer (GEN_INT (count_instrumented_arcs), long_bytes, 40450503Sobrien 1); 40518334Speter 40618334Speter /* zero word (link field) */ 40750503Sobrien assemble_integer (const0_rtx, pointer_bytes, 1); 40818334Speter 40918334Speter /* address of basic block start address table */ 41050503Sobrien if (profile_block_flag) 41150503Sobrien { 41250503Sobrien ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3); 41350503Sobrien assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 41450503Sobrien 1); 41550503Sobrien } 41650503Sobrien else 41750503Sobrien assemble_integer (const0_rtx, pointer_bytes, 1); 41818334Speter 41918334Speter /* byte count for extended structure. */ 42050503Sobrien assemble_integer (GEN_INT (10 * UNITS_PER_WORD), long_bytes, 1); 42118334Speter 42218334Speter /* address of function name table */ 42350503Sobrien if (profile_block_flag) 42450503Sobrien { 42550503Sobrien ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 4); 42650503Sobrien assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 42750503Sobrien 1); 42850503Sobrien } 42950503Sobrien else 43050503Sobrien assemble_integer (const0_rtx, pointer_bytes, 1); 43118334Speter 43218334Speter /* address of line number and filename tables if debugging. */ 43350503Sobrien if (write_symbols != NO_DEBUG && profile_block_flag) 43418334Speter { 43518334Speter ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 5); 43650503Sobrien assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1); 43718334Speter ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 6); 43850503Sobrien assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1); 43918334Speter } 44018334Speter else 44118334Speter { 44250503Sobrien assemble_integer (const0_rtx, pointer_bytes, 1); 44350503Sobrien assemble_integer (const0_rtx, pointer_bytes, 1); 44418334Speter } 44518334Speter 44650503Sobrien /* space for extension ptr (link field) */ 44750503Sobrien assemble_integer (const0_rtx, UNITS_PER_WORD, 1); 44850503Sobrien 44918334Speter /* Output the file name changing the suffix to .d for Sun tcov 45018334Speter compatibility. */ 45118334Speter ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1); 45218334Speter { 45318334Speter char *cwd = getpwd (); 45418334Speter int len = strlen (filename) + strlen (cwd) + 1; 45518334Speter char *data_file = (char *) alloca (len + 4); 45618334Speter 45718334Speter strcpy (data_file, cwd); 45818334Speter strcat (data_file, "/"); 45918334Speter strcat (data_file, filename); 46018334Speter strip_off_ending (data_file, len); 46150503Sobrien if (profile_block_flag) 46250503Sobrien strcat (data_file, ".d"); 46350503Sobrien else 46450503Sobrien strcat (data_file, ".da"); 46518334Speter assemble_string (data_file, strlen (data_file) + 1); 46618334Speter } 46718334Speter 46818334Speter /* Make space for the table of counts. */ 46950503Sobrien if (size == 0) 47018334Speter { 47118334Speter /* Realign data section. */ 47218334Speter ASM_OUTPUT_ALIGN (asm_out_file, align); 47318334Speter ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 2); 47418334Speter if (size != 0) 47518334Speter assemble_zeros (size); 47618334Speter } 47718334Speter else 47818334Speter { 47918334Speter ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2); 48018334Speter#ifdef ASM_OUTPUT_SHARED_LOCAL 48118334Speter if (flag_shared_data) 48218334Speter ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded); 48318334Speter else 48418334Speter#endif 48550503Sobrien#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL 48650503Sobrien ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size, 48750503Sobrien BIGGEST_ALIGNMENT); 48850503Sobrien#else 48918334Speter#ifdef ASM_OUTPUT_ALIGNED_LOCAL 49018334Speter ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, 49118334Speter BIGGEST_ALIGNMENT); 49218334Speter#else 49318334Speter ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded); 49418334Speter#endif 49550503Sobrien#endif 49618334Speter } 49718334Speter 49818334Speter /* Output any basic block strings */ 49950503Sobrien if (profile_block_flag) 50018334Speter { 50150503Sobrien readonly_data_section (); 50250503Sobrien if (sbb_head) 50318334Speter { 50450503Sobrien ASM_OUTPUT_ALIGN (asm_out_file, align); 50550503Sobrien for (sptr = sbb_head; sptr != 0; sptr = sptr->next) 50650503Sobrien { 50750503Sobrien ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBC", 50850503Sobrien sptr->label_num); 50950503Sobrien assemble_string (sptr->string, sptr->length); 51050503Sobrien } 51118334Speter } 51218334Speter } 51318334Speter 51418334Speter /* Output the table of addresses. */ 51550503Sobrien if (profile_block_flag) 51618334Speter { 51750503Sobrien /* Realign in new section */ 51850503Sobrien ASM_OUTPUT_ALIGN (asm_out_file, align); 51950503Sobrien ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 3); 52050503Sobrien for (i = 0; i < count_basic_blocks; i++) 52150503Sobrien { 52250503Sobrien ASM_GENERATE_INTERNAL_LABEL (name, "LPB", i); 52350503Sobrien assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), 52450503Sobrien pointer_bytes, 1); 52550503Sobrien } 52618334Speter } 52718334Speter 52818334Speter /* Output the table of function names. */ 52950503Sobrien if (profile_block_flag) 53018334Speter { 53150503Sobrien ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 4); 53250503Sobrien for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++) 53318334Speter { 53450503Sobrien if (ptr->func_label_num >= 0) 53550503Sobrien { 53650503Sobrien ASM_GENERATE_INTERNAL_LABEL (name, "LPBC", 53750503Sobrien ptr->func_label_num); 53850503Sobrien assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), 53950503Sobrien pointer_bytes, 1); 54050503Sobrien } 54150503Sobrien else 54250503Sobrien assemble_integer (const0_rtx, pointer_bytes, 1); 54318334Speter } 54450503Sobrien 54550503Sobrien for ( ; i < count_basic_blocks; i++) 54650503Sobrien assemble_integer (const0_rtx, pointer_bytes, 1); 54718334Speter } 54818334Speter 54950503Sobrien if (write_symbols != NO_DEBUG && profile_block_flag) 55018334Speter { 55118334Speter /* Output the table of line numbers. */ 55218334Speter ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 5); 55318334Speter for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++) 55450503Sobrien assemble_integer (GEN_INT (ptr->line_num), long_bytes, 1); 55518334Speter 55618334Speter for ( ; i < count_basic_blocks; i++) 55750503Sobrien assemble_integer (const0_rtx, long_bytes, 1); 55818334Speter 55918334Speter /* Output the table of file names. */ 56018334Speter ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 6); 56118334Speter for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++) 56218334Speter { 56318334Speter if (ptr->file_label_num >= 0) 56418334Speter { 56550503Sobrien ASM_GENERATE_INTERNAL_LABEL (name, "LPBC", 56650503Sobrien ptr->file_label_num); 56750503Sobrien assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), 56850503Sobrien pointer_bytes, 1); 56918334Speter } 57018334Speter else 57150503Sobrien assemble_integer (const0_rtx, pointer_bytes, 1); 57218334Speter } 57318334Speter 57418334Speter for ( ; i < count_basic_blocks; i++) 57550503Sobrien assemble_integer (const0_rtx, pointer_bytes, 1); 57618334Speter } 57718334Speter 57818334Speter /* End with the address of the table of addresses, 57918334Speter so we can find it easily, as the last word in the file's text. */ 58050503Sobrien if (profile_block_flag) 58150503Sobrien { 58250503Sobrien ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3); 58350503Sobrien assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 58450503Sobrien 1); 58550503Sobrien } 58618334Speter } 58718334Speter} 58818334Speter 58918334Speter/* Enable APP processing of subsequent output. 59018334Speter Used before the output from an `asm' statement. */ 59118334Speter 59218334Spetervoid 59318334Speterapp_enable () 59418334Speter{ 59518334Speter if (! app_on) 59618334Speter { 59750503Sobrien fputs (ASM_APP_ON, asm_out_file); 59818334Speter app_on = 1; 59918334Speter } 60018334Speter} 60118334Speter 60218334Speter/* Disable APP processing of subsequent output. 60318334Speter Called from varasm.c before most kinds of output. */ 60418334Speter 60518334Spetervoid 60618334Speterapp_disable () 60718334Speter{ 60818334Speter if (app_on) 60918334Speter { 61050503Sobrien fputs (ASM_APP_OFF, asm_out_file); 61118334Speter app_on = 0; 61218334Speter } 61318334Speter} 61418334Speter 61518334Speter/* Return the number of slots filled in the current 61618334Speter delayed branch sequence (we don't count the insn needing the 61718334Speter delay slot). Zero if not in a delayed branch sequence. */ 61818334Speter 61918334Speter#ifdef DELAY_SLOTS 62018334Speterint 62118334Speterdbr_sequence_length () 62218334Speter{ 62318334Speter if (final_sequence != 0) 62418334Speter return XVECLEN (final_sequence, 0) - 1; 62518334Speter else 62618334Speter return 0; 62718334Speter} 62818334Speter#endif 62918334Speter 63018334Speter/* The next two pages contain routines used to compute the length of an insn 63118334Speter and to shorten branches. */ 63218334Speter 63318334Speter/* Arrays for insn lengths, and addresses. The latter is referenced by 63418334Speter `insn_current_length'. */ 63518334Speter 63618334Speterstatic short *insn_lengths; 63718334Speterint *insn_addresses; 63818334Speter 63918334Speter/* Address of insn being processed. Used by `insn_current_length'. */ 64018334Speterint insn_current_address; 64118334Speter 64250503Sobrien/* Address of insn being processed in previous iteration. */ 64350503Sobrienint insn_last_address; 64450503Sobrien 64550503Sobrien/* konwn invariant alignment of insn being processed. */ 64650503Sobrienint insn_current_align; 64750503Sobrien 64850503Sobrien/* After shorten_branches, for any insn, uid_align[INSN_UID (insn)] 64950503Sobrien gives the next following alignment insn that increases the known 65050503Sobrien alignment, or NULL_RTX if there is no such insn. 65150503Sobrien For any alignment obtained this way, we can again index uid_align with 65250503Sobrien its uid to obtain the next following align that in turn increases the 65350503Sobrien alignment, till we reach NULL_RTX; the sequence obtained this way 65450503Sobrien for each insn we'll call the alignment chain of this insn in the following 65550503Sobrien comments. */ 65650503Sobrien 65750503Sobrienstruct label_alignment { 65850503Sobrien short alignment; 65950503Sobrien short max_skip; 66050503Sobrien}; 66150503Sobrien 66250503Sobrienstatic rtx *uid_align; 66350503Sobrienstatic int *uid_shuid; 66450503Sobrienstatic struct label_alignment *label_align; 66550503Sobrien 66618334Speter/* Indicate that branch shortening hasn't yet been done. */ 66718334Speter 66818334Spetervoid 66918334Speterinit_insn_lengths () 67018334Speter{ 67150503Sobrien if (label_align) 67250503Sobrien { 67350503Sobrien free (label_align); 67450503Sobrien label_align = 0; 67550503Sobrien } 67650503Sobrien if (uid_shuid) 67750503Sobrien { 67850503Sobrien free (uid_shuid); 67950503Sobrien uid_shuid = 0; 68050503Sobrien } 68150503Sobrien if (insn_lengths) 68250503Sobrien { 68350503Sobrien free (insn_lengths); 68450503Sobrien insn_lengths = 0; 68550503Sobrien } 68650503Sobrien if (insn_addresses) 68750503Sobrien { 68850503Sobrien free (insn_addresses); 68950503Sobrien insn_addresses = 0; 69050503Sobrien } 69150503Sobrien if (uid_align) 69250503Sobrien { 69350503Sobrien free (uid_align); 69450503Sobrien uid_align = 0; 69550503Sobrien } 69618334Speter} 69718334Speter 69818334Speter/* Obtain the current length of an insn. If branch shortening has been done, 69918334Speter get its actual length. Otherwise, get its maximum length. */ 70018334Speter 70118334Speterint 70218334Speterget_attr_length (insn) 70318334Speter rtx insn; 70418334Speter{ 70518334Speter#ifdef HAVE_ATTR_length 70618334Speter rtx body; 70718334Speter int i; 70818334Speter int length = 0; 70918334Speter 71018334Speter if (insn_lengths) 71118334Speter return insn_lengths[INSN_UID (insn)]; 71218334Speter else 71318334Speter switch (GET_CODE (insn)) 71418334Speter { 71518334Speter case NOTE: 71618334Speter case BARRIER: 71718334Speter case CODE_LABEL: 71818334Speter return 0; 71918334Speter 72018334Speter case CALL_INSN: 72118334Speter length = insn_default_length (insn); 72218334Speter break; 72318334Speter 72418334Speter case JUMP_INSN: 72518334Speter body = PATTERN (insn); 72618334Speter if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) 72718334Speter { 72850503Sobrien /* Alignment is machine-dependent and should be handled by 72950503Sobrien ADDR_VEC_ALIGN. */ 73018334Speter } 73118334Speter else 73218334Speter length = insn_default_length (insn); 73318334Speter break; 73418334Speter 73518334Speter case INSN: 73618334Speter body = PATTERN (insn); 73718334Speter if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER) 73818334Speter return 0; 73918334Speter 74018334Speter else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0) 74118334Speter length = asm_insn_count (body) * insn_default_length (insn); 74218334Speter else if (GET_CODE (body) == SEQUENCE) 74318334Speter for (i = 0; i < XVECLEN (body, 0); i++) 74418334Speter length += get_attr_length (XVECEXP (body, 0, i)); 74518334Speter else 74618334Speter length = insn_default_length (insn); 74750503Sobrien break; 74850503Sobrien 74950503Sobrien default: 75050503Sobrien break; 75118334Speter } 75218334Speter 75318334Speter#ifdef ADJUST_INSN_LENGTH 75418334Speter ADJUST_INSN_LENGTH (insn, length); 75518334Speter#endif 75618334Speter return length; 75718334Speter#else /* not HAVE_ATTR_length */ 75818334Speter return 0; 75918334Speter#endif /* not HAVE_ATTR_length */ 76018334Speter} 76118334Speter 76250503Sobrien/* Code to handle alignment inside shorten_branches. */ 76350503Sobrien 76450503Sobrien/* Here is an explanation how the algorithm in align_fuzz can give 76550503Sobrien proper results: 76650503Sobrien 76750503Sobrien Call a sequence of instructions beginning with alignment point X 76850503Sobrien and continuing until the next alignment point `block X'. When `X' 76950503Sobrien is used in an expression, it means the alignment value of the 77050503Sobrien alignment point. 77150503Sobrien 77250503Sobrien Call the distance between the start of the first insn of block X, and 77350503Sobrien the end of the last insn of block X `IX', for the `inner size of X'. 77450503Sobrien This is clearly the sum of the instruction lengths. 77550503Sobrien 77650503Sobrien Likewise with the next alignment-delimited block following X, which we 77750503Sobrien shall call block Y. 77850503Sobrien 77950503Sobrien Call the distance between the start of the first insn of block X, and 78050503Sobrien the start of the first insn of block Y `OX', for the `outer size of X'. 78150503Sobrien 78250503Sobrien The estimated padding is then OX - IX. 78350503Sobrien 78450503Sobrien OX can be safely estimated as 78550503Sobrien 78650503Sobrien if (X >= Y) 78750503Sobrien OX = round_up(IX, Y) 78850503Sobrien else 78950503Sobrien OX = round_up(IX, X) + Y - X 79050503Sobrien 79150503Sobrien Clearly est(IX) >= real(IX), because that only depends on the 79250503Sobrien instruction lengths, and those being overestimated is a given. 79350503Sobrien 79450503Sobrien Clearly round_up(foo, Z) >= round_up(bar, Z) if foo >= bar, so 79550503Sobrien we needn't worry about that when thinking about OX. 79650503Sobrien 79750503Sobrien When X >= Y, the alignment provided by Y adds no uncertainty factor 79850503Sobrien for branch ranges starting before X, so we can just round what we have. 79950503Sobrien But when X < Y, we don't know anything about the, so to speak, 80050503Sobrien `middle bits', so we have to assume the worst when aligning up from an 80150503Sobrien address mod X to one mod Y, which is Y - X. */ 80250503Sobrien 80350503Sobrien#ifndef LABEL_ALIGN 80450503Sobrien#define LABEL_ALIGN(LABEL) 0 80550503Sobrien#endif 80650503Sobrien 80750503Sobrien#ifndef LABEL_ALIGN_MAX_SKIP 80850503Sobrien#define LABEL_ALIGN_MAX_SKIP 0 80950503Sobrien#endif 81050503Sobrien 81150503Sobrien#ifndef LOOP_ALIGN 81250503Sobrien#define LOOP_ALIGN(LABEL) 0 81350503Sobrien#endif 81450503Sobrien 81550503Sobrien#ifndef LOOP_ALIGN_MAX_SKIP 81650503Sobrien#define LOOP_ALIGN_MAX_SKIP 0 81750503Sobrien#endif 81850503Sobrien 81950503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER 82050503Sobrien#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0 82150503Sobrien#endif 82250503Sobrien 82350503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 82450503Sobrien#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0 82550503Sobrien#endif 82650503Sobrien 82750503Sobrien#ifndef ADDR_VEC_ALIGN 82850503Sobrienint 82950503Sobrienfinal_addr_vec_align (addr_vec) 83050503Sobrien rtx addr_vec; 83150503Sobrien{ 83250503Sobrien int align = exact_log2 (GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec)))); 83350503Sobrien 83450503Sobrien if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT) 83550503Sobrien align = BIGGEST_ALIGNMENT / BITS_PER_UNIT; 83650503Sobrien return align; 83750503Sobrien 83850503Sobrien} 83950503Sobrien#define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC) 84050503Sobrien#endif 84150503Sobrien 84250503Sobrien#ifndef INSN_LENGTH_ALIGNMENT 84350503Sobrien#define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log 84450503Sobrien#endif 84550503Sobrien 84650503Sobrien#define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)]) 84750503Sobrien 84850503Sobrienstatic int min_labelno, max_labelno; 84950503Sobrien 85050503Sobrien#define LABEL_TO_ALIGNMENT(LABEL) \ 85150503Sobrien (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].alignment) 85250503Sobrien 85350503Sobrien#define LABEL_TO_MAX_SKIP(LABEL) \ 85450503Sobrien (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].max_skip) 85550503Sobrien 85650503Sobrien/* For the benefit of port specific code do this also as a function. */ 85750503Sobrienint 85850503Sobrienlabel_to_alignment (label) 85950503Sobrien rtx label; 86050503Sobrien{ 86150503Sobrien return LABEL_TO_ALIGNMENT (label); 86250503Sobrien} 86350503Sobrien 86450503Sobrien#ifdef HAVE_ATTR_length 86550503Sobrien/* The differences in addresses 86650503Sobrien between a branch and its target might grow or shrink depending on 86750503Sobrien the alignment the start insn of the range (the branch for a forward 86850503Sobrien branch or the label for a backward branch) starts out on; if these 86950503Sobrien differences are used naively, they can even oscillate infinitely. 87050503Sobrien We therefore want to compute a 'worst case' address difference that 87150503Sobrien is independent of the alignment the start insn of the range end 87250503Sobrien up on, and that is at least as large as the actual difference. 87350503Sobrien The function align_fuzz calculates the amount we have to add to the 87450503Sobrien naively computed difference, by traversing the part of the alignment 87550503Sobrien chain of the start insn of the range that is in front of the end insn 87650503Sobrien of the range, and considering for each alignment the maximum amount 87750503Sobrien that it might contribute to a size increase. 87850503Sobrien 87950503Sobrien For casesi tables, we also want to know worst case minimum amounts of 88050503Sobrien address difference, in case a machine description wants to introduce 88150503Sobrien some common offset that is added to all offsets in a table. 88250503Sobrien For this purpose, align_fuzz with a growth argument of 0 comuptes the 88350503Sobrien appropriate adjustment. */ 88450503Sobrien 88550503Sobrien 88650503Sobrien/* Compute the maximum delta by which the difference of the addresses of 88750503Sobrien START and END might grow / shrink due to a different address for start 88850503Sobrien which changes the size of alignment insns between START and END. 88950503Sobrien KNOWN_ALIGN_LOG is the alignment known for START. 89050503Sobrien GROWTH should be ~0 if the objective is to compute potential code size 89150503Sobrien increase, and 0 if the objective is to compute potential shrink. 89250503Sobrien The return value is undefined for any other value of GROWTH. */ 89350503Sobrienint 89450503Sobrienalign_fuzz (start, end, known_align_log, growth) 89550503Sobrien rtx start, end; 89650503Sobrien int known_align_log; 89750503Sobrien unsigned growth; 89850503Sobrien{ 89950503Sobrien int uid = INSN_UID (start); 90050503Sobrien rtx align_label; 90150503Sobrien int known_align = 1 << known_align_log; 90250503Sobrien int end_shuid = INSN_SHUID (end); 90350503Sobrien int fuzz = 0; 90450503Sobrien 90550503Sobrien for (align_label = uid_align[uid]; align_label; align_label = uid_align[uid]) 90650503Sobrien { 90750503Sobrien int align_addr, new_align; 90850503Sobrien 90950503Sobrien uid = INSN_UID (align_label); 91050503Sobrien align_addr = insn_addresses[uid] - insn_lengths[uid]; 91150503Sobrien if (uid_shuid[uid] > end_shuid) 91250503Sobrien break; 91350503Sobrien known_align_log = LABEL_TO_ALIGNMENT (align_label); 91450503Sobrien new_align = 1 << known_align_log; 91550503Sobrien if (new_align < known_align) 91650503Sobrien continue; 91750503Sobrien fuzz += (-align_addr ^ growth) & (new_align - known_align); 91850503Sobrien known_align = new_align; 91950503Sobrien } 92050503Sobrien return fuzz; 92150503Sobrien} 92250503Sobrien 92350503Sobrien/* Compute a worst-case reference address of a branch so that it 92450503Sobrien can be safely used in the presence of aligned labels. Since the 92550503Sobrien size of the branch itself is unknown, the size of the branch is 92650503Sobrien not included in the range. I.e. for a forward branch, the reference 92750503Sobrien address is the end address of the branch as known from the previous 92850503Sobrien branch shortening pass, minus a value to account for possible size 92950503Sobrien increase due to alignment. For a backward branch, it is the start 93050503Sobrien address of the branch as known from the current pass, plus a value 93150503Sobrien to account for possible size increase due to alignment. 93250503Sobrien NB.: Therefore, the maximum offset allowed for backward branches needs 93350503Sobrien to exclude the branch size. */ 93450503Sobrienint 93550503Sobrieninsn_current_reference_address (branch) 93650503Sobrien rtx branch; 93750503Sobrien{ 93850503Sobrien rtx dest; 93950503Sobrien rtx seq = NEXT_INSN (PREV_INSN (branch)); 94050503Sobrien int seq_uid = INSN_UID (seq); 94150503Sobrien if (GET_CODE (branch) != JUMP_INSN) 94250503Sobrien /* This can happen for example on the PA; the objective is to know the 94350503Sobrien offset to address something in front of the start of the function. 94450503Sobrien Thus, we can treat it like a backward branch. 94550503Sobrien We assume here that FUNCTION_BOUNDARY / BITS_PER_UNIT is larger than 94650503Sobrien any alignment we'd encounter, so we skip the call to align_fuzz. */ 94750503Sobrien return insn_current_address; 94850503Sobrien dest = JUMP_LABEL (branch); 94950503Sobrien /* BRANCH has no proper alignment chain set, so use SEQ. */ 95050503Sobrien if (INSN_SHUID (branch) < INSN_SHUID (dest)) 95150503Sobrien { 95250503Sobrien /* Forward branch. */ 95350503Sobrien return (insn_last_address + insn_lengths[seq_uid] 95450503Sobrien - align_fuzz (seq, dest, length_unit_log, ~0)); 95550503Sobrien } 95650503Sobrien else 95750503Sobrien { 95850503Sobrien /* Backward branch. */ 95950503Sobrien return (insn_current_address 96050503Sobrien + align_fuzz (dest, seq, length_unit_log, ~0)); 96150503Sobrien } 96250503Sobrien} 96350503Sobrien#endif /* HAVE_ATTR_length */ 96450503Sobrien 96518334Speter/* Make a pass over all insns and compute their actual lengths by shortening 96618334Speter any branches of variable length if possible. */ 96718334Speter 96818334Speter/* Give a default value for the lowest address in a function. */ 96918334Speter 97018334Speter#ifndef FIRST_INSN_ADDRESS 97118334Speter#define FIRST_INSN_ADDRESS 0 97218334Speter#endif 97318334Speter 97450503Sobrien/* shorten_branches might be called multiple times: for example, the SH 97550503Sobrien port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG. 97650503Sobrien In order to do this, it needs proper length information, which it obtains 97750503Sobrien by calling shorten_branches. This cannot be collapsed with 97850503Sobrien shorten_branches itself into a single pass unless we also want to intergate 97950503Sobrien reorg.c, since the branch splitting exposes new instructions with delay 98050503Sobrien slots. */ 98150503Sobrien 98218334Spetervoid 98318334Spetershorten_branches (first) 98418334Speter rtx first; 98518334Speter{ 98650503Sobrien rtx insn; 98750503Sobrien int max_uid; 98850503Sobrien int i; 98950503Sobrien int max_log; 99050503Sobrien int max_skip; 99118334Speter#ifdef HAVE_ATTR_length 99250503Sobrien#define MAX_CODE_ALIGN 16 99350503Sobrien rtx seq; 99418334Speter int something_changed = 1; 99518334Speter char *varying_length; 99618334Speter rtx body; 99718334Speter int uid; 99850503Sobrien rtx align_tab[MAX_CODE_ALIGN]; 99918334Speter 100050503Sobrien /* In order to make sure that all instructions have valid length info, 100150503Sobrien we must split them before we compute the address/length info. */ 100218334Speter 100350503Sobrien for (insn = NEXT_INSN (first); insn; insn = NEXT_INSN (insn)) 100450503Sobrien if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') 100550503Sobrien { 100650503Sobrien rtx old = insn; 100750503Sobrien insn = try_split (PATTERN (old), old, 1); 100850503Sobrien /* When not optimizing, the old insn will be still left around 100950503Sobrien with only the 'deleted' bit set. Transform it into a note 101050503Sobrien to avoid confusion of subsequent processing. */ 101150503Sobrien if (INSN_DELETED_P (old)) 101250503Sobrien { 101350503Sobrien PUT_CODE (old , NOTE); 101450503Sobrien NOTE_LINE_NUMBER (old) = NOTE_INSN_DELETED; 101550503Sobrien NOTE_SOURCE_FILE (old) = 0; 101650503Sobrien } 101750503Sobrien } 101850503Sobrien#endif 101918334Speter 102050503Sobrien /* We must do some computations even when not actually shortening, in 102150503Sobrien order to get the alignment information for the labels. */ 102250503Sobrien 102350503Sobrien init_insn_lengths (); 102450503Sobrien 102550503Sobrien /* Compute maximum UID and allocate label_align / uid_shuid. */ 102650503Sobrien max_uid = get_max_uid (); 102750503Sobrien 102850503Sobrien max_labelno = max_label_num (); 102950503Sobrien min_labelno = get_first_label_num (); 103050503Sobrien label_align = (struct label_alignment *) xmalloc ( 103150503Sobrien (max_labelno - min_labelno + 1) * sizeof (struct label_alignment)); 103250503Sobrien bzero ((char *) label_align, 103350503Sobrien (max_labelno - min_labelno + 1) * sizeof (struct label_alignment)); 103450503Sobrien 103550503Sobrien uid_shuid = (int *) xmalloc (max_uid * sizeof *uid_shuid); 103650503Sobrien 103750503Sobrien /* Initialize label_align and set up uid_shuid to be strictly 103850503Sobrien monotonically rising with insn order. */ 103950503Sobrien /* We use max_log here to keep track of the maximum alignment we want to 104050503Sobrien impose on the next CODE_LABEL (or the current one if we are processing 104150503Sobrien the CODE_LABEL itself). */ 104250503Sobrien 104350503Sobrien max_log = 0; 104450503Sobrien max_skip = 0; 104550503Sobrien 104650503Sobrien for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn)) 104750503Sobrien { 104850503Sobrien int log; 104950503Sobrien 105050503Sobrien INSN_SHUID (insn) = i++; 105150503Sobrien if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') 105250503Sobrien { 105350503Sobrien /* reorg might make the first insn of a loop being run once only, 105450503Sobrien and delete the label in front of it. Then we want to apply 105550503Sobrien the loop alignment to the new label created by reorg, which 105650503Sobrien is separated by the former loop start insn from the 105750503Sobrien NOTE_INSN_LOOP_BEG. */ 105850503Sobrien } 105950503Sobrien else if (GET_CODE (insn) == CODE_LABEL) 106050503Sobrien { 106150503Sobrien rtx next; 106250503Sobrien 106350503Sobrien log = LABEL_ALIGN (insn); 106450503Sobrien if (max_log < log) 106550503Sobrien { 106650503Sobrien max_log = log; 106750503Sobrien max_skip = LABEL_ALIGN_MAX_SKIP; 106850503Sobrien } 106950503Sobrien next = NEXT_INSN (insn); 107050503Sobrien /* ADDR_VECs only take room if read-only data goes into the text 107150503Sobrien section. */ 107250503Sobrien if (JUMP_TABLES_IN_TEXT_SECTION 107350503Sobrien#if !defined(READONLY_DATA_SECTION) 107450503Sobrien || 1 107550503Sobrien#endif 107650503Sobrien ) 107750503Sobrien if (next && GET_CODE (next) == JUMP_INSN) 107850503Sobrien { 107950503Sobrien rtx nextbody = PATTERN (next); 108050503Sobrien if (GET_CODE (nextbody) == ADDR_VEC 108150503Sobrien || GET_CODE (nextbody) == ADDR_DIFF_VEC) 108250503Sobrien { 108350503Sobrien log = ADDR_VEC_ALIGN (next); 108450503Sobrien if (max_log < log) 108550503Sobrien { 108650503Sobrien max_log = log; 108750503Sobrien max_skip = LABEL_ALIGN_MAX_SKIP; 108850503Sobrien } 108950503Sobrien } 109050503Sobrien } 109150503Sobrien LABEL_TO_ALIGNMENT (insn) = max_log; 109250503Sobrien LABEL_TO_MAX_SKIP (insn) = max_skip; 109350503Sobrien max_log = 0; 109450503Sobrien max_skip = 0; 109550503Sobrien } 109650503Sobrien else if (GET_CODE (insn) == BARRIER) 109750503Sobrien { 109850503Sobrien rtx label; 109950503Sobrien 110050503Sobrien for (label = insn; label && GET_RTX_CLASS (GET_CODE (label)) != 'i'; 110150503Sobrien label = NEXT_INSN (label)) 110250503Sobrien if (GET_CODE (label) == CODE_LABEL) 110350503Sobrien { 110450503Sobrien log = LABEL_ALIGN_AFTER_BARRIER (insn); 110550503Sobrien if (max_log < log) 110650503Sobrien { 110750503Sobrien max_log = log; 110850503Sobrien max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP; 110950503Sobrien } 111050503Sobrien break; 111150503Sobrien } 111250503Sobrien } 111350503Sobrien /* Again, we allow NOTE_INSN_LOOP_BEG - INSN - CODE_LABEL 111450503Sobrien sequences in order to handle reorg output efficiently. */ 111550503Sobrien else if (GET_CODE (insn) == NOTE 111650503Sobrien && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG) 111750503Sobrien { 111850503Sobrien rtx label; 111950503Sobrien 112050503Sobrien for (label = insn; label; label = NEXT_INSN (label)) 112150503Sobrien if (GET_CODE (label) == CODE_LABEL) 112250503Sobrien { 112350503Sobrien log = LOOP_ALIGN (insn); 112450503Sobrien if (max_log < log) 112550503Sobrien { 112650503Sobrien max_log = log; 112750503Sobrien max_skip = LOOP_ALIGN_MAX_SKIP; 112850503Sobrien } 112950503Sobrien break; 113050503Sobrien } 113150503Sobrien } 113250503Sobrien else 113350503Sobrien continue; 113450503Sobrien } 113550503Sobrien#ifdef HAVE_ATTR_length 113650503Sobrien 113750503Sobrien /* Allocate the rest of the arrays. */ 113850503Sobrien insn_lengths = (short *) xmalloc (max_uid * sizeof (short)); 113950503Sobrien insn_addresses = (int *) xmalloc (max_uid * sizeof (int)); 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]); 132518334Speter#endif 132618334Speter } 132718334Speter 132818334Speter /* Now loop over all the insns finding varying length insns. For each, 132918334Speter get the current insn length. If it has changed, reflect the change. 133018334Speter When nothing changes for a full pass, we are done. */ 133118334Speter 133218334Speter while (something_changed) 133318334Speter { 133418334Speter something_changed = 0; 133550503Sobrien insn_current_align = MAX_CODE_ALIGN - 1; 133618334Speter for (insn_current_address = FIRST_INSN_ADDRESS, insn = first; 133718334Speter insn != 0; 133818334Speter insn = NEXT_INSN (insn)) 133918334Speter { 134018334Speter int new_length; 134150503Sobrien#ifdef ADJUST_INSN_LENGTH 134218334Speter int tmp_length; 134350503Sobrien#endif 134450503Sobrien int length_align; 134518334Speter 134618334Speter uid = INSN_UID (insn); 134750503Sobrien 134850503Sobrien if (GET_CODE (insn) == CODE_LABEL) 134950503Sobrien { 135050503Sobrien int log = LABEL_TO_ALIGNMENT (insn); 135150503Sobrien if (log > insn_current_align) 135250503Sobrien { 135350503Sobrien int align = 1 << log; 135450503Sobrien int new_address= (insn_current_address + align - 1) & -align; 135550503Sobrien insn_lengths[uid] = new_address - insn_current_address; 135650503Sobrien insn_current_align = log; 135750503Sobrien insn_current_address = new_address; 135850503Sobrien } 135950503Sobrien else 136050503Sobrien insn_lengths[uid] = 0; 136150503Sobrien insn_addresses[uid] = insn_current_address; 136250503Sobrien continue; 136350503Sobrien } 136450503Sobrien 136550503Sobrien length_align = INSN_LENGTH_ALIGNMENT (insn); 136650503Sobrien if (length_align < insn_current_align) 136750503Sobrien insn_current_align = length_align; 136850503Sobrien 136950503Sobrien insn_last_address = insn_addresses[uid]; 137018334Speter insn_addresses[uid] = insn_current_address; 137150503Sobrien 137250503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE 137350503Sobrien if (optimize && GET_CODE (insn) == JUMP_INSN 137450503Sobrien && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC) 137518334Speter { 137650503Sobrien rtx body = PATTERN (insn); 137750503Sobrien int old_length = insn_lengths[uid]; 137850503Sobrien rtx rel_lab = XEXP (XEXP (body, 0), 0); 137950503Sobrien rtx min_lab = XEXP (XEXP (body, 2), 0); 138050503Sobrien rtx max_lab = XEXP (XEXP (body, 3), 0); 138150503Sobrien addr_diff_vec_flags flags = ADDR_DIFF_VEC_FLAGS (body); 138250503Sobrien int rel_addr = insn_addresses[INSN_UID (rel_lab)]; 138350503Sobrien int min_addr = insn_addresses[INSN_UID (min_lab)]; 138450503Sobrien int max_addr = insn_addresses[INSN_UID (max_lab)]; 138550503Sobrien rtx prev; 138650503Sobrien int rel_align = 0; 138750503Sobrien 138850503Sobrien /* Try to find a known alignment for rel_lab. */ 138950503Sobrien for (prev = rel_lab; 139050503Sobrien prev 139150503Sobrien && ! insn_lengths[INSN_UID (prev)] 139250503Sobrien && ! (varying_length[INSN_UID (prev)] & 1); 139350503Sobrien prev = PREV_INSN (prev)) 139450503Sobrien if (varying_length[INSN_UID (prev)] & 2) 139550503Sobrien { 139650503Sobrien rel_align = LABEL_TO_ALIGNMENT (prev); 139750503Sobrien break; 139850503Sobrien } 139950503Sobrien 140050503Sobrien /* See the comment on addr_diff_vec_flags in rtl.h for the 140150503Sobrien meaning of the flags values. base: REL_LAB vec: INSN */ 140250503Sobrien /* Anything after INSN has still addresses from the last 140350503Sobrien pass; adjust these so that they reflect our current 140450503Sobrien estimate for this pass. */ 140550503Sobrien if (flags.base_after_vec) 140650503Sobrien rel_addr += insn_current_address - insn_last_address; 140750503Sobrien if (flags.min_after_vec) 140850503Sobrien min_addr += insn_current_address - insn_last_address; 140950503Sobrien if (flags.max_after_vec) 141050503Sobrien max_addr += insn_current_address - insn_last_address; 141150503Sobrien /* We want to know the worst case, i.e. lowest possible value 141250503Sobrien for the offset of MIN_LAB. If MIN_LAB is after REL_LAB, 141350503Sobrien its offset is positive, and we have to be wary of code shrink; 141450503Sobrien otherwise, it is negative, and we have to be vary of code 141550503Sobrien size increase. */ 141650503Sobrien if (flags.min_after_base) 141750503Sobrien { 141850503Sobrien /* If INSN is between REL_LAB and MIN_LAB, the size 141950503Sobrien changes we are about to make can change the alignment 142050503Sobrien within the observed offset, therefore we have to break 142150503Sobrien it up into two parts that are independent. */ 142250503Sobrien if (! flags.base_after_vec && flags.min_after_vec) 142350503Sobrien { 142450503Sobrien min_addr -= align_fuzz (rel_lab, insn, rel_align, 0); 142550503Sobrien min_addr -= align_fuzz (insn, min_lab, 0, 0); 142650503Sobrien } 142750503Sobrien else 142850503Sobrien min_addr -= align_fuzz (rel_lab, min_lab, rel_align, 0); 142950503Sobrien } 143050503Sobrien else 143150503Sobrien { 143250503Sobrien if (flags.base_after_vec && ! flags.min_after_vec) 143350503Sobrien { 143450503Sobrien min_addr -= align_fuzz (min_lab, insn, 0, ~0); 143550503Sobrien min_addr -= align_fuzz (insn, rel_lab, 0, ~0); 143650503Sobrien } 143750503Sobrien else 143850503Sobrien min_addr -= align_fuzz (min_lab, rel_lab, 0, ~0); 143950503Sobrien } 144050503Sobrien /* Likewise, determine the highest lowest possible value 144150503Sobrien for the offset of MAX_LAB. */ 144250503Sobrien if (flags.max_after_base) 144350503Sobrien { 144450503Sobrien if (! flags.base_after_vec && flags.max_after_vec) 144550503Sobrien { 144650503Sobrien max_addr += align_fuzz (rel_lab, insn, rel_align, ~0); 144750503Sobrien max_addr += align_fuzz (insn, max_lab, 0, ~0); 144850503Sobrien } 144950503Sobrien else 145050503Sobrien max_addr += align_fuzz (rel_lab, max_lab, rel_align, ~0); 145150503Sobrien } 145250503Sobrien else 145350503Sobrien { 145450503Sobrien if (flags.base_after_vec && ! flags.max_after_vec) 145550503Sobrien { 145650503Sobrien max_addr += align_fuzz (max_lab, insn, 0, 0); 145750503Sobrien max_addr += align_fuzz (insn, rel_lab, 0, 0); 145850503Sobrien } 145950503Sobrien else 146050503Sobrien max_addr += align_fuzz (max_lab, rel_lab, 0, 0); 146150503Sobrien } 146250503Sobrien PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr, 146350503Sobrien max_addr - rel_addr, 146450503Sobrien body)); 146550503Sobrien if (JUMP_TABLES_IN_TEXT_SECTION 146650503Sobrien#if !defined(READONLY_DATA_SECTION) 146750503Sobrien || 1 146850503Sobrien#endif 146950503Sobrien ) 147050503Sobrien { 147150503Sobrien insn_lengths[uid] 147250503Sobrien = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body))); 147350503Sobrien insn_current_address += insn_lengths[uid]; 147450503Sobrien if (insn_lengths[uid] != old_length) 147550503Sobrien something_changed = 1; 147650503Sobrien } 147750503Sobrien 147850503Sobrien continue; 147950503Sobrien } 148050503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */ 148150503Sobrien 148250503Sobrien if (! (varying_length[uid])) 148350503Sobrien { 148418334Speter insn_current_address += insn_lengths[uid]; 148518334Speter continue; 148618334Speter } 148718334Speter if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) 148818334Speter { 148918334Speter int i; 149018334Speter 149118334Speter body = PATTERN (insn); 149218334Speter new_length = 0; 149318334Speter for (i = 0; i < XVECLEN (body, 0); i++) 149418334Speter { 149518334Speter rtx inner_insn = XVECEXP (body, 0, i); 149618334Speter int inner_uid = INSN_UID (inner_insn); 149718334Speter int inner_length; 149818334Speter 149918334Speter insn_addresses[inner_uid] = insn_current_address; 150018334Speter 150118334Speter /* insn_current_length returns 0 for insns with a 150218334Speter non-varying length. */ 150318334Speter if (! varying_length[inner_uid]) 150418334Speter inner_length = insn_lengths[inner_uid]; 150518334Speter else 150618334Speter inner_length = insn_current_length (inner_insn); 150718334Speter 150818334Speter if (inner_length != insn_lengths[inner_uid]) 150918334Speter { 151018334Speter insn_lengths[inner_uid] = inner_length; 151118334Speter something_changed = 1; 151218334Speter } 151318334Speter insn_current_address += insn_lengths[inner_uid]; 151418334Speter new_length += inner_length; 151518334Speter } 151618334Speter } 151718334Speter else 151818334Speter { 151918334Speter new_length = insn_current_length (insn); 152018334Speter insn_current_address += new_length; 152118334Speter } 152218334Speter 152318334Speter#ifdef ADJUST_INSN_LENGTH 152418334Speter /* If needed, do any adjustment. */ 152518334Speter tmp_length = new_length; 152618334Speter ADJUST_INSN_LENGTH (insn, new_length); 152718334Speter insn_current_address += (new_length - tmp_length); 152818334Speter#endif 152918334Speter 153018334Speter if (new_length != insn_lengths[uid]) 153118334Speter { 153218334Speter insn_lengths[uid] = new_length; 153318334Speter something_changed = 1; 153418334Speter } 153518334Speter } 153618334Speter /* For a non-optimizing compile, do only a single pass. */ 153718334Speter if (!optimize) 153818334Speter break; 153918334Speter } 154050503Sobrien 154150503Sobrien free (varying_length); 154250503Sobrien 154318334Speter#endif /* HAVE_ATTR_length */ 154418334Speter} 154518334Speter 154618334Speter#ifdef HAVE_ATTR_length 154718334Speter/* Given the body of an INSN known to be generated by an ASM statement, return 154818334Speter the number of machine instructions likely to be generated for this insn. 154918334Speter This is used to compute its length. */ 155018334Speter 155118334Speterstatic int 155218334Speterasm_insn_count (body) 155318334Speter rtx body; 155418334Speter{ 155518334Speter char *template; 155618334Speter int count = 1; 155718334Speter 155818334Speter if (GET_CODE (body) == ASM_INPUT) 155918334Speter template = XSTR (body, 0); 156018334Speter else 156118334Speter template = decode_asm_operands (body, NULL_PTR, NULL_PTR, 156218334Speter NULL_PTR, NULL_PTR); 156318334Speter 156418334Speter for ( ; *template; template++) 156518334Speter if (IS_ASM_LOGICAL_LINE_SEPARATOR(*template) || *template == '\n') 156618334Speter count++; 156718334Speter 156818334Speter return count; 156918334Speter} 157018334Speter#endif 157118334Speter 157218334Speter/* Output assembler code for the start of a function, 157318334Speter and initialize some of the variables in this file 157418334Speter for the new function. The label for the function and associated 157518334Speter assembler pseudo-ops have already been output in `assemble_start_function'. 157618334Speter 157718334Speter FIRST is the first insn of the rtl for the function being compiled. 157818334Speter FILE is the file to write assembler code to. 157918334Speter OPTIMIZE is nonzero if we should eliminate redundant 158018334Speter test and compare insns. */ 158118334Speter 158218334Spetervoid 158318334Speterfinal_start_function (first, file, optimize) 158418334Speter rtx first; 158518334Speter FILE *file; 158618334Speter int optimize; 158718334Speter{ 158818334Speter block_depth = 0; 158918334Speter 159018334Speter this_is_asm_operands = 0; 159118334Speter 159218334Speter#ifdef NON_SAVING_SETJMP 159318334Speter /* A function that calls setjmp should save and restore all the 159418334Speter call-saved registers on a system where longjmp clobbers them. */ 159518334Speter if (NON_SAVING_SETJMP && current_function_calls_setjmp) 159618334Speter { 159718334Speter int i; 159818334Speter 159918334Speter for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 160018334Speter if (!call_used_regs[i] && !call_fixed_regs[i]) 160118334Speter regs_ever_live[i] = 1; 160218334Speter } 160318334Speter#endif 160418334Speter 160518334Speter /* Initial line number is supposed to be output 160618334Speter before the function's prologue and label 160718334Speter so that the function's address will not appear to be 160818334Speter in the last statement of the preceding function. */ 160918334Speter if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED) 161018334Speter last_linenum = high_block_linenum = high_function_linenum 161118334Speter = NOTE_LINE_NUMBER (first); 161218334Speter 161350503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO) 161450503Sobrien /* Output DWARF definition of the function. */ 161550503Sobrien if (dwarf2out_do_frame ()) 161650503Sobrien dwarf2out_begin_prologue (); 161750503Sobrien#endif 161850503Sobrien 161918334Speter /* For SDB and XCOFF, the function beginning must be marked between 162018334Speter the function label and the prologue. We always need this, even when 162118334Speter -g1 was used. Defer on MIPS systems so that parameter descriptions 162250503Sobrien follow function entry. */ 162318334Speter#if defined(SDB_DEBUGGING_INFO) && !defined(MIPS_DEBUGGING_INFO) 162418334Speter if (write_symbols == SDB_DEBUG) 162518334Speter sdbout_begin_function (last_linenum); 162618334Speter else 162718334Speter#endif 162818334Speter#ifdef XCOFF_DEBUGGING_INFO 162918334Speter if (write_symbols == XCOFF_DEBUG) 163018334Speter xcoffout_begin_function (file, last_linenum); 163118334Speter else 163218334Speter#endif 163318334Speter /* But only output line number for other debug info types if -g2 163418334Speter or better. */ 163518334Speter if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED) 163618334Speter output_source_line (file, first); 163718334Speter 163818334Speter#ifdef LEAF_REG_REMAP 163918334Speter if (leaf_function) 164018334Speter leaf_renumber_regs (first); 164118334Speter#endif 164218334Speter 164318347Speter if (profile_block_flag) 164418347Speter add_bb (file); 164518347Speter 164618334Speter /* The Sun386i and perhaps other machines don't work right 164718334Speter if the profiling code comes after the prologue. */ 164818334Speter#ifdef PROFILE_BEFORE_PROLOGUE 164918334Speter if (profile_flag) 165018334Speter profile_function (file); 165118334Speter#endif /* PROFILE_BEFORE_PROLOGUE */ 165218334Speter 165350503Sobrien#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue) 165450503Sobrien if (dwarf2out_do_frame ()) 165550503Sobrien dwarf2out_frame_debug (NULL_RTX); 165650503Sobrien#endif 165750503Sobrien 165818334Speter#ifdef FUNCTION_PROLOGUE 165918334Speter /* First output the function prologue: code to set up the stack frame. */ 166018334Speter FUNCTION_PROLOGUE (file, get_frame_size ()); 166118334Speter#endif 166218334Speter 166318334Speter#if defined (SDB_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) 166418334Speter if (write_symbols == SDB_DEBUG || write_symbols == XCOFF_DEBUG) 166518334Speter next_block_index = 1; 166618334Speter#endif 166718334Speter 166818334Speter /* If the machine represents the prologue as RTL, the profiling code must 166918334Speter be emitted when NOTE_INSN_PROLOGUE_END is scanned. */ 167018334Speter#ifdef HAVE_prologue 167118334Speter if (! HAVE_prologue) 167218334Speter#endif 167318334Speter profile_after_prologue (file); 167418334Speter 167518334Speter profile_label_no++; 167618334Speter 167718334Speter /* If we are doing basic block profiling, remember a printable version 167818334Speter of the function name. */ 167918334Speter if (profile_block_flag) 168018334Speter { 168150503Sobrien bb_func_label_num 168250503Sobrien = add_bb_string ((*decl_printable_name) (current_function_decl, 2), FALSE); 168318334Speter } 168418334Speter} 168518334Speter 168618334Speterstatic void 168718334Speterprofile_after_prologue (file) 168818334Speter FILE *file; 168918334Speter{ 169018334Speter#ifdef FUNCTION_BLOCK_PROFILER 169118334Speter if (profile_block_flag) 169218334Speter { 169350503Sobrien FUNCTION_BLOCK_PROFILER (file, count_basic_blocks); 169418334Speter } 169518334Speter#endif /* FUNCTION_BLOCK_PROFILER */ 169618334Speter 169718334Speter#ifndef PROFILE_BEFORE_PROLOGUE 169818334Speter if (profile_flag) 169918334Speter profile_function (file); 170018334Speter#endif /* not PROFILE_BEFORE_PROLOGUE */ 170118334Speter} 170218334Speter 170318334Speterstatic void 170418334Speterprofile_function (file) 170518334Speter FILE *file; 170618334Speter{ 170718347Speter#ifndef NO_PROFILE_DATA 170850503Sobrien int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE); 170918347Speter#endif /* not NO_PROFILE_DATA */ 171050503Sobrien#if defined(ASM_OUTPUT_REG_PUSH) 171150503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) || defined(STRUCT_VALUE_REGNUM) 171218334Speter int sval = current_function_returns_struct; 171350503Sobrien#endif 171450503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM) 171518334Speter int cxt = current_function_needs_context; 171650503Sobrien#endif 171750503Sobrien#endif /* ASM_OUTPUT_REG_PUSH */ 171818334Speter 171918347Speter#ifndef NO_PROFILE_DATA 172018334Speter data_section (); 172118334Speter ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT)); 172218334Speter ASM_OUTPUT_INTERNAL_LABEL (file, "LP", profile_label_no); 172350503Sobrien assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, 1); 172418347Speter#endif /* not NO_PROFILE_DATA */ 172518334Speter 172650503Sobrien function_section (current_function_decl); 172718334Speter 172850503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 172918334Speter if (sval) 173018334Speter ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_INCOMING_REGNUM); 173118334Speter#else 173250503Sobrien#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 173318334Speter if (sval) 173450503Sobrien { 173550503Sobrien ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_REGNUM); 173650503Sobrien } 173718334Speter#endif 173818334Speter#endif 173918334Speter 174050503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 174118334Speter if (cxt) 174218334Speter ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM); 174318334Speter#else 174450503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 174518334Speter if (cxt) 174650503Sobrien { 174750503Sobrien ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM); 174850503Sobrien } 174918334Speter#endif 175018334Speter#endif 175118334Speter 175218334Speter FUNCTION_PROFILER (file, profile_label_no); 175318334Speter 175450503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 175518334Speter if (cxt) 175618334Speter ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM); 175718334Speter#else 175850503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 175918334Speter if (cxt) 176050503Sobrien { 176150503Sobrien ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM); 176250503Sobrien } 176318334Speter#endif 176418334Speter#endif 176518334Speter 176650503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 176718334Speter if (sval) 176818334Speter ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_INCOMING_REGNUM); 176918334Speter#else 177050503Sobrien#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 177118334Speter if (sval) 177250503Sobrien { 177350503Sobrien ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_REGNUM); 177450503Sobrien } 177518334Speter#endif 177618334Speter#endif 177718334Speter} 177818334Speter 177918334Speter/* Output assembler code for the end of a function. 178018334Speter For clarity, args are same as those of `final_start_function' 178118334Speter even though not all of them are needed. */ 178218334Speter 178318334Spetervoid 178418334Speterfinal_end_function (first, file, optimize) 178518334Speter rtx first; 178618334Speter FILE *file; 178718334Speter int optimize; 178818334Speter{ 178918334Speter if (app_on) 179018334Speter { 179150503Sobrien fputs (ASM_APP_OFF, file); 179218334Speter app_on = 0; 179318334Speter } 179418334Speter 179518334Speter#ifdef SDB_DEBUGGING_INFO 179618334Speter if (write_symbols == SDB_DEBUG) 179718334Speter sdbout_end_function (high_function_linenum); 179818334Speter#endif 179918334Speter 180018334Speter#ifdef DWARF_DEBUGGING_INFO 180118334Speter if (write_symbols == DWARF_DEBUG) 180218334Speter dwarfout_end_function (); 180318334Speter#endif 180418334Speter 180518334Speter#ifdef XCOFF_DEBUGGING_INFO 180618334Speter if (write_symbols == XCOFF_DEBUG) 180718334Speter xcoffout_end_function (file, high_function_linenum); 180818334Speter#endif 180918334Speter 181018334Speter#ifdef FUNCTION_EPILOGUE 181118334Speter /* Finally, output the function epilogue: 181218334Speter code to restore the stack frame and return to the caller. */ 181318334Speter FUNCTION_EPILOGUE (file, get_frame_size ()); 181418334Speter#endif 181518334Speter 181618347Speter if (profile_block_flag) 181718347Speter add_bb (file); 181818347Speter 181918334Speter#ifdef SDB_DEBUGGING_INFO 182018334Speter if (write_symbols == SDB_DEBUG) 182118334Speter sdbout_end_epilogue (); 182218334Speter#endif 182318334Speter 182418334Speter#ifdef DWARF_DEBUGGING_INFO 182518334Speter if (write_symbols == DWARF_DEBUG) 182618334Speter dwarfout_end_epilogue (); 182718334Speter#endif 182818334Speter 182950503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO) 183050503Sobrien if (dwarf2out_do_frame ()) 183150503Sobrien dwarf2out_end_epilogue (); 183250503Sobrien#endif 183350503Sobrien 183418334Speter#ifdef XCOFF_DEBUGGING_INFO 183518334Speter if (write_symbols == XCOFF_DEBUG) 183618334Speter xcoffout_end_epilogue (file); 183718334Speter#endif 183818334Speter 183918334Speter bb_func_label_num = -1; /* not in function, nuke label # */ 184018334Speter 184118334Speter /* If FUNCTION_EPILOGUE is not defined, then the function body 184218334Speter itself contains return instructions wherever needed. */ 184318334Speter} 184418334Speter 184518334Speter/* Add a block to the linked list that remembers the current line/file/function 184618334Speter for basic block profiling. Emit the label in front of the basic block and 184718334Speter the instructions that increment the count field. */ 184818334Speter 184918334Speterstatic void 185018334Speteradd_bb (file) 185118334Speter FILE *file; 185218334Speter{ 185318334Speter struct bb_list *ptr = (struct bb_list *) permalloc (sizeof (struct bb_list)); 185418334Speter 185518334Speter /* Add basic block to linked list. */ 185618334Speter ptr->next = 0; 185718334Speter ptr->line_num = last_linenum; 185818334Speter ptr->file_label_num = bb_file_label_num; 185918334Speter ptr->func_label_num = bb_func_label_num; 186018334Speter *bb_tail = ptr; 186118334Speter bb_tail = &ptr->next; 186218334Speter 186318334Speter /* Enable the table of basic-block use counts 186418334Speter to point at the code it applies to. */ 186518334Speter ASM_OUTPUT_INTERNAL_LABEL (file, "LPB", count_basic_blocks); 186618334Speter 186718334Speter /* Before first insn of this basic block, increment the 186818334Speter count of times it was entered. */ 186918334Speter#ifdef BLOCK_PROFILER 187018334Speter BLOCK_PROFILER (file, count_basic_blocks); 187150503Sobrien#endif 187250503Sobrien#ifdef HAVE_cc0 187318334Speter CC_STATUS_INIT; 187418334Speter#endif 187518334Speter 187618334Speter new_block = 0; 187718334Speter count_basic_blocks++; 187818334Speter} 187918334Speter 188018334Speter/* Add a string to be used for basic block profiling. */ 188118334Speter 188218334Speterstatic int 188318334Speteradd_bb_string (string, perm_p) 188418334Speter char *string; 188518334Speter int perm_p; 188618334Speter{ 188718334Speter int len; 188818334Speter struct bb_str *ptr = 0; 188918334Speter 189018334Speter if (!string) 189118334Speter { 189218334Speter string = "<unknown>"; 189318334Speter perm_p = TRUE; 189418334Speter } 189518334Speter 189618334Speter /* Allocate a new string if the current string isn't permanent. If 189718334Speter the string is permanent search for the same string in other 189818334Speter allocations. */ 189918334Speter 190018334Speter len = strlen (string) + 1; 190118334Speter if (!perm_p) 190218334Speter { 190318334Speter char *p = (char *) permalloc (len); 190418334Speter bcopy (string, p, len); 190518334Speter string = p; 190618334Speter } 190718334Speter else 190850503Sobrien for (ptr = sbb_head; ptr != (struct bb_str *) 0; ptr = ptr->next) 190918334Speter if (ptr->string == string) 191018334Speter break; 191118334Speter 191218334Speter /* Allocate a new string block if we need to. */ 191318334Speter if (!ptr) 191418334Speter { 191518334Speter ptr = (struct bb_str *) permalloc (sizeof (*ptr)); 191618334Speter ptr->next = 0; 191718334Speter ptr->length = len; 191818334Speter ptr->label_num = sbb_label_num++; 191918334Speter ptr->string = string; 192018334Speter *sbb_tail = ptr; 192118334Speter sbb_tail = &ptr->next; 192218334Speter } 192318334Speter 192418334Speter return ptr->label_num; 192518334Speter} 192618334Speter 192718334Speter 192818334Speter/* Output assembler code for some insns: all or part of a function. 192918334Speter For description of args, see `final_start_function', above. 193018334Speter 193118334Speter PRESCAN is 1 if we are not really outputting, 193218334Speter just scanning as if we were outputting. 193318334Speter Prescanning deletes and rearranges insns just like ordinary output. 193418334Speter PRESCAN is -2 if we are outputting after having prescanned. 193518334Speter In this case, don't try to delete or rearrange insns 193618334Speter because that has already been done. 193718334Speter Prescanning is done only on certain machines. */ 193818334Speter 193918334Spetervoid 194018334Speterfinal (first, file, optimize, prescan) 194118334Speter rtx first; 194218334Speter FILE *file; 194318334Speter int optimize; 194418334Speter int prescan; 194518334Speter{ 194618334Speter register rtx insn; 194718334Speter int max_line = 0; 194850503Sobrien int max_uid = 0; 194918334Speter 195018334Speter last_ignored_compare = 0; 195118334Speter new_block = 1; 195218334Speter 195350503Sobrien check_exception_handler_labels (); 195450503Sobrien 195518334Speter /* Make a map indicating which line numbers appear in this function. 195618334Speter When producing SDB debugging info, delete troublesome line number 195718334Speter notes from inlined functions in other files as well as duplicate 195818334Speter line number notes. */ 195918334Speter#ifdef SDB_DEBUGGING_INFO 196018334Speter if (write_symbols == SDB_DEBUG) 196118334Speter { 196218334Speter rtx last = 0; 196318334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 196418334Speter if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) 196518334Speter { 196618334Speter if ((RTX_INTEGRATED_P (insn) 196718334Speter && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0) 196818334Speter || (last != 0 196918334Speter && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last) 197018334Speter && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last))) 197118334Speter { 197218334Speter NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; 197318334Speter NOTE_SOURCE_FILE (insn) = 0; 197418334Speter continue; 197518334Speter } 197618334Speter last = insn; 197718334Speter if (NOTE_LINE_NUMBER (insn) > max_line) 197818334Speter max_line = NOTE_LINE_NUMBER (insn); 197918334Speter } 198018334Speter } 198118334Speter else 198218334Speter#endif 198318334Speter { 198418334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 198518334Speter if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > max_line) 198618334Speter max_line = NOTE_LINE_NUMBER (insn); 198718334Speter } 198818334Speter 198918334Speter line_note_exists = (char *) oballoc (max_line + 1); 199018334Speter bzero (line_note_exists, max_line + 1); 199118334Speter 199218334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 199350503Sobrien { 199450503Sobrien if (INSN_UID (insn) > max_uid) /* find largest UID */ 199550503Sobrien max_uid = INSN_UID (insn); 199650503Sobrien if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) 199750503Sobrien line_note_exists[NOTE_LINE_NUMBER (insn)] = 1; 199850503Sobrien } 199918334Speter 200050503Sobrien /* Initialize insn_eh_region table if eh is being used. */ 200150503Sobrien 200250503Sobrien init_insn_eh_region (first, max_uid); 200350503Sobrien 200418334Speter init_recog (); 200518334Speter 200618334Speter CC_STATUS_INIT; 200718334Speter 200818334Speter /* Output the insns. */ 200918334Speter for (insn = NEXT_INSN (first); insn;) 201050503Sobrien { 201150503Sobrien#ifdef HAVE_ATTR_length 201250503Sobrien insn_current_address = insn_addresses[INSN_UID (insn)]; 201350503Sobrien#endif 201450503Sobrien insn = final_scan_insn (insn, file, optimize, prescan, 0); 201550503Sobrien } 201618334Speter 201718334Speter /* Do basic-block profiling here 201818334Speter if the last insn was a conditional branch. */ 201918334Speter if (profile_block_flag && new_block) 202018334Speter add_bb (file); 202150503Sobrien 202250503Sobrien free_insn_eh_region (); 202318334Speter} 202418334Speter 202518334Speter/* The final scan for one insn, INSN. 202618334Speter Args are same as in `final', except that INSN 202718334Speter is the insn being scanned. 202818334Speter Value returned is the next insn to be scanned. 202918334Speter 203018334Speter NOPEEPHOLES is the flag to disallow peephole processing (currently 203118334Speter used for within delayed branch sequence output). */ 203218334Speter 203318334Speterrtx 203418334Speterfinal_scan_insn (insn, file, optimize, prescan, nopeepholes) 203518334Speter rtx insn; 203618334Speter FILE *file; 203718334Speter int optimize; 203818334Speter int prescan; 203918334Speter int nopeepholes; 204018334Speter{ 204118334Speter register int i; 204250503Sobrien#ifdef HAVE_cc0 204350503Sobrien rtx set; 204450503Sobrien#endif 204550503Sobrien 204618334Speter insn_counter++; 204718334Speter 204818334Speter /* Ignore deleted insns. These can occur when we split insns (due to a 204918334Speter template of "#") while not optimizing. */ 205018334Speter if (INSN_DELETED_P (insn)) 205118334Speter return NEXT_INSN (insn); 205218334Speter 205318334Speter switch (GET_CODE (insn)) 205418334Speter { 205518334Speter case NOTE: 205618334Speter if (prescan > 0) 205718334Speter break; 205818334Speter 205918334Speter /* Align the beginning of a loop, for higher speed 206018334Speter on certain machines. */ 206118334Speter 206250503Sobrien if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG) 206350503Sobrien break; /* This used to depend on optimize, but that was bogus. */ 206450503Sobrien if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END) 206550503Sobrien break; 206650503Sobrien 206750503Sobrien if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG 206850503Sobrien && ! exceptions_via_longjmp) 206918334Speter { 207050503Sobrien ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", NOTE_BLOCK_NUMBER (insn)); 207150503Sobrien if (! flag_new_exceptions) 207250503Sobrien add_eh_table_entry (NOTE_BLOCK_NUMBER (insn)); 207350503Sobrien#ifdef ASM_OUTPUT_EH_REGION_BEG 207450503Sobrien ASM_OUTPUT_EH_REGION_BEG (file, NOTE_BLOCK_NUMBER (insn)); 207518334Speter#endif 207618334Speter break; 207718334Speter } 207818334Speter 207950503Sobrien if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END 208050503Sobrien && ! exceptions_via_longjmp) 208150503Sobrien { 208250503Sobrien ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", NOTE_BLOCK_NUMBER (insn)); 208350503Sobrien if (flag_new_exceptions) 208450503Sobrien add_eh_table_entry (NOTE_BLOCK_NUMBER (insn)); 208550503Sobrien#ifdef ASM_OUTPUT_EH_REGION_END 208650503Sobrien ASM_OUTPUT_EH_REGION_END (file, NOTE_BLOCK_NUMBER (insn)); 208750503Sobrien#endif 208850503Sobrien break; 208950503Sobrien } 209050503Sobrien 209118334Speter if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END) 209218334Speter { 209318334Speter#ifdef FUNCTION_END_PROLOGUE 209418334Speter FUNCTION_END_PROLOGUE (file); 209518334Speter#endif 209618334Speter profile_after_prologue (file); 209718334Speter break; 209818334Speter } 209918334Speter 210018334Speter#ifdef FUNCTION_BEGIN_EPILOGUE 210118334Speter if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG) 210218334Speter { 210318334Speter FUNCTION_BEGIN_EPILOGUE (file); 210418334Speter break; 210518334Speter } 210618334Speter#endif 210718334Speter 210818334Speter if (write_symbols == NO_DEBUG) 210918334Speter break; 211018334Speter if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG) 211118334Speter { 211218334Speter#if defined(SDB_DEBUGGING_INFO) && defined(MIPS_DEBUGGING_INFO) 211318334Speter /* MIPS stabs require the parameter descriptions to be after the 211450503Sobrien function entry point rather than before. */ 211518334Speter if (write_symbols == SDB_DEBUG) 211618334Speter sdbout_begin_function (last_linenum); 211718334Speter else 211818334Speter#endif 211918334Speter#ifdef DWARF_DEBUGGING_INFO 212018334Speter /* This outputs a marker where the function body starts, so it 212118334Speter must be after the prologue. */ 212218334Speter if (write_symbols == DWARF_DEBUG) 212318334Speter dwarfout_begin_function (); 212418334Speter#endif 212518334Speter break; 212618334Speter } 212718334Speter if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED) 212818334Speter break; /* An insn that was "deleted" */ 212918334Speter if (app_on) 213018334Speter { 213150503Sobrien fputs (ASM_APP_OFF, file); 213218334Speter app_on = 0; 213318334Speter } 213418334Speter if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG 213518334Speter && (debug_info_level == DINFO_LEVEL_NORMAL 213618334Speter || debug_info_level == DINFO_LEVEL_VERBOSE 213718334Speter || write_symbols == DWARF_DEBUG 213850503Sobrien || write_symbols == DWARF2_DEBUG)) 213918334Speter { 214018334Speter /* Beginning of a symbol-block. Assign it a sequence number 214118334Speter and push the number onto the stack PENDING_BLOCKS. */ 214218334Speter 214318334Speter if (block_depth == max_block_depth) 214418334Speter { 214518334Speter /* PENDING_BLOCKS is full; make it longer. */ 214618334Speter max_block_depth *= 2; 214718334Speter pending_blocks 214818334Speter = (int *) xrealloc (pending_blocks, 214918334Speter max_block_depth * sizeof (int)); 215018334Speter } 215118334Speter pending_blocks[block_depth++] = next_block_index; 215218334Speter 215318334Speter high_block_linenum = last_linenum; 215418334Speter 215518334Speter /* Output debugging info about the symbol-block beginning. */ 215618334Speter 215718334Speter#ifdef SDB_DEBUGGING_INFO 215818334Speter if (write_symbols == SDB_DEBUG) 215918334Speter sdbout_begin_block (file, last_linenum, next_block_index); 216018334Speter#endif 216118334Speter#ifdef XCOFF_DEBUGGING_INFO 216218334Speter if (write_symbols == XCOFF_DEBUG) 216318334Speter xcoffout_begin_block (file, last_linenum, next_block_index); 216418334Speter#endif 216518334Speter#ifdef DBX_DEBUGGING_INFO 216618334Speter if (write_symbols == DBX_DEBUG) 216718334Speter ASM_OUTPUT_INTERNAL_LABEL (file, "LBB", next_block_index); 216818334Speter#endif 216918334Speter#ifdef DWARF_DEBUGGING_INFO 217050503Sobrien if (write_symbols == DWARF_DEBUG) 217118334Speter dwarfout_begin_block (next_block_index); 217218334Speter#endif 217350503Sobrien#ifdef DWARF2_DEBUGGING_INFO 217450503Sobrien if (write_symbols == DWARF2_DEBUG) 217550503Sobrien dwarf2out_begin_block (next_block_index); 217650503Sobrien#endif 217718334Speter 217818334Speter next_block_index++; 217918334Speter } 218018334Speter else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END 218118334Speter && (debug_info_level == DINFO_LEVEL_NORMAL 218218334Speter || debug_info_level == DINFO_LEVEL_VERBOSE 218318334Speter || write_symbols == DWARF_DEBUG 218450503Sobrien || write_symbols == DWARF2_DEBUG)) 218518334Speter { 218618334Speter /* End of a symbol-block. Pop its sequence number off 218718334Speter PENDING_BLOCKS and output debugging info based on that. */ 218818334Speter 218918334Speter --block_depth; 219018334Speter 219118334Speter#ifdef XCOFF_DEBUGGING_INFO 219218334Speter if (write_symbols == XCOFF_DEBUG && block_depth >= 0) 219318334Speter xcoffout_end_block (file, high_block_linenum, 219418334Speter pending_blocks[block_depth]); 219518334Speter#endif 219618334Speter#ifdef DBX_DEBUGGING_INFO 219718334Speter if (write_symbols == DBX_DEBUG && block_depth >= 0) 219818334Speter ASM_OUTPUT_INTERNAL_LABEL (file, "LBE", 219918334Speter pending_blocks[block_depth]); 220018334Speter#endif 220118334Speter#ifdef SDB_DEBUGGING_INFO 220218334Speter if (write_symbols == SDB_DEBUG && block_depth >= 0) 220318334Speter sdbout_end_block (file, high_block_linenum, 220418334Speter pending_blocks[block_depth]); 220518334Speter#endif 220618334Speter#ifdef DWARF_DEBUGGING_INFO 220750503Sobrien if (write_symbols == DWARF_DEBUG && block_depth >= 0) 220818334Speter dwarfout_end_block (pending_blocks[block_depth]); 220918334Speter#endif 221050503Sobrien#ifdef DWARF2_DEBUGGING_INFO 221150503Sobrien if (write_symbols == DWARF2_DEBUG && block_depth >= 0) 221250503Sobrien dwarf2out_end_block (pending_blocks[block_depth]); 221350503Sobrien#endif 221418334Speter } 221518334Speter else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL 221618334Speter && (debug_info_level == DINFO_LEVEL_NORMAL 221718334Speter || debug_info_level == DINFO_LEVEL_VERBOSE)) 221818334Speter { 221918334Speter#ifdef DWARF_DEBUGGING_INFO 222018334Speter if (write_symbols == DWARF_DEBUG) 222118334Speter dwarfout_label (insn); 222218334Speter#endif 222350503Sobrien#ifdef DWARF2_DEBUGGING_INFO 222450503Sobrien if (write_symbols == DWARF2_DEBUG) 222550503Sobrien dwarf2out_label (insn); 222650503Sobrien#endif 222718334Speter } 222818334Speter else if (NOTE_LINE_NUMBER (insn) > 0) 222918334Speter /* This note is a line-number. */ 223018334Speter { 223118334Speter register rtx note; 223218334Speter 223318334Speter#if 0 /* This is what we used to do. */ 223418334Speter output_source_line (file, insn); 223518334Speter#endif 223618334Speter int note_after = 0; 223718334Speter 223818334Speter /* If there is anything real after this note, 223918334Speter output it. If another line note follows, omit this one. */ 224018334Speter for (note = NEXT_INSN (insn); note; note = NEXT_INSN (note)) 224118334Speter { 224218334Speter if (GET_CODE (note) != NOTE && GET_CODE (note) != CODE_LABEL) 224318334Speter break; 224418334Speter /* These types of notes can be significant 224518334Speter so make sure the preceding line number stays. */ 224618334Speter else if (GET_CODE (note) == NOTE 224718334Speter && (NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_BEG 224818334Speter || NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_END 224918334Speter || NOTE_LINE_NUMBER (note) == NOTE_INSN_FUNCTION_BEG)) 225018334Speter break; 225118334Speter else if (GET_CODE (note) == NOTE && NOTE_LINE_NUMBER (note) > 0) 225218334Speter { 225318334Speter /* Another line note follows; we can delete this note 225418334Speter if no intervening line numbers have notes elsewhere. */ 225518334Speter int num; 225618334Speter for (num = NOTE_LINE_NUMBER (insn) + 1; 225718334Speter num < NOTE_LINE_NUMBER (note); 225818334Speter num++) 225918334Speter if (line_note_exists[num]) 226018334Speter break; 226118334Speter 226218334Speter if (num >= NOTE_LINE_NUMBER (note)) 226318334Speter note_after = 1; 226418334Speter break; 226518334Speter } 226618334Speter } 226718334Speter 226818334Speter /* Output this line note 226918334Speter if it is the first or the last line note in a row. */ 227018334Speter if (!note_after) 227118334Speter output_source_line (file, insn); 227218334Speter } 227318334Speter break; 227418334Speter 227518334Speter case BARRIER: 227650503Sobrien#if defined (DWARF2_UNWIND_INFO) && !defined (ACCUMULATE_OUTGOING_ARGS) 227750503Sobrien /* If we push arguments, we need to check all insns for stack 227850503Sobrien adjustments. */ 227950503Sobrien if (dwarf2out_do_frame ()) 228050503Sobrien dwarf2out_frame_debug (insn); 228118334Speter#endif 228218334Speter break; 228318334Speter 228418334Speter case CODE_LABEL: 228550503Sobrien /* The target port might emit labels in the output function for 228650503Sobrien some insn, e.g. sh.c output_branchy_insn. */ 228750503Sobrien if (CODE_LABEL_NUMBER (insn) <= max_labelno) 228850503Sobrien { 228950503Sobrien int align = LABEL_TO_ALIGNMENT (insn); 229050503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN 229150503Sobrien int max_skip = LABEL_TO_MAX_SKIP (insn); 229250503Sobrien#endif 229350503Sobrien 229450503Sobrien if (align && NEXT_INSN (insn)) 229550503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN 229650503Sobrien ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip); 229750503Sobrien#else 229850503Sobrien ASM_OUTPUT_ALIGN (file, align); 229950503Sobrien#endif 230050503Sobrien } 230118334Speter CC_STATUS_INIT; 230218334Speter if (prescan > 0) 230318334Speter break; 230418334Speter new_block = 1; 230550503Sobrien 230650503Sobrien#ifdef FINAL_PRESCAN_LABEL 230750503Sobrien FINAL_PRESCAN_INSN (insn, NULL_PTR, 0); 230850503Sobrien#endif 230950503Sobrien 231018334Speter#ifdef SDB_DEBUGGING_INFO 231118334Speter if (write_symbols == SDB_DEBUG && LABEL_NAME (insn)) 231218334Speter sdbout_label (insn); 231318334Speter#endif 231418334Speter#ifdef DWARF_DEBUGGING_INFO 231518334Speter if (write_symbols == DWARF_DEBUG && LABEL_NAME (insn)) 231618334Speter dwarfout_label (insn); 231718334Speter#endif 231850503Sobrien#ifdef DWARF2_DEBUGGING_INFO 231950503Sobrien if (write_symbols == DWARF2_DEBUG && LABEL_NAME (insn)) 232050503Sobrien dwarf2out_label (insn); 232150503Sobrien#endif 232218334Speter if (app_on) 232318334Speter { 232450503Sobrien fputs (ASM_APP_OFF, file); 232518334Speter app_on = 0; 232618334Speter } 232718334Speter if (NEXT_INSN (insn) != 0 232818334Speter && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN) 232918334Speter { 233018334Speter rtx nextbody = PATTERN (NEXT_INSN (insn)); 233118334Speter 233218334Speter /* If this label is followed by a jump-table, 233318334Speter make sure we put the label in the read-only section. Also 233418334Speter possibly write the label and jump table together. */ 233518334Speter 233618334Speter if (GET_CODE (nextbody) == ADDR_VEC 233718334Speter || GET_CODE (nextbody) == ADDR_DIFF_VEC) 233818334Speter { 233950503Sobrien if (! JUMP_TABLES_IN_TEXT_SECTION) 234050503Sobrien { 234150503Sobrien readonly_data_section (); 234218334Speter#ifdef READONLY_DATA_SECTION 234350503Sobrien ASM_OUTPUT_ALIGN (file, 234450503Sobrien exact_log2 (BIGGEST_ALIGNMENT 234550503Sobrien / BITS_PER_UNIT)); 234618334Speter#endif /* READONLY_DATA_SECTION */ 234750503Sobrien } 234850503Sobrien else 234950503Sobrien function_section (current_function_decl); 235050503Sobrien 235118334Speter#ifdef ASM_OUTPUT_CASE_LABEL 235218334Speter ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), 235318334Speter NEXT_INSN (insn)); 235418334Speter#else 235518334Speter ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); 235618334Speter#endif 235718334Speter break; 235818334Speter } 235918334Speter } 236018334Speter 236118334Speter ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); 236218334Speter break; 236318334Speter 236418334Speter default: 236518334Speter { 236618334Speter register rtx body = PATTERN (insn); 236718334Speter int insn_code_number; 236818334Speter char *template; 236950503Sobrien#ifdef HAVE_cc0 237018334Speter rtx note; 237150503Sobrien#endif 237218334Speter 237318334Speter /* An INSN, JUMP_INSN or CALL_INSN. 237418334Speter First check for special kinds that recog doesn't recognize. */ 237518334Speter 237618334Speter if (GET_CODE (body) == USE /* These are just declarations */ 237718334Speter || GET_CODE (body) == CLOBBER) 237818334Speter break; 237918334Speter 238018334Speter#ifdef HAVE_cc0 238118334Speter /* If there is a REG_CC_SETTER note on this insn, it means that 238218334Speter the setting of the condition code was done in the delay slot 238318334Speter of the insn that branched here. So recover the cc status 238418334Speter from the insn that set it. */ 238518334Speter 238618334Speter note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX); 238718334Speter if (note) 238818334Speter { 238918334Speter NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0)); 239018334Speter cc_prev_status = cc_status; 239118334Speter } 239218334Speter#endif 239318334Speter 239418334Speter /* Detect insns that are really jump-tables 239518334Speter and output them as such. */ 239618334Speter 239718334Speter if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) 239818334Speter { 239918334Speter register int vlen, idx; 240018334Speter 240118334Speter if (prescan > 0) 240218334Speter break; 240318334Speter 240418334Speter if (app_on) 240518334Speter { 240650503Sobrien fputs (ASM_APP_OFF, file); 240718334Speter app_on = 0; 240818334Speter } 240918334Speter 241018334Speter vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC); 241118334Speter for (idx = 0; idx < vlen; idx++) 241218334Speter { 241318334Speter if (GET_CODE (body) == ADDR_VEC) 241418334Speter { 241518334Speter#ifdef ASM_OUTPUT_ADDR_VEC_ELT 241618334Speter ASM_OUTPUT_ADDR_VEC_ELT 241718334Speter (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0))); 241818334Speter#else 241918334Speter abort (); 242018334Speter#endif 242118334Speter } 242218334Speter else 242318334Speter { 242418334Speter#ifdef ASM_OUTPUT_ADDR_DIFF_ELT 242518334Speter ASM_OUTPUT_ADDR_DIFF_ELT 242618334Speter (file, 242750503Sobrien body, 242818334Speter CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)), 242918334Speter CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0))); 243018334Speter#else 243118334Speter abort (); 243218334Speter#endif 243318334Speter } 243418334Speter } 243518334Speter#ifdef ASM_OUTPUT_CASE_END 243618334Speter ASM_OUTPUT_CASE_END (file, 243718334Speter CODE_LABEL_NUMBER (PREV_INSN (insn)), 243818334Speter insn); 243918334Speter#endif 244018334Speter 244118334Speter function_section (current_function_decl); 244218334Speter 244318334Speter break; 244418334Speter } 244518334Speter 244618334Speter /* Do basic-block profiling when we reach a new block. 244718334Speter Done here to avoid jump tables. */ 244818334Speter if (profile_block_flag && new_block) 244918334Speter add_bb (file); 245018334Speter 245118334Speter if (GET_CODE (body) == ASM_INPUT) 245218334Speter { 245318334Speter /* There's no telling what that did to the condition codes. */ 245418334Speter CC_STATUS_INIT; 245518334Speter if (prescan > 0) 245618334Speter break; 245718334Speter if (! app_on) 245818334Speter { 245950503Sobrien fputs (ASM_APP_ON, file); 246018334Speter app_on = 1; 246118334Speter } 246218334Speter fprintf (asm_out_file, "\t%s\n", XSTR (body, 0)); 246318334Speter break; 246418334Speter } 246518334Speter 246618334Speter /* Detect `asm' construct with operands. */ 246718334Speter if (asm_noperands (body) >= 0) 246818334Speter { 246950503Sobrien unsigned int noperands = asm_noperands (body); 247018334Speter rtx *ops = (rtx *) alloca (noperands * sizeof (rtx)); 247118334Speter char *string; 247218334Speter 247318334Speter /* There's no telling what that did to the condition codes. */ 247418334Speter CC_STATUS_INIT; 247518334Speter if (prescan > 0) 247618334Speter break; 247718334Speter 247818334Speter if (! app_on) 247918334Speter { 248050503Sobrien fputs (ASM_APP_ON, file); 248118334Speter app_on = 1; 248218334Speter } 248318334Speter 248418334Speter /* Get out the operand values. */ 248518334Speter string = decode_asm_operands (body, ops, NULL_PTR, 248618334Speter NULL_PTR, NULL_PTR); 248718334Speter /* Inhibit aborts on what would otherwise be compiler bugs. */ 248818334Speter insn_noperands = noperands; 248918334Speter this_is_asm_operands = insn; 249018334Speter 249118334Speter /* Output the insn using them. */ 249218334Speter output_asm_insn (string, ops); 249318334Speter this_is_asm_operands = 0; 249418334Speter break; 249518334Speter } 249618334Speter 249718334Speter if (prescan <= 0 && app_on) 249818334Speter { 249950503Sobrien fputs (ASM_APP_OFF, file); 250018334Speter app_on = 0; 250118334Speter } 250218334Speter 250318334Speter if (GET_CODE (body) == SEQUENCE) 250418334Speter { 250518334Speter /* A delayed-branch sequence */ 250618334Speter register int i; 250718334Speter rtx next; 250818334Speter 250918334Speter if (prescan > 0) 251018334Speter break; 251118334Speter final_sequence = body; 251218334Speter 251318334Speter /* The first insn in this SEQUENCE might be a JUMP_INSN that will 251418334Speter force the restoration of a comparison that was previously 251518334Speter thought unnecessary. If that happens, cancel this sequence 251618334Speter and cause that insn to be restored. */ 251718334Speter 251818334Speter next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1); 251918334Speter if (next != XVECEXP (body, 0, 1)) 252018334Speter { 252118334Speter final_sequence = 0; 252218334Speter return next; 252318334Speter } 252418334Speter 252518334Speter for (i = 1; i < XVECLEN (body, 0); i++) 252618334Speter { 252718334Speter rtx insn = XVECEXP (body, 0, i); 252818334Speter rtx next = NEXT_INSN (insn); 252918334Speter /* We loop in case any instruction in a delay slot gets 253018334Speter split. */ 253118334Speter do 253218334Speter insn = final_scan_insn (insn, file, 0, prescan, 1); 253318334Speter while (insn != next); 253418334Speter } 253518334Speter#ifdef DBR_OUTPUT_SEQEND 253618334Speter DBR_OUTPUT_SEQEND (file); 253718334Speter#endif 253818334Speter final_sequence = 0; 253918334Speter 254018334Speter /* If the insn requiring the delay slot was a CALL_INSN, the 254118334Speter insns in the delay slot are actually executed before the 254218334Speter called function. Hence we don't preserve any CC-setting 254318334Speter actions in these insns and the CC must be marked as being 254418334Speter clobbered by the function. */ 254518334Speter if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN) 254650503Sobrien { 254750503Sobrien CC_STATUS_INIT; 254850503Sobrien } 254918334Speter 255018334Speter /* Following a conditional branch sequence, we have a new basic 255118334Speter block. */ 255218334Speter if (profile_block_flag) 255318334Speter { 255418334Speter rtx insn = XVECEXP (body, 0, 0); 255518334Speter rtx body = PATTERN (insn); 255618334Speter 255718334Speter if ((GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET 255818334Speter && GET_CODE (SET_SRC (body)) != LABEL_REF) 255918334Speter || (GET_CODE (insn) == JUMP_INSN 256018334Speter && GET_CODE (body) == PARALLEL 256118334Speter && GET_CODE (XVECEXP (body, 0, 0)) == SET 256218334Speter && GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF)) 256318334Speter new_block = 1; 256418334Speter } 256518334Speter break; 256618334Speter } 256718334Speter 256818334Speter /* We have a real machine instruction as rtl. */ 256918334Speter 257018334Speter body = PATTERN (insn); 257118334Speter 257218334Speter#ifdef HAVE_cc0 257350503Sobrien set = single_set(insn); 257450503Sobrien 257518334Speter /* Check for redundant test and compare instructions 257618334Speter (when the condition codes are already set up as desired). 257718334Speter This is done only when optimizing; if not optimizing, 257818334Speter it should be possible for the user to alter a variable 257918334Speter with the debugger in between statements 258018334Speter and the next statement should reexamine the variable 258118334Speter to compute the condition codes. */ 258218334Speter 258350503Sobrien if (optimize) 258418334Speter { 258550503Sobrien#if 0 258650503Sobrien rtx set = single_set(insn); 258750503Sobrien#endif 258850503Sobrien 258950503Sobrien if (set 259050503Sobrien && GET_CODE (SET_DEST (set)) == CC0 259150503Sobrien && insn != last_ignored_compare) 259218334Speter { 259350503Sobrien if (GET_CODE (SET_SRC (set)) == SUBREG) 259450503Sobrien SET_SRC (set) = alter_subreg (SET_SRC (set)); 259550503Sobrien else if (GET_CODE (SET_SRC (set)) == COMPARE) 259618334Speter { 259750503Sobrien if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG) 259850503Sobrien XEXP (SET_SRC (set), 0) 259950503Sobrien = alter_subreg (XEXP (SET_SRC (set), 0)); 260050503Sobrien if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG) 260150503Sobrien XEXP (SET_SRC (set), 1) 260250503Sobrien = alter_subreg (XEXP (SET_SRC (set), 1)); 260318334Speter } 260450503Sobrien if ((cc_status.value1 != 0 260550503Sobrien && rtx_equal_p (SET_SRC (set), cc_status.value1)) 260650503Sobrien || (cc_status.value2 != 0 260750503Sobrien && rtx_equal_p (SET_SRC (set), cc_status.value2))) 260850503Sobrien { 260950503Sobrien /* Don't delete insn if it has an addressing side-effect. */ 261050503Sobrien if (! FIND_REG_INC_NOTE (insn, 0) 261150503Sobrien /* or if anything in it is volatile. */ 261250503Sobrien && ! volatile_refs_p (PATTERN (insn))) 261350503Sobrien { 261450503Sobrien /* We don't really delete the insn; just ignore it. */ 261550503Sobrien last_ignored_compare = insn; 261650503Sobrien break; 261750503Sobrien } 261850503Sobrien } 261918334Speter } 262018334Speter } 262118334Speter#endif 262218334Speter 262318334Speter /* Following a conditional branch, we have a new basic block. 262418334Speter But if we are inside a sequence, the new block starts after the 262518334Speter last insn of the sequence. */ 262618334Speter if (profile_block_flag && final_sequence == 0 262718334Speter && ((GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET 262818334Speter && GET_CODE (SET_SRC (body)) != LABEL_REF) 262918334Speter || (GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == PARALLEL 263018334Speter && GET_CODE (XVECEXP (body, 0, 0)) == SET 263118334Speter && GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF))) 263218334Speter new_block = 1; 263318334Speter 263418334Speter#ifndef STACK_REGS 263518334Speter /* Don't bother outputting obvious no-ops, even without -O. 263618334Speter This optimization is fast and doesn't interfere with debugging. 263718334Speter Don't do this if the insn is in a delay slot, since this 263818334Speter will cause an improper number of delay insns to be written. */ 263918334Speter if (final_sequence == 0 264018334Speter && prescan >= 0 264118334Speter && GET_CODE (insn) == INSN && GET_CODE (body) == SET 264218334Speter && GET_CODE (SET_SRC (body)) == REG 264318334Speter && GET_CODE (SET_DEST (body)) == REG 264418334Speter && REGNO (SET_SRC (body)) == REGNO (SET_DEST (body))) 264518334Speter break; 264618334Speter#endif 264718334Speter 264818334Speter#ifdef HAVE_cc0 264918334Speter /* If this is a conditional branch, maybe modify it 265018334Speter if the cc's are in a nonstandard state 265118334Speter so that it accomplishes the same thing that it would 265218334Speter do straightforwardly if the cc's were set up normally. */ 265318334Speter 265418334Speter if (cc_status.flags != 0 265518334Speter && GET_CODE (insn) == JUMP_INSN 265618334Speter && GET_CODE (body) == SET 265718334Speter && SET_DEST (body) == pc_rtx 265818334Speter && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE 265918334Speter && GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (body), 0))) == '<' 266018334Speter && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx 266118334Speter /* This is done during prescan; it is not done again 266218334Speter in final scan when prescan has been done. */ 266318334Speter && prescan >= 0) 266418334Speter { 266518334Speter /* This function may alter the contents of its argument 266618334Speter and clear some of the cc_status.flags bits. 266718334Speter It may also return 1 meaning condition now always true 266818334Speter or -1 meaning condition now always false 266918334Speter or 2 meaning condition nontrivial but altered. */ 267018334Speter register int result = alter_cond (XEXP (SET_SRC (body), 0)); 267118334Speter /* If condition now has fixed value, replace the IF_THEN_ELSE 267218334Speter with its then-operand or its else-operand. */ 267318334Speter if (result == 1) 267418334Speter SET_SRC (body) = XEXP (SET_SRC (body), 1); 267518334Speter if (result == -1) 267618334Speter SET_SRC (body) = XEXP (SET_SRC (body), 2); 267718334Speter 267818334Speter /* The jump is now either unconditional or a no-op. 267918334Speter If it has become a no-op, don't try to output it. 268018334Speter (It would not be recognized.) */ 268118334Speter if (SET_SRC (body) == pc_rtx) 268218334Speter { 268318334Speter PUT_CODE (insn, NOTE); 268418334Speter NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; 268518334Speter NOTE_SOURCE_FILE (insn) = 0; 268618334Speter break; 268718334Speter } 268818334Speter else if (GET_CODE (SET_SRC (body)) == RETURN) 268918334Speter /* Replace (set (pc) (return)) with (return). */ 269018334Speter PATTERN (insn) = body = SET_SRC (body); 269118334Speter 269218334Speter /* Rerecognize the instruction if it has changed. */ 269318334Speter if (result != 0) 269418334Speter INSN_CODE (insn) = -1; 269518334Speter } 269618334Speter 269718334Speter /* Make same adjustments to instructions that examine the 269850503Sobrien condition codes without jumping and instructions that 269950503Sobrien handle conditional moves (if this machine has either one). */ 270018334Speter 270118334Speter if (cc_status.flags != 0 270250503Sobrien && set != 0) 270318334Speter { 270450503Sobrien rtx cond_rtx, then_rtx, else_rtx; 270550503Sobrien 270650503Sobrien if (GET_CODE (insn) != JUMP_INSN 270750503Sobrien && GET_CODE (SET_SRC (set)) == IF_THEN_ELSE) 270818334Speter { 270950503Sobrien cond_rtx = XEXP (SET_SRC (set), 0); 271050503Sobrien then_rtx = XEXP (SET_SRC (set), 1); 271150503Sobrien else_rtx = XEXP (SET_SRC (set), 2); 271250503Sobrien } 271350503Sobrien else 271450503Sobrien { 271550503Sobrien cond_rtx = SET_SRC (set); 271650503Sobrien then_rtx = const_true_rtx; 271750503Sobrien else_rtx = const0_rtx; 271850503Sobrien } 271950503Sobrien 272050503Sobrien switch (GET_CODE (cond_rtx)) 272150503Sobrien { 272218334Speter case GTU: 272318334Speter case GT: 272418334Speter case LTU: 272518334Speter case LT: 272618334Speter case GEU: 272718334Speter case GE: 272818334Speter case LEU: 272918334Speter case LE: 273018334Speter case EQ: 273118334Speter case NE: 273218334Speter { 273318334Speter register int result; 273450503Sobrien if (XEXP (cond_rtx, 0) != cc0_rtx) 273518334Speter break; 273650503Sobrien result = alter_cond (cond_rtx); 273718334Speter if (result == 1) 273850503Sobrien validate_change (insn, &SET_SRC (set), then_rtx, 0); 273918334Speter else if (result == -1) 274050503Sobrien validate_change (insn, &SET_SRC (set), else_rtx, 0); 274118334Speter else if (result == 2) 274218334Speter INSN_CODE (insn) = -1; 274350503Sobrien if (SET_DEST (set) == SET_SRC (set)) 274450503Sobrien { 274550503Sobrien PUT_CODE (insn, NOTE); 274650503Sobrien NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; 274750503Sobrien NOTE_SOURCE_FILE (insn) = 0; 274850503Sobrien } 274918334Speter } 275050503Sobrien break; 275150503Sobrien 275250503Sobrien default: 275350503Sobrien break; 275418334Speter } 275518334Speter } 275650503Sobrien 275718334Speter#endif 275818334Speter 275918334Speter /* Do machine-specific peephole optimizations if desired. */ 276018334Speter 276118334Speter if (optimize && !flag_no_peephole && !nopeepholes) 276218334Speter { 276318334Speter rtx next = peephole (insn); 276418334Speter /* When peepholing, if there were notes within the peephole, 276518334Speter emit them before the peephole. */ 276618334Speter if (next != 0 && next != NEXT_INSN (insn)) 276718334Speter { 276818334Speter rtx prev = PREV_INSN (insn); 276918334Speter rtx note; 277018334Speter 277118334Speter for (note = NEXT_INSN (insn); note != next; 277218334Speter note = NEXT_INSN (note)) 277318334Speter final_scan_insn (note, file, optimize, prescan, nopeepholes); 277418334Speter 277518334Speter /* In case this is prescan, put the notes 277618334Speter in proper position for later rescan. */ 277718334Speter note = NEXT_INSN (insn); 277818334Speter PREV_INSN (note) = prev; 277918334Speter NEXT_INSN (prev) = note; 278018334Speter NEXT_INSN (PREV_INSN (next)) = insn; 278118334Speter PREV_INSN (insn) = PREV_INSN (next); 278218334Speter NEXT_INSN (insn) = next; 278318334Speter PREV_INSN (next) = insn; 278418334Speter } 278518334Speter 278618334Speter /* PEEPHOLE might have changed this. */ 278718334Speter body = PATTERN (insn); 278818334Speter } 278918334Speter 279018334Speter /* Try to recognize the instruction. 279118334Speter If successful, verify that the operands satisfy the 279218334Speter constraints for the instruction. Crash if they don't, 279318334Speter since `reload' should have changed them so that they do. */ 279418334Speter 279518334Speter insn_code_number = recog_memoized (insn); 279618334Speter insn_extract (insn); 279718334Speter for (i = 0; i < insn_n_operands[insn_code_number]; i++) 279818334Speter { 279918334Speter if (GET_CODE (recog_operand[i]) == SUBREG) 280018334Speter recog_operand[i] = alter_subreg (recog_operand[i]); 280118334Speter else if (GET_CODE (recog_operand[i]) == PLUS 280218334Speter || GET_CODE (recog_operand[i]) == MULT) 280318334Speter recog_operand[i] = walk_alter_subreg (recog_operand[i]); 280418334Speter } 280518334Speter 280618334Speter for (i = 0; i < insn_n_dups[insn_code_number]; i++) 280718334Speter { 280818334Speter if (GET_CODE (*recog_dup_loc[i]) == SUBREG) 280918334Speter *recog_dup_loc[i] = alter_subreg (*recog_dup_loc[i]); 281018334Speter else if (GET_CODE (*recog_dup_loc[i]) == PLUS 281118334Speter || GET_CODE (*recog_dup_loc[i]) == MULT) 281218334Speter *recog_dup_loc[i] = walk_alter_subreg (*recog_dup_loc[i]); 281318334Speter } 281418334Speter 281518334Speter#ifdef REGISTER_CONSTRAINTS 281618334Speter if (! constrain_operands (insn_code_number, 1)) 281718334Speter fatal_insn_not_found (insn); 281818334Speter#endif 281918334Speter 282018334Speter /* Some target machines need to prescan each insn before 282118334Speter it is output. */ 282218334Speter 282318334Speter#ifdef FINAL_PRESCAN_INSN 282418334Speter FINAL_PRESCAN_INSN (insn, recog_operand, 282518334Speter insn_n_operands[insn_code_number]); 282618334Speter#endif 282718334Speter 282818334Speter#ifdef HAVE_cc0 282918334Speter cc_prev_status = cc_status; 283018334Speter 283118334Speter /* Update `cc_status' for this instruction. 283218334Speter The instruction's output routine may change it further. 283318334Speter If the output routine for a jump insn needs to depend 283418334Speter on the cc status, it should look at cc_prev_status. */ 283518334Speter 283618334Speter NOTICE_UPDATE_CC (body, insn); 283718334Speter#endif 283818334Speter 283918334Speter debug_insn = insn; 284018334Speter 284150503Sobrien#if defined (DWARF2_UNWIND_INFO) && !defined (ACCUMULATE_OUTGOING_ARGS) 284250503Sobrien /* If we push arguments, we want to know where the calls are. */ 284350503Sobrien if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ()) 284450503Sobrien dwarf2out_frame_debug (insn); 284550503Sobrien#endif 284650503Sobrien 284718334Speter /* If the proper template needs to be chosen by some C code, 284818334Speter run that code and get the real template. */ 284918334Speter 285018334Speter template = insn_template[insn_code_number]; 285118334Speter if (template == 0) 285218334Speter { 285318334Speter template = (*insn_outfun[insn_code_number]) (recog_operand, insn); 285418334Speter 285518334Speter /* If the C code returns 0, it means that it is a jump insn 285618334Speter which follows a deleted test insn, and that test insn 285718334Speter needs to be reinserted. */ 285818334Speter if (template == 0) 285918334Speter { 286018334Speter if (prev_nonnote_insn (insn) != last_ignored_compare) 286118334Speter abort (); 286218334Speter new_block = 0; 286318334Speter return prev_nonnote_insn (insn); 286418334Speter } 286518334Speter } 286618334Speter 286718334Speter /* If the template is the string "#", it means that this insn must 286818334Speter be split. */ 286918334Speter if (template[0] == '#' && template[1] == '\0') 287018334Speter { 287118334Speter rtx new = try_split (body, insn, 0); 287218334Speter 287318334Speter /* If we didn't split the insn, go away. */ 287418334Speter if (new == insn && PATTERN (new) == body) 287550503Sobrien fatal_insn ("Could not split insn", insn); 287618334Speter 287750503Sobrien#ifdef HAVE_ATTR_length 287850503Sobrien /* This instruction should have been split in shorten_branches, 287950503Sobrien to ensure that we would have valid length info for the 288050503Sobrien splitees. */ 288150503Sobrien abort (); 288250503Sobrien#endif 288350503Sobrien 288418334Speter new_block = 0; 288518334Speter return new; 288618334Speter } 288718334Speter 288818334Speter if (prescan > 0) 288918334Speter break; 289018334Speter 289118334Speter /* Output assembler code from the template. */ 289218334Speter 289318334Speter output_asm_insn (template, recog_operand); 289418334Speter 289550503Sobrien#if defined (DWARF2_UNWIND_INFO) 289650503Sobrien#if !defined (ACCUMULATE_OUTGOING_ARGS) 289750503Sobrien /* If we push arguments, we need to check all insns for stack 289850503Sobrien adjustments. */ 289950503Sobrien if (GET_CODE (insn) == INSN && dwarf2out_do_frame ()) 290050503Sobrien dwarf2out_frame_debug (insn); 290150503Sobrien#else 290250503Sobrien#if defined (HAVE_prologue) 290350503Sobrien /* If this insn is part of the prologue, emit DWARF v2 290450503Sobrien call frame info. */ 290550503Sobrien if (RTX_FRAME_RELATED_P (insn) && dwarf2out_do_frame ()) 290650503Sobrien dwarf2out_frame_debug (insn); 290750503Sobrien#endif 290850503Sobrien#endif 290950503Sobrien#endif 291050503Sobrien 291118334Speter#if 0 291218334Speter /* It's not at all clear why we did this and doing so interferes 291318334Speter with tests we'd like to do to use REG_WAS_0 notes, so let's try 291418334Speter with this out. */ 291518334Speter 291618334Speter /* Mark this insn as having been output. */ 291718334Speter INSN_DELETED_P (insn) = 1; 291818334Speter#endif 291918334Speter 292018334Speter debug_insn = 0; 292118334Speter } 292218334Speter } 292318334Speter return NEXT_INSN (insn); 292418334Speter} 292518334Speter 292618334Speter/* Output debugging info to the assembler file FILE 292718334Speter based on the NOTE-insn INSN, assumed to be a line number. */ 292818334Speter 292918334Speterstatic void 293018334Speteroutput_source_line (file, insn) 293118334Speter FILE *file; 293218334Speter rtx insn; 293318334Speter{ 293418334Speter register char *filename = NOTE_SOURCE_FILE (insn); 293518334Speter 293618334Speter /* Remember filename for basic block profiling. 293718334Speter Filenames are allocated on the permanent obstack 293818334Speter or are passed in ARGV, so we don't have to save 293918334Speter the string. */ 294018334Speter 294118334Speter if (profile_block_flag && last_filename != filename) 294218334Speter bb_file_label_num = add_bb_string (filename, TRUE); 294318334Speter 294418334Speter last_filename = filename; 294518334Speter last_linenum = NOTE_LINE_NUMBER (insn); 294618334Speter high_block_linenum = MAX (last_linenum, high_block_linenum); 294718334Speter high_function_linenum = MAX (last_linenum, high_function_linenum); 294818334Speter 294918334Speter if (write_symbols != NO_DEBUG) 295018334Speter { 295118334Speter#ifdef SDB_DEBUGGING_INFO 295218334Speter if (write_symbols == SDB_DEBUG 295318334Speter#if 0 /* People like having line numbers even in wrong file! */ 295418334Speter /* COFF can't handle multiple source files--lose, lose. */ 295518334Speter && !strcmp (filename, main_input_filename) 295618334Speter#endif 295718334Speter /* COFF relative line numbers must be positive. */ 295818334Speter && last_linenum > sdb_begin_function_line) 295918334Speter { 296018334Speter#ifdef ASM_OUTPUT_SOURCE_LINE 296118334Speter ASM_OUTPUT_SOURCE_LINE (file, last_linenum); 296218334Speter#else 296318334Speter fprintf (file, "\t.ln\t%d\n", 296418334Speter ((sdb_begin_function_line > -1) 296518334Speter ? last_linenum - sdb_begin_function_line : 1)); 296618334Speter#endif 296718334Speter } 296818334Speter#endif 296918334Speter 297018334Speter#if defined (DBX_DEBUGGING_INFO) 297118334Speter if (write_symbols == DBX_DEBUG) 297218334Speter dbxout_source_line (file, filename, NOTE_LINE_NUMBER (insn)); 297318334Speter#endif 297418334Speter 297518334Speter#if defined (XCOFF_DEBUGGING_INFO) 297618334Speter if (write_symbols == XCOFF_DEBUG) 297718334Speter xcoffout_source_line (file, filename, insn); 297818334Speter#endif 297918334Speter 298018334Speter#ifdef DWARF_DEBUGGING_INFO 298118334Speter if (write_symbols == DWARF_DEBUG) 298218334Speter dwarfout_line (filename, NOTE_LINE_NUMBER (insn)); 298318334Speter#endif 298450503Sobrien 298550503Sobrien#ifdef DWARF2_DEBUGGING_INFO 298650503Sobrien if (write_symbols == DWARF2_DEBUG) 298750503Sobrien dwarf2out_line (filename, NOTE_LINE_NUMBER (insn)); 298850503Sobrien#endif 298918334Speter } 299018334Speter} 299118334Speter 299218334Speter/* If X is a SUBREG, replace it with a REG or a MEM, 299318334Speter based on the thing it is a subreg of. */ 299418334Speter 299518334Speterrtx 299618334Speteralter_subreg (x) 299718334Speter register rtx x; 299818334Speter{ 299918334Speter register rtx y = SUBREG_REG (x); 300050503Sobrien 300118334Speter if (GET_CODE (y) == SUBREG) 300218334Speter y = alter_subreg (y); 300318334Speter 300450503Sobrien /* If reload is operating, we may be replacing inside this SUBREG. 300550503Sobrien Check for that and make a new one if so. */ 300650503Sobrien if (reload_in_progress && find_replacement (&SUBREG_REG (x)) != 0) 300750503Sobrien x = copy_rtx (x); 300850503Sobrien 300918334Speter if (GET_CODE (y) == REG) 301018334Speter { 301150503Sobrien /* If the word size is larger than the size of this register, 301250503Sobrien adjust the register number to compensate. */ 301350503Sobrien /* ??? Note that this just catches stragglers created by/for 301450503Sobrien integrate. It would be better if we either caught these 301550503Sobrien earlier, or kept _all_ subregs until now and eliminate 301650503Sobrien gen_lowpart and friends. */ 301750503Sobrien 301818334Speter PUT_CODE (x, REG); 301950503Sobrien#ifdef ALTER_HARD_SUBREG 302050503Sobrien REGNO (x) = ALTER_HARD_SUBREG(GET_MODE (x), SUBREG_WORD (x), 302150503Sobrien GET_MODE (y), REGNO (y)); 302250503Sobrien#else 302318334Speter REGNO (x) = REGNO (y) + SUBREG_WORD (x); 302450503Sobrien#endif 302518334Speter } 302618334Speter else if (GET_CODE (y) == MEM) 302718334Speter { 302818334Speter register int offset = SUBREG_WORD (x) * UNITS_PER_WORD; 302918334Speter if (BYTES_BIG_ENDIAN) 303018334Speter offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))) 303118334Speter - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y)))); 303218334Speter PUT_CODE (x, MEM); 303318334Speter MEM_VOLATILE_P (x) = MEM_VOLATILE_P (y); 303450503Sobrien MEM_IN_STRUCT_P (x) = MEM_IN_STRUCT_P (y); 303550503Sobrien MEM_ALIAS_SET (x) = MEM_ALIAS_SET (y); 303618334Speter XEXP (x, 0) = plus_constant (XEXP (y, 0), offset); 303718334Speter } 303818334Speter 303918334Speter return x; 304018334Speter} 304118334Speter 304218334Speter/* Do alter_subreg on all the SUBREGs contained in X. */ 304318334Speter 304418334Speterstatic rtx 304518334Speterwalk_alter_subreg (x) 304618334Speter rtx x; 304718334Speter{ 304818334Speter switch (GET_CODE (x)) 304918334Speter { 305018334Speter case PLUS: 305118334Speter case MULT: 305218334Speter XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0)); 305318334Speter XEXP (x, 1) = walk_alter_subreg (XEXP (x, 1)); 305418334Speter break; 305518334Speter 305618334Speter case MEM: 305718334Speter XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0)); 305818334Speter break; 305918334Speter 306018334Speter case SUBREG: 306118334Speter return alter_subreg (x); 306250503Sobrien 306350503Sobrien default: 306450503Sobrien break; 306518334Speter } 306618334Speter 306718334Speter return x; 306818334Speter} 306918334Speter 307018334Speter#ifdef HAVE_cc0 307118334Speter 307218334Speter/* Given BODY, the body of a jump instruction, alter the jump condition 307318334Speter as required by the bits that are set in cc_status.flags. 307418334Speter Not all of the bits there can be handled at this level in all cases. 307518334Speter 307618334Speter The value is normally 0. 307718334Speter 1 means that the condition has become always true. 307818334Speter -1 means that the condition has become always false. 307918334Speter 2 means that COND has been altered. */ 308018334Speter 308118334Speterstatic int 308218334Speteralter_cond (cond) 308318334Speter register rtx cond; 308418334Speter{ 308518334Speter int value = 0; 308618334Speter 308718334Speter if (cc_status.flags & CC_REVERSED) 308818334Speter { 308918334Speter value = 2; 309018334Speter PUT_CODE (cond, swap_condition (GET_CODE (cond))); 309118334Speter } 309218334Speter 309318334Speter if (cc_status.flags & CC_INVERTED) 309418334Speter { 309518334Speter value = 2; 309618334Speter PUT_CODE (cond, reverse_condition (GET_CODE (cond))); 309718334Speter } 309818334Speter 309918334Speter if (cc_status.flags & CC_NOT_POSITIVE) 310018334Speter switch (GET_CODE (cond)) 310118334Speter { 310218334Speter case LE: 310318334Speter case LEU: 310418334Speter case GEU: 310518334Speter /* Jump becomes unconditional. */ 310618334Speter return 1; 310718334Speter 310818334Speter case GT: 310918334Speter case GTU: 311018334Speter case LTU: 311118334Speter /* Jump becomes no-op. */ 311218334Speter return -1; 311318334Speter 311418334Speter case GE: 311518334Speter PUT_CODE (cond, EQ); 311618334Speter value = 2; 311718334Speter break; 311818334Speter 311918334Speter case LT: 312018334Speter PUT_CODE (cond, NE); 312118334Speter value = 2; 312218334Speter break; 312350503Sobrien 312450503Sobrien default: 312550503Sobrien break; 312618334Speter } 312718334Speter 312818334Speter if (cc_status.flags & CC_NOT_NEGATIVE) 312918334Speter switch (GET_CODE (cond)) 313018334Speter { 313118334Speter case GE: 313218334Speter case GEU: 313318334Speter /* Jump becomes unconditional. */ 313418334Speter return 1; 313518334Speter 313618334Speter case LT: 313718334Speter case LTU: 313818334Speter /* Jump becomes no-op. */ 313918334Speter return -1; 314018334Speter 314118334Speter case LE: 314218334Speter case LEU: 314318334Speter PUT_CODE (cond, EQ); 314418334Speter value = 2; 314518334Speter break; 314618334Speter 314718334Speter case GT: 314818334Speter case GTU: 314918334Speter PUT_CODE (cond, NE); 315018334Speter value = 2; 315118334Speter break; 315250503Sobrien 315350503Sobrien default: 315450503Sobrien break; 315518334Speter } 315618334Speter 315718334Speter if (cc_status.flags & CC_NO_OVERFLOW) 315818334Speter switch (GET_CODE (cond)) 315918334Speter { 316018334Speter case GEU: 316118334Speter /* Jump becomes unconditional. */ 316218334Speter return 1; 316318334Speter 316418334Speter case LEU: 316518334Speter PUT_CODE (cond, EQ); 316618334Speter value = 2; 316718334Speter break; 316818334Speter 316918334Speter case GTU: 317018334Speter PUT_CODE (cond, NE); 317118334Speter value = 2; 317218334Speter break; 317318334Speter 317418334Speter case LTU: 317518334Speter /* Jump becomes no-op. */ 317618334Speter return -1; 317750503Sobrien 317850503Sobrien default: 317950503Sobrien break; 318018334Speter } 318118334Speter 318218334Speter if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N)) 318318334Speter switch (GET_CODE (cond)) 318418334Speter { 318550503Sobrien default: 318618334Speter abort (); 318718334Speter 318818334Speter case NE: 318918334Speter PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT); 319018334Speter value = 2; 319118334Speter break; 319218334Speter 319318334Speter case EQ: 319418334Speter PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE); 319518334Speter value = 2; 319618334Speter break; 319718334Speter } 319818334Speter 319918334Speter if (cc_status.flags & CC_NOT_SIGNED) 320018334Speter /* The flags are valid if signed condition operators are converted 320118334Speter to unsigned. */ 320218334Speter switch (GET_CODE (cond)) 320318334Speter { 320418334Speter case LE: 320518334Speter PUT_CODE (cond, LEU); 320618334Speter value = 2; 320718334Speter break; 320818334Speter 320918334Speter case LT: 321018334Speter PUT_CODE (cond, LTU); 321118334Speter value = 2; 321218334Speter break; 321318334Speter 321418334Speter case GT: 321518334Speter PUT_CODE (cond, GTU); 321618334Speter value = 2; 321718334Speter break; 321818334Speter 321918334Speter case GE: 322018334Speter PUT_CODE (cond, GEU); 322118334Speter value = 2; 322218334Speter break; 322350503Sobrien 322450503Sobrien default: 322550503Sobrien break; 322618334Speter } 322718334Speter 322818334Speter return value; 322918334Speter} 323018334Speter#endif 323118334Speter 323218334Speter/* Report inconsistency between the assembler template and the operands. 323318334Speter In an `asm', it's the user's fault; otherwise, the compiler's fault. */ 323418334Speter 323518334Spetervoid 323618334Speteroutput_operand_lossage (str) 323718334Speter char *str; 323818334Speter{ 323918334Speter if (this_is_asm_operands) 324018334Speter error_for_asm (this_is_asm_operands, "invalid `asm': %s", str); 324118334Speter else 324250503Sobrien fatal ("Internal compiler error, output_operand_lossage `%s'", str); 324318334Speter} 324418334Speter 324518334Speter/* Output of assembler code from a template, and its subroutines. */ 324618334Speter 324718334Speter/* Output text from TEMPLATE to the assembler output file, 324818334Speter obeying %-directions to substitute operands taken from 324918334Speter the vector OPERANDS. 325018334Speter 325118334Speter %N (for N a digit) means print operand N in usual manner. 325218334Speter %lN means require operand N to be a CODE_LABEL or LABEL_REF 325318334Speter and print the label name with no punctuation. 325418334Speter %cN means require operand N to be a constant 325518334Speter and print the constant expression with no punctuation. 325618334Speter %aN means expect operand N to be a memory address 325718334Speter (not a memory reference!) and print a reference 325818334Speter to that address. 325918334Speter %nN means expect operand N to be a constant 326018334Speter and print a constant expression for minus the value 326118334Speter of the operand, with no other punctuation. */ 326218334Speter 326318334Speterstatic void 326418334Speteroutput_asm_name () 326518334Speter{ 326618334Speter if (flag_print_asm_name) 326718334Speter { 326818334Speter /* Annotate the assembly with a comment describing the pattern and 326918334Speter alternative used. */ 327018334Speter if (debug_insn) 327118334Speter { 327218334Speter register int num = INSN_CODE (debug_insn); 327318334Speter fprintf (asm_out_file, " %s %d %s", 327418334Speter ASM_COMMENT_START, INSN_UID (debug_insn), insn_name[num]); 327518334Speter if (insn_n_alternatives[num] > 1) 327618334Speter fprintf (asm_out_file, "/%d", which_alternative + 1); 327718334Speter 327818334Speter /* Clear this so only the first assembler insn 327918334Speter of any rtl insn will get the special comment for -dp. */ 328018334Speter debug_insn = 0; 328118334Speter } 328218334Speter } 328318334Speter} 328418334Speter 328518334Spetervoid 328618334Speteroutput_asm_insn (template, operands) 328718334Speter char *template; 328818334Speter rtx *operands; 328918334Speter{ 329018334Speter register char *p; 329150503Sobrien register int c; 329218334Speter 329318334Speter /* An insn may return a null string template 329418334Speter in a case where no assembler code is needed. */ 329518334Speter if (*template == 0) 329618334Speter return; 329718334Speter 329818334Speter p = template; 329918334Speter putc ('\t', asm_out_file); 330018334Speter 330118334Speter#ifdef ASM_OUTPUT_OPCODE 330218334Speter ASM_OUTPUT_OPCODE (asm_out_file, p); 330318334Speter#endif 330418334Speter 330550503Sobrien while ((c = *p++)) 330618334Speter switch (c) 330718334Speter { 330818334Speter case '\n': 330918334Speter output_asm_name (); 331018334Speter putc (c, asm_out_file); 331118334Speter#ifdef ASM_OUTPUT_OPCODE 331218334Speter while ((c = *p) == '\t') 331318334Speter { 331418334Speter putc (c, asm_out_file); 331518334Speter p++; 331618334Speter } 331718334Speter ASM_OUTPUT_OPCODE (asm_out_file, p); 331818334Speter#endif 331918334Speter break; 332018334Speter 332118334Speter#ifdef ASSEMBLER_DIALECT 332218334Speter case '{': 332350503Sobrien { 332450503Sobrien register int i; 332550503Sobrien 332650503Sobrien /* If we want the first dialect, do nothing. Otherwise, skip 332750503Sobrien DIALECT_NUMBER of strings ending with '|'. */ 332850503Sobrien for (i = 0; i < dialect_number; i++) 332950503Sobrien { 333050503Sobrien while (*p && *p++ != '|') 333150503Sobrien ; 333218334Speter 333350503Sobrien if (*p == '|') 333450503Sobrien p++; 333550503Sobrien } 333650503Sobrien } 333718334Speter break; 333818334Speter 333918334Speter case '|': 334018334Speter /* Skip to close brace. */ 334118334Speter while (*p && *p++ != '}') 334218334Speter ; 334318334Speter break; 334418334Speter 334518334Speter case '}': 334618334Speter break; 334718334Speter#endif 334818334Speter 334918334Speter case '%': 335018334Speter /* %% outputs a single %. */ 335118334Speter if (*p == '%') 335218334Speter { 335318334Speter p++; 335418334Speter putc (c, asm_out_file); 335518334Speter } 335618334Speter /* %= outputs a number which is unique to each insn in the entire 335718334Speter compilation. This is useful for making local labels that are 335818334Speter referred to more than once in a given insn. */ 335918334Speter else if (*p == '=') 336018334Speter { 336118334Speter p++; 336218334Speter fprintf (asm_out_file, "%d", insn_counter); 336318334Speter } 336418334Speter /* % followed by a letter and some digits 336518334Speter outputs an operand in a special way depending on the letter. 336618334Speter Letters `acln' are implemented directly. 336718334Speter Other letters are passed to `output_operand' so that 336818334Speter the PRINT_OPERAND macro can define them. */ 336918334Speter else if ((*p >= 'a' && *p <= 'z') 337018334Speter || (*p >= 'A' && *p <= 'Z')) 337118334Speter { 337218334Speter int letter = *p++; 337318334Speter c = atoi (p); 337418334Speter 337518334Speter if (! (*p >= '0' && *p <= '9')) 337618334Speter output_operand_lossage ("operand number missing after %-letter"); 337750503Sobrien else if (this_is_asm_operands && (c < 0 || (unsigned int) c >= insn_noperands)) 337818334Speter output_operand_lossage ("operand number out of range"); 337918334Speter else if (letter == 'l') 338018334Speter output_asm_label (operands[c]); 338118334Speter else if (letter == 'a') 338218334Speter output_address (operands[c]); 338318334Speter else if (letter == 'c') 338418334Speter { 338518334Speter if (CONSTANT_ADDRESS_P (operands[c])) 338618334Speter output_addr_const (asm_out_file, operands[c]); 338718334Speter else 338818334Speter output_operand (operands[c], 'c'); 338918334Speter } 339018334Speter else if (letter == 'n') 339118334Speter { 339218334Speter if (GET_CODE (operands[c]) == CONST_INT) 339350503Sobrien fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, 339418334Speter - INTVAL (operands[c])); 339518334Speter else 339618334Speter { 339718334Speter putc ('-', asm_out_file); 339818334Speter output_addr_const (asm_out_file, operands[c]); 339918334Speter } 340018334Speter } 340118334Speter else 340218334Speter output_operand (operands[c], letter); 340318334Speter 340418334Speter while ((c = *p) >= '0' && c <= '9') p++; 340518334Speter } 340618334Speter /* % followed by a digit outputs an operand the default way. */ 340718334Speter else if (*p >= '0' && *p <= '9') 340818334Speter { 340918334Speter c = atoi (p); 341050503Sobrien if (this_is_asm_operands && (c < 0 || (unsigned int) c >= insn_noperands)) 341118334Speter output_operand_lossage ("operand number out of range"); 341218334Speter else 341318334Speter output_operand (operands[c], 0); 341418334Speter while ((c = *p) >= '0' && c <= '9') p++; 341518334Speter } 341618334Speter /* % followed by punctuation: output something for that 341718334Speter punctuation character alone, with no operand. 341818334Speter The PRINT_OPERAND macro decides what is actually done. */ 341918334Speter#ifdef PRINT_OPERAND_PUNCT_VALID_P 342018334Speter else if (PRINT_OPERAND_PUNCT_VALID_P (*p)) 342118334Speter output_operand (NULL_RTX, *p++); 342218334Speter#endif 342318334Speter else 342418334Speter output_operand_lossage ("invalid %%-code"); 342518334Speter break; 342618334Speter 342718334Speter default: 342818334Speter putc (c, asm_out_file); 342918334Speter } 343018334Speter 343118334Speter output_asm_name (); 343218334Speter 343318334Speter putc ('\n', asm_out_file); 343418334Speter} 343518334Speter 343618334Speter/* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol. */ 343718334Speter 343818334Spetervoid 343918334Speteroutput_asm_label (x) 344018334Speter rtx x; 344118334Speter{ 344218334Speter char buf[256]; 344318334Speter 344418334Speter if (GET_CODE (x) == LABEL_REF) 344518334Speter ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0))); 344618334Speter else if (GET_CODE (x) == CODE_LABEL) 344718334Speter ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); 344818334Speter else 344918334Speter output_operand_lossage ("`%l' operand isn't a label"); 345018334Speter 345118334Speter assemble_name (asm_out_file, buf); 345218334Speter} 345318334Speter 345418334Speter/* Print operand X using machine-dependent assembler syntax. 345518334Speter The macro PRINT_OPERAND is defined just to control this function. 345618334Speter CODE is a non-digit that preceded the operand-number in the % spec, 345718334Speter such as 'z' if the spec was `%z3'. CODE is 0 if there was no char 345818334Speter between the % and the digits. 345918334Speter When CODE is a non-letter, X is 0. 346018334Speter 346118334Speter The meanings of the letters are machine-dependent and controlled 346218334Speter by PRINT_OPERAND. */ 346318334Speter 346418334Speterstatic void 346518334Speteroutput_operand (x, code) 346618334Speter rtx x; 346718334Speter int code; 346818334Speter{ 346918334Speter if (x && GET_CODE (x) == SUBREG) 347018334Speter x = alter_subreg (x); 347118334Speter 347218334Speter /* If X is a pseudo-register, abort now rather than writing trash to the 347318334Speter assembler file. */ 347418334Speter 347518334Speter if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER) 347618334Speter abort (); 347718334Speter 347818334Speter PRINT_OPERAND (asm_out_file, x, code); 347918334Speter} 348018334Speter 348118334Speter/* Print a memory reference operand for address X 348218334Speter using machine-dependent assembler syntax. 348318334Speter The macro PRINT_OPERAND_ADDRESS exists just to control this function. */ 348418334Speter 348518334Spetervoid 348618334Speteroutput_address (x) 348718334Speter rtx x; 348818334Speter{ 348918334Speter walk_alter_subreg (x); 349018334Speter PRINT_OPERAND_ADDRESS (asm_out_file, x); 349118334Speter} 349218334Speter 349318334Speter/* Print an integer constant expression in assembler syntax. 349418334Speter Addition and subtraction are the only arithmetic 349518334Speter that may appear in these expressions. */ 349618334Speter 349718334Spetervoid 349818334Speteroutput_addr_const (file, x) 349918334Speter FILE *file; 350018334Speter rtx x; 350118334Speter{ 350218334Speter char buf[256]; 350318334Speter 350418334Speter restart: 350518334Speter switch (GET_CODE (x)) 350618334Speter { 350718334Speter case PC: 350818334Speter if (flag_pic) 350918334Speter putc ('.', file); 351018334Speter else 351118334Speter abort (); 351218334Speter break; 351318334Speter 351418334Speter case SYMBOL_REF: 351518334Speter assemble_name (file, XSTR (x, 0)); 351618334Speter break; 351718334Speter 351818334Speter case LABEL_REF: 351918334Speter ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0))); 352018334Speter assemble_name (file, buf); 352118334Speter break; 352218334Speter 352318334Speter case CODE_LABEL: 352418334Speter ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); 352518334Speter assemble_name (file, buf); 352618334Speter break; 352718334Speter 352818334Speter case CONST_INT: 352950503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); 353018334Speter break; 353118334Speter 353218334Speter case CONST: 353318334Speter /* This used to output parentheses around the expression, 353418334Speter but that does not work on the 386 (either ATT or BSD assembler). */ 353518334Speter output_addr_const (file, XEXP (x, 0)); 353618334Speter break; 353718334Speter 353818334Speter case CONST_DOUBLE: 353918334Speter if (GET_MODE (x) == VOIDmode) 354018334Speter { 354118334Speter /* We can use %d if the number is one word and positive. */ 354218334Speter if (CONST_DOUBLE_HIGH (x)) 354350503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX, 354418334Speter CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x)); 354518334Speter else if (CONST_DOUBLE_LOW (x) < 0) 354650503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x)); 354718334Speter else 354850503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x)); 354918334Speter } 355018334Speter else 355118334Speter /* We can't handle floating point constants; 355218334Speter PRINT_OPERAND must handle them. */ 355318334Speter output_operand_lossage ("floating constant misused"); 355418334Speter break; 355518334Speter 355618334Speter case PLUS: 355718334Speter /* Some assemblers need integer constants to appear last (eg masm). */ 355818334Speter if (GET_CODE (XEXP (x, 0)) == CONST_INT) 355918334Speter { 356018334Speter output_addr_const (file, XEXP (x, 1)); 356118334Speter if (INTVAL (XEXP (x, 0)) >= 0) 356218334Speter fprintf (file, "+"); 356318334Speter output_addr_const (file, XEXP (x, 0)); 356418334Speter } 356518334Speter else 356618334Speter { 356718334Speter output_addr_const (file, XEXP (x, 0)); 356818334Speter if (INTVAL (XEXP (x, 1)) >= 0) 356918334Speter fprintf (file, "+"); 357018334Speter output_addr_const (file, XEXP (x, 1)); 357118334Speter } 357218334Speter break; 357318334Speter 357418334Speter case MINUS: 357518334Speter /* Avoid outputting things like x-x or x+5-x, 357618334Speter since some assemblers can't handle that. */ 357718334Speter x = simplify_subtraction (x); 357818334Speter if (GET_CODE (x) != MINUS) 357918334Speter goto restart; 358018334Speter 358118334Speter output_addr_const (file, XEXP (x, 0)); 358218334Speter fprintf (file, "-"); 358318334Speter if (GET_CODE (XEXP (x, 1)) == CONST_INT 358418334Speter && INTVAL (XEXP (x, 1)) < 0) 358518334Speter { 358618334Speter fprintf (file, ASM_OPEN_PAREN); 358718334Speter output_addr_const (file, XEXP (x, 1)); 358818334Speter fprintf (file, ASM_CLOSE_PAREN); 358918334Speter } 359018334Speter else 359118334Speter output_addr_const (file, XEXP (x, 1)); 359218334Speter break; 359318334Speter 359418334Speter case ZERO_EXTEND: 359518334Speter case SIGN_EXTEND: 359618334Speter output_addr_const (file, XEXP (x, 0)); 359718334Speter break; 359818334Speter 359918334Speter default: 360018334Speter output_operand_lossage ("invalid expression as operand"); 360118334Speter } 360218334Speter} 360318334Speter 360418334Speter/* A poor man's fprintf, with the added features of %I, %R, %L, and %U. 360518334Speter %R prints the value of REGISTER_PREFIX. 360618334Speter %L prints the value of LOCAL_LABEL_PREFIX. 360718334Speter %U prints the value of USER_LABEL_PREFIX. 360818334Speter %I prints the value of IMMEDIATE_PREFIX. 360918334Speter %O runs ASM_OUTPUT_OPCODE to transform what follows in the string. 361018334Speter Also supported are %d, %x, %s, %e, %f, %g and %%. 361118334Speter 361218334Speter We handle alternate assembler dialects here, just like output_asm_insn. */ 361318334Speter 361418334Spetervoid 361518334Speterasm_fprintf VPROTO((FILE *file, char *p, ...)) 361618334Speter{ 361718334Speter#ifndef __STDC__ 361818334Speter FILE *file; 361918334Speter char *p; 362018334Speter#endif 362118334Speter va_list argptr; 362218334Speter char buf[10]; 362318334Speter char *q, c; 362418334Speter 362518334Speter VA_START (argptr, p); 362618334Speter 362718334Speter#ifndef __STDC__ 362850503Sobrien file = va_arg (argptr, FILE *); 362950503Sobrien p = va_arg (argptr, char *); 363018334Speter#endif 363118334Speter 363218334Speter buf[0] = '%'; 363318334Speter 363450503Sobrien while ((c = *p++)) 363518334Speter switch (c) 363618334Speter { 363718334Speter#ifdef ASSEMBLER_DIALECT 363818334Speter case '{': 363950503Sobrien { 364050503Sobrien int i; 364118334Speter 364250503Sobrien /* If we want the first dialect, do nothing. Otherwise, skip 364350503Sobrien DIALECT_NUMBER of strings ending with '|'. */ 364450503Sobrien for (i = 0; i < dialect_number; i++) 364550503Sobrien { 364650503Sobrien while (*p && *p++ != '|') 364750503Sobrien ; 364850503Sobrien 364950503Sobrien if (*p == '|') 365050503Sobrien p++; 365118334Speter } 365250503Sobrien } 365318334Speter break; 365418334Speter 365518334Speter case '|': 365618334Speter /* Skip to close brace. */ 365718334Speter while (*p && *p++ != '}') 365818334Speter ; 365918334Speter break; 366018334Speter 366118334Speter case '}': 366218334Speter break; 366318334Speter#endif 366418334Speter 366518334Speter case '%': 366618334Speter c = *p++; 366718334Speter q = &buf[1]; 366818334Speter while ((c >= '0' && c <= '9') || c == '.') 366918334Speter { 367018334Speter *q++ = c; 367118334Speter c = *p++; 367218334Speter } 367318334Speter switch (c) 367418334Speter { 367518334Speter case '%': 367618334Speter fprintf (file, "%%"); 367718334Speter break; 367818334Speter 367918334Speter case 'd': case 'i': case 'u': 368018334Speter case 'x': case 'p': case 'X': 368118334Speter case 'o': 368218334Speter *q++ = c; 368318334Speter *q = 0; 368418334Speter fprintf (file, buf, va_arg (argptr, int)); 368518334Speter break; 368618334Speter 368718334Speter case 'w': 368818334Speter /* This is a prefix to the 'd', 'i', 'u', 'x', 'p', and 'X' cases, 368918334Speter but we do not check for those cases. It means that the value 369018334Speter is a HOST_WIDE_INT, which may be either `int' or `long'. */ 369118334Speter 369250503Sobrien#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT 369350503Sobrien#else 369450503Sobrien#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG 369518334Speter *q++ = 'l'; 369650503Sobrien#else 369750503Sobrien *q++ = 'l'; 369850503Sobrien *q++ = 'l'; 369918334Speter#endif 370050503Sobrien#endif 370118334Speter 370218334Speter *q++ = *p++; 370318334Speter *q = 0; 370418334Speter fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT)); 370518334Speter break; 370618334Speter 370718334Speter case 'l': 370818334Speter *q++ = c; 370918334Speter *q++ = *p++; 371018334Speter *q = 0; 371118334Speter fprintf (file, buf, va_arg (argptr, long)); 371218334Speter break; 371318334Speter 371418334Speter case 'e': 371518334Speter case 'f': 371618334Speter case 'g': 371718334Speter *q++ = c; 371818334Speter *q = 0; 371918334Speter fprintf (file, buf, va_arg (argptr, double)); 372018334Speter break; 372118334Speter 372218334Speter case 's': 372318334Speter *q++ = c; 372418334Speter *q = 0; 372518334Speter fprintf (file, buf, va_arg (argptr, char *)); 372618334Speter break; 372718334Speter 372818334Speter case 'O': 372918334Speter#ifdef ASM_OUTPUT_OPCODE 373018334Speter ASM_OUTPUT_OPCODE (asm_out_file, p); 373118334Speter#endif 373218334Speter break; 373318334Speter 373418334Speter case 'R': 373518334Speter#ifdef REGISTER_PREFIX 373618334Speter fprintf (file, "%s", REGISTER_PREFIX); 373718334Speter#endif 373818334Speter break; 373918334Speter 374018334Speter case 'I': 374118334Speter#ifdef IMMEDIATE_PREFIX 374218334Speter fprintf (file, "%s", IMMEDIATE_PREFIX); 374318334Speter#endif 374418334Speter break; 374518334Speter 374618334Speter case 'L': 374718334Speter#ifdef LOCAL_LABEL_PREFIX 374818334Speter fprintf (file, "%s", LOCAL_LABEL_PREFIX); 374918334Speter#endif 375018334Speter break; 375118334Speter 375218334Speter case 'U': 375318334Speter#ifdef USER_LABEL_PREFIX 375418334Speter fprintf (file, "%s", USER_LABEL_PREFIX); 375518334Speter#endif 375618334Speter break; 375718334Speter 375818334Speter default: 375918334Speter abort (); 376018334Speter } 376118334Speter break; 376218334Speter 376318334Speter default: 376418334Speter fputc (c, file); 376518334Speter } 376618334Speter} 376718334Speter 376818334Speter/* Split up a CONST_DOUBLE or integer constant rtx 376918334Speter into two rtx's for single words, 377018334Speter storing in *FIRST the word that comes first in memory in the target 377118334Speter and in *SECOND the other. */ 377218334Speter 377318334Spetervoid 377418334Spetersplit_double (value, first, second) 377518334Speter rtx value; 377618334Speter rtx *first, *second; 377718334Speter{ 377818334Speter if (GET_CODE (value) == CONST_INT) 377918334Speter { 378018334Speter if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD)) 378118334Speter { 378218334Speter /* In this case the CONST_INT holds both target words. 378350503Sobrien Extract the bits from it into two word-sized pieces. 378450503Sobrien Sign extend each half to HOST_WIDE_INT. */ 378518334Speter rtx low, high; 378650503Sobrien /* On machines where HOST_BITS_PER_WIDE_INT == BITS_PER_WORD 378750503Sobrien the shift below will cause a compiler warning, even though 378850503Sobrien this code won't be executed. So put the shift amounts in 378950503Sobrien variables to avoid the warning. */ 379050503Sobrien int rshift = HOST_BITS_PER_WIDE_INT - BITS_PER_WORD; 379150503Sobrien int lshift = HOST_BITS_PER_WIDE_INT - 2 * BITS_PER_WORD; 379218334Speter 379350503Sobrien low = GEN_INT ((INTVAL (value) << rshift) >> rshift); 379450503Sobrien high = GEN_INT ((INTVAL (value) << lshift) >> rshift); 379518334Speter if (WORDS_BIG_ENDIAN) 379618334Speter { 379718334Speter *first = high; 379818334Speter *second = low; 379918334Speter } 380018334Speter else 380118334Speter { 380218334Speter *first = low; 380318334Speter *second = high; 380418334Speter } 380518334Speter } 380618334Speter else 380718334Speter { 380818334Speter /* The rule for using CONST_INT for a wider mode 380918334Speter is that we regard the value as signed. 381018334Speter So sign-extend it. */ 381118334Speter rtx high = (INTVAL (value) < 0 ? constm1_rtx : const0_rtx); 381218334Speter if (WORDS_BIG_ENDIAN) 381318334Speter { 381418334Speter *first = high; 381518334Speter *second = value; 381618334Speter } 381718334Speter else 381818334Speter { 381918334Speter *first = value; 382018334Speter *second = high; 382118334Speter } 382218334Speter } 382318334Speter } 382418334Speter else if (GET_CODE (value) != CONST_DOUBLE) 382518334Speter { 382618334Speter if (WORDS_BIG_ENDIAN) 382718334Speter { 382818334Speter *first = const0_rtx; 382918334Speter *second = value; 383018334Speter } 383118334Speter else 383218334Speter { 383318334Speter *first = value; 383418334Speter *second = const0_rtx; 383518334Speter } 383618334Speter } 383718334Speter else if (GET_MODE (value) == VOIDmode 383818334Speter /* This is the old way we did CONST_DOUBLE integers. */ 383918334Speter || GET_MODE_CLASS (GET_MODE (value)) == MODE_INT) 384018334Speter { 384118334Speter /* In an integer, the words are defined as most and least significant. 384218334Speter So order them by the target's convention. */ 384318334Speter if (WORDS_BIG_ENDIAN) 384418334Speter { 384518334Speter *first = GEN_INT (CONST_DOUBLE_HIGH (value)); 384618334Speter *second = GEN_INT (CONST_DOUBLE_LOW (value)); 384718334Speter } 384818334Speter else 384918334Speter { 385018334Speter *first = GEN_INT (CONST_DOUBLE_LOW (value)); 385118334Speter *second = GEN_INT (CONST_DOUBLE_HIGH (value)); 385218334Speter } 385318334Speter } 385418334Speter else 385518334Speter { 385618334Speter#ifdef REAL_ARITHMETIC 385718334Speter REAL_VALUE_TYPE r; long l[2]; 385818334Speter REAL_VALUE_FROM_CONST_DOUBLE (r, value); 385918334Speter 386018334Speter /* Note, this converts the REAL_VALUE_TYPE to the target's 386118334Speter format, splits up the floating point double and outputs 386218334Speter exactly 32 bits of it into each of l[0] and l[1] -- 386350503Sobrien not necessarily BITS_PER_WORD bits. */ 386418334Speter REAL_VALUE_TO_TARGET_DOUBLE (r, l); 386518334Speter 386618334Speter *first = GEN_INT ((HOST_WIDE_INT) l[0]); 386718334Speter *second = GEN_INT ((HOST_WIDE_INT) l[1]); 386818334Speter#else 386918334Speter if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT 387018334Speter || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD) 387118334Speter && ! flag_pretend_float) 387218334Speter abort (); 387318334Speter 387418334Speter if ( 387518334Speter#ifdef HOST_WORDS_BIG_ENDIAN 387618334Speter WORDS_BIG_ENDIAN 387718334Speter#else 387818334Speter ! WORDS_BIG_ENDIAN 387918334Speter#endif 388018334Speter ) 388118334Speter { 388218334Speter /* Host and target agree => no need to swap. */ 388318334Speter *first = GEN_INT (CONST_DOUBLE_LOW (value)); 388418334Speter *second = GEN_INT (CONST_DOUBLE_HIGH (value)); 388518334Speter } 388618334Speter else 388718334Speter { 388818334Speter *second = GEN_INT (CONST_DOUBLE_LOW (value)); 388918334Speter *first = GEN_INT (CONST_DOUBLE_HIGH (value)); 389018334Speter } 389118334Speter#endif /* no REAL_ARITHMETIC */ 389218334Speter } 389318334Speter} 389418334Speter 389518334Speter/* Return nonzero if this function has no function calls. */ 389618334Speter 389718334Speterint 389818334Speterleaf_function_p () 389918334Speter{ 390018334Speter rtx insn; 390118334Speter 390250503Sobrien if (profile_flag || profile_block_flag || profile_arc_flag) 390318334Speter return 0; 390418334Speter 390518334Speter for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 390618334Speter { 390718334Speter if (GET_CODE (insn) == CALL_INSN) 390818334Speter return 0; 390918334Speter if (GET_CODE (insn) == INSN 391018334Speter && GET_CODE (PATTERN (insn)) == SEQUENCE 391118334Speter && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN) 391218334Speter return 0; 391318334Speter } 391418334Speter for (insn = current_function_epilogue_delay_list; insn; insn = XEXP (insn, 1)) 391518334Speter { 391618334Speter if (GET_CODE (XEXP (insn, 0)) == CALL_INSN) 391718334Speter return 0; 391818334Speter if (GET_CODE (XEXP (insn, 0)) == INSN 391918334Speter && GET_CODE (PATTERN (XEXP (insn, 0))) == SEQUENCE 392018334Speter && GET_CODE (XVECEXP (PATTERN (XEXP (insn, 0)), 0, 0)) == CALL_INSN) 392118334Speter return 0; 392218334Speter } 392318334Speter 392418334Speter return 1; 392518334Speter} 392618334Speter 392718334Speter/* On some machines, a function with no call insns 392818334Speter can run faster if it doesn't create its own register window. 392918334Speter When output, the leaf function should use only the "output" 393018334Speter registers. Ordinarily, the function would be compiled to use 393118334Speter the "input" registers to find its arguments; it is a candidate 393218334Speter for leaf treatment if it uses only the "input" registers. 393318334Speter Leaf function treatment means renumbering so the function 393418334Speter uses the "output" registers instead. */ 393518334Speter 393618334Speter#ifdef LEAF_REGISTERS 393718334Speter 393818334Speterstatic char permitted_reg_in_leaf_functions[] = LEAF_REGISTERS; 393918334Speter 394018334Speter/* Return 1 if this function uses only the registers that can be 394118334Speter safely renumbered. */ 394218334Speter 394318334Speterint 394418334Speteronly_leaf_regs_used () 394518334Speter{ 394618334Speter int i; 394718334Speter 394818334Speter for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 394950503Sobrien if ((regs_ever_live[i] || global_regs[i]) 395050503Sobrien && ! permitted_reg_in_leaf_functions[i]) 395150503Sobrien return 0; 395250503Sobrien 395350503Sobrien if (current_function_uses_pic_offset_table 395450503Sobrien && pic_offset_table_rtx != 0 395550503Sobrien && GET_CODE (pic_offset_table_rtx) == REG 395650503Sobrien && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)]) 395750503Sobrien return 0; 395850503Sobrien 395918334Speter return 1; 396018334Speter} 396118334Speter 396218334Speter/* Scan all instructions and renumber all registers into those 396318334Speter available in leaf functions. */ 396418334Speter 396518334Speterstatic void 396618334Speterleaf_renumber_regs (first) 396718334Speter rtx first; 396818334Speter{ 396918334Speter rtx insn; 397018334Speter 397118334Speter /* Renumber only the actual patterns. 397218334Speter The reg-notes can contain frame pointer refs, 397318334Speter and renumbering them could crash, and should not be needed. */ 397418334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 397518334Speter if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') 397618334Speter leaf_renumber_regs_insn (PATTERN (insn)); 397718334Speter for (insn = current_function_epilogue_delay_list; insn; insn = XEXP (insn, 1)) 397818334Speter if (GET_RTX_CLASS (GET_CODE (XEXP (insn, 0))) == 'i') 397918334Speter leaf_renumber_regs_insn (PATTERN (XEXP (insn, 0))); 398018334Speter} 398118334Speter 398218334Speter/* Scan IN_RTX and its subexpressions, and renumber all regs into those 398318334Speter available in leaf functions. */ 398418334Speter 398518334Spetervoid 398618334Speterleaf_renumber_regs_insn (in_rtx) 398718334Speter register rtx in_rtx; 398818334Speter{ 398918334Speter register int i, j; 399018334Speter register char *format_ptr; 399118334Speter 399218334Speter if (in_rtx == 0) 399318334Speter return; 399418334Speter 399518334Speter /* Renumber all input-registers into output-registers. 399618334Speter renumbered_regs would be 1 for an output-register; 399718334Speter they */ 399818334Speter 399918334Speter if (GET_CODE (in_rtx) == REG) 400018334Speter { 400118334Speter int newreg; 400218334Speter 400318334Speter /* Don't renumber the same reg twice. */ 400418334Speter if (in_rtx->used) 400518334Speter return; 400618334Speter 400718334Speter newreg = REGNO (in_rtx); 400818334Speter /* Don't try to renumber pseudo regs. It is possible for a pseudo reg 400918334Speter to reach here as part of a REG_NOTE. */ 401018334Speter if (newreg >= FIRST_PSEUDO_REGISTER) 401118334Speter { 401218334Speter in_rtx->used = 1; 401318334Speter return; 401418334Speter } 401518334Speter newreg = LEAF_REG_REMAP (newreg); 401618334Speter if (newreg < 0) 401718334Speter abort (); 401818334Speter regs_ever_live[REGNO (in_rtx)] = 0; 401918334Speter regs_ever_live[newreg] = 1; 402018334Speter REGNO (in_rtx) = newreg; 402118334Speter in_rtx->used = 1; 402218334Speter } 402318334Speter 402418334Speter if (GET_RTX_CLASS (GET_CODE (in_rtx)) == 'i') 402518334Speter { 402618334Speter /* Inside a SEQUENCE, we find insns. 402718334Speter Renumber just the patterns of these insns, 402818334Speter just as we do for the top-level insns. */ 402918334Speter leaf_renumber_regs_insn (PATTERN (in_rtx)); 403018334Speter return; 403118334Speter } 403218334Speter 403318334Speter format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx)); 403418334Speter 403518334Speter for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++) 403618334Speter switch (*format_ptr++) 403718334Speter { 403818334Speter case 'e': 403918334Speter leaf_renumber_regs_insn (XEXP (in_rtx, i)); 404018334Speter break; 404118334Speter 404218334Speter case 'E': 404318334Speter if (NULL != XVEC (in_rtx, i)) 404418334Speter { 404518334Speter for (j = 0; j < XVECLEN (in_rtx, i); j++) 404618334Speter leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j)); 404718334Speter } 404818334Speter break; 404918334Speter 405018334Speter case 'S': 405118334Speter case 's': 405218334Speter case '0': 405318334Speter case 'i': 405418334Speter case 'w': 405518334Speter case 'n': 405618334Speter case 'u': 405718334Speter break; 405818334Speter 405918334Speter default: 406018334Speter abort (); 406118334Speter } 406218334Speter} 406318334Speter#endif 4064