final.c revision 132727
118334Speter/* Convert RTL to assembler code and output it, for GNU compiler. 290087Sobrien Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 3132727Skan 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. 418334Speter 590087SobrienThis file is part of GCC. 618334Speter 790087SobrienGCC is free software; you can redistribute it and/or modify it under 890087Sobrienthe terms of the GNU General Public License as published by the Free 990087SobrienSoftware Foundation; either version 2, or (at your option) any later 1090087Sobrienversion. 1118334Speter 1290087SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1390087SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1490087SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1590087Sobrienfor more details. 1618334Speter 1718334SpeterYou should have received a copy of the GNU General Public License 1890087Sobrienalong with GCC; see the file COPYING. If not, write to the Free 1990087SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 2090087Sobrien02111-1307, USA. */ 2118334Speter 2218334Speter/* This is the final pass of the compiler. 2318334Speter It looks at the rtl code for a function and outputs assembler code. 2418334Speter 2518334Speter Call `final_start_function' to output the assembler code for function entry, 2618334Speter `final' to output assembler code for some RTL code, 2718334Speter `final_end_function' to output assembler code for function exit. 2818334Speter If a function is compiled in several pieces, each piece is 2918334Speter output separately with `final'. 3018334Speter 3118334Speter Some optimizations are also done at this level. 3218334Speter Move instructions that were made unnecessary by good register allocation 3318334Speter are detected and omitted from the output. (Though most of these 3418334Speter are removed by the last jump pass.) 3518334Speter 3618334Speter Instructions to set the condition codes are omitted when it can be 3718334Speter seen that the condition codes already had the desired values. 3818334Speter 3918334Speter In some cases it is sufficient if the inherited condition codes 4018334Speter have related values, but this may require the following insn 4118334Speter (the one that tests the condition codes) to be modified. 4218334Speter 4318334Speter The code for the function prologue and epilogue are generated 4490087Sobrien directly in assembler by the target functions function_prologue and 4590087Sobrien function_epilogue. Those instructions never exist as rtl. */ 4618334Speter 4718334Speter#include "config.h" 4850503Sobrien#include "system.h" 49132727Skan#include "coretypes.h" 50132727Skan#include "tm.h" 5118334Speter 5218334Speter#include "tree.h" 5318334Speter#include "rtl.h" 5490087Sobrien#include "tm_p.h" 5518334Speter#include "regs.h" 5618334Speter#include "insn-config.h" 5718334Speter#include "insn-attr.h" 5818334Speter#include "recog.h" 5918334Speter#include "conditions.h" 6018334Speter#include "flags.h" 6118334Speter#include "real.h" 6218334Speter#include "hard-reg-set.h" 6318334Speter#include "output.h" 6450503Sobrien#include "except.h" 6590087Sobrien#include "function.h" 6650503Sobrien#include "toplev.h" 6750503Sobrien#include "reload.h" 6852515Sobrien#include "intl.h" 6990087Sobrien#include "basic-block.h" 7090087Sobrien#include "target.h" 7190087Sobrien#include "debug.h" 7290087Sobrien#include "expr.h" 73117404Skan#include "cfglayout.h" 7418334Speter 7518334Speter#ifdef XCOFF_DEBUGGING_INFO 7690087Sobrien#include "xcoffout.h" /* Needed for external data 7790087Sobrien declarations for e.g. AIX 4.x. */ 7818334Speter#endif 7918334Speter 8050503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO) 8150503Sobrien#include "dwarf2out.h" 8250503Sobrien#endif 8350503Sobrien 84132727Skan#ifdef DBX_DEBUGGING_INFO 85132727Skan#include "dbxout.h" 86132727Skan#endif 87132727Skan 8818334Speter/* If we aren't using cc0, CC_STATUS_INIT shouldn't exist. So define a 8918334Speter null default for it to save conditionalization later. */ 9018334Speter#ifndef CC_STATUS_INIT 9118334Speter#define CC_STATUS_INIT 9218334Speter#endif 9318334Speter 9418334Speter/* How to start an assembler comment. */ 9518334Speter#ifndef ASM_COMMENT_START 9618334Speter#define ASM_COMMENT_START ";#" 9718334Speter#endif 9818334Speter 9918334Speter/* Is the given character a logical line separator for the assembler? */ 10018334Speter#ifndef IS_ASM_LOGICAL_LINE_SEPARATOR 10118334Speter#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';') 10218334Speter#endif 10318334Speter 10450503Sobrien#ifndef JUMP_TABLES_IN_TEXT_SECTION 10550503Sobrien#define JUMP_TABLES_IN_TEXT_SECTION 0 10650503Sobrien#endif 10750503Sobrien 108117404Skan#if defined(READONLY_DATA_SECTION) || defined(READONLY_DATA_SECTION_ASM_OP) 109117404Skan#define HAVE_READONLY_DATA_SECTION 1 110117404Skan#else 111117404Skan#define HAVE_READONLY_DATA_SECTION 0 112117404Skan#endif 113117404Skan 114132727Skan/* Bitflags used by final_scan_insn. */ 115132727Skan#define SEEN_BB 1 116132727Skan#define SEEN_NOTE 2 117132727Skan#define SEEN_EMITTED 4 118132727Skan 11918334Speter/* Last insn processed by final_scan_insn. */ 12090087Sobrienstatic rtx debug_insn; 12190087Sobrienrtx current_output_insn; 12218334Speter 12318334Speter/* Line number of last NOTE. */ 12418334Speterstatic int last_linenum; 12518334Speter 12618334Speter/* Highest line number in current block. */ 12718334Speterstatic int high_block_linenum; 12818334Speter 12918334Speter/* Likewise for function. */ 13018334Speterstatic int high_function_linenum; 13118334Speter 13218334Speter/* Filename of last NOTE. */ 13390087Sobrienstatic const char *last_filename; 13418334Speter 13550503Sobrienextern int length_unit_log; /* This is defined in insn-attrtab.c. */ 13650503Sobrien 13718334Speter/* Nonzero while outputting an `asm' with operands. 13818334Speter This means that inconsistencies are the user's fault, so don't abort. 13918334Speter The precise value is the insn being output, to pass to error_for_asm. */ 140117404Skanrtx this_is_asm_operands; 14118334Speter 14218334Speter/* Number of operands of this insn, for an `asm' with operands. */ 14350503Sobrienstatic unsigned int insn_noperands; 14418334Speter 14518334Speter/* Compare optimization flag. */ 14618334Speter 14718334Speterstatic rtx last_ignored_compare = 0; 14818334Speter 14918334Speter/* Assign a unique number to each insn that is output. 15018334Speter This can be used to generate unique local labels. */ 15118334Speter 15218334Speterstatic int insn_counter = 0; 15318334Speter 15418334Speter#ifdef HAVE_cc0 15518334Speter/* This variable contains machine-dependent flags (defined in tm.h) 15618334Speter set and examined by output routines 15718334Speter that describe how to interpret the condition codes properly. */ 15818334Speter 15918334SpeterCC_STATUS cc_status; 16018334Speter 16118334Speter/* During output of an insn, this contains a copy of cc_status 16218334Speter from before the insn. */ 16318334Speter 16418334SpeterCC_STATUS cc_prev_status; 16518334Speter#endif 16618334Speter 16718334Speter/* Indexed by hardware reg number, is 1 if that register is ever 16818334Speter used in the current function. 16918334Speter 17018334Speter In life_analysis, or in stupid_life_analysis, this is set 17118334Speter up to record the hard regs used explicitly. Reload adds 17218334Speter in the hard regs used for holding pseudo regs. Final uses 17318334Speter it to generate the code in the function prologue and epilogue 17418334Speter to save and restore registers as needed. */ 17518334Speter 17618334Speterchar regs_ever_live[FIRST_PSEUDO_REGISTER]; 17718334Speter 178132727Skan/* Like regs_ever_live, but 1 if a reg is set or clobbered from an asm. 179132727Skan Unlike regs_ever_live, elements of this array corresponding to 180132727Skan eliminable regs like the frame pointer are set if an asm sets them. */ 181132727Skan 182132727Skanchar regs_asm_clobbered[FIRST_PSEUDO_REGISTER]; 183132727Skan 18418334Speter/* Nonzero means current function must be given a frame pointer. 185132727Skan Initialized in function.c to 0. Set only in reload1.c as per 186132727Skan the needs of the function. */ 18718334Speter 18818334Speterint frame_pointer_needed; 18918334Speter 19090087Sobrien/* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen. */ 19118334Speter 19218334Speterstatic int block_depth; 19318334Speter 19418334Speter/* Nonzero if have enabled APP processing of our assembler output. */ 19518334Speter 19618334Speterstatic int app_on; 19718334Speter 19818334Speter/* If we are outputting an insn sequence, this contains the sequence rtx. 19918334Speter Zero otherwise. */ 20018334Speter 20118334Speterrtx final_sequence; 20218334Speter 20318334Speter#ifdef ASSEMBLER_DIALECT 20418334Speter 20518334Speter/* Number of the assembler dialect to use, starting at 0. */ 20618334Speterstatic int dialect_number; 20718334Speter#endif 20818334Speter 20990087Sobrien#ifdef HAVE_conditional_execution 21090087Sobrien/* Nonnull if the insn currently being emitted was a COND_EXEC pattern. */ 21190087Sobrienrtx current_insn_predicate; 21290087Sobrien#endif 21318334Speter 21450503Sobrien#ifdef HAVE_ATTR_length 215132727Skanstatic int asm_insn_count (rtx); 21650503Sobrien#endif 217132727Skanstatic void profile_function (FILE *); 218132727Skanstatic void profile_after_prologue (FILE *); 219132727Skanstatic bool notice_source_line (rtx); 220132727Skanstatic rtx walk_alter_subreg (rtx *); 221132727Skanstatic void output_asm_name (void); 222132727Skanstatic void output_alternate_entry_point (FILE *, rtx); 223132727Skanstatic tree get_mem_expr_from_op (rtx, int *); 224132727Skanstatic void output_asm_operand_names (rtx *, int *, int); 225132727Skanstatic void output_operand (rtx, int); 22650503Sobrien#ifdef LEAF_REGISTERS 227132727Skanstatic void leaf_renumber_regs (rtx); 22850503Sobrien#endif 22950503Sobrien#ifdef HAVE_cc0 230132727Skanstatic int alter_cond (rtx); 23150503Sobrien#endif 23290087Sobrien#ifndef ADDR_VEC_ALIGN 233132727Skanstatic int final_addr_vec_align (rtx); 23490087Sobrien#endif 23590087Sobrien#ifdef HAVE_ATTR_length 236132727Skanstatic int align_fuzz (rtx, rtx, int, unsigned); 23790087Sobrien#endif 23818334Speter 23918334Speter/* Initialize data in final at the beginning of a compilation. */ 24018334Speter 24118334Spetervoid 242132727Skaninit_final (const char *filename ATTRIBUTE_UNUSED) 24318334Speter{ 24418334Speter app_on = 0; 24518334Speter final_sequence = 0; 24618334Speter 24718334Speter#ifdef ASSEMBLER_DIALECT 24818334Speter dialect_number = ASSEMBLER_DIALECT; 24918334Speter#endif 25018334Speter} 25118334Speter 25290087Sobrien/* Default target function prologue and epilogue assembler output. 25318334Speter 25490087Sobrien If not overridden for epilogue code, then the function body itself 25590087Sobrien contains return instructions wherever needed. */ 25690087Sobrienvoid 257132727Skandefault_function_pro_epilogue (FILE *file ATTRIBUTE_UNUSED, 258132727Skan HOST_WIDE_INT size ATTRIBUTE_UNUSED) 25990087Sobrien{ 26090087Sobrien} 26118334Speter 26290087Sobrien/* Default target hook that outputs nothing to a stream. */ 26390087Sobrienvoid 264132727Skanno_asm_to_stream (FILE *file ATTRIBUTE_UNUSED) 26590087Sobrien{ 26618334Speter} 26718334Speter 26818334Speter/* Enable APP processing of subsequent output. 26918334Speter Used before the output from an `asm' statement. */ 27018334Speter 27118334Spetervoid 272132727Skanapp_enable (void) 27318334Speter{ 27418334Speter if (! app_on) 27518334Speter { 27650503Sobrien fputs (ASM_APP_ON, asm_out_file); 27718334Speter app_on = 1; 27818334Speter } 27918334Speter} 28018334Speter 28118334Speter/* Disable APP processing of subsequent output. 28218334Speter Called from varasm.c before most kinds of output. */ 28318334Speter 28418334Spetervoid 285132727Skanapp_disable (void) 28618334Speter{ 28718334Speter if (app_on) 28818334Speter { 28950503Sobrien fputs (ASM_APP_OFF, asm_out_file); 29018334Speter app_on = 0; 29118334Speter } 29218334Speter} 29318334Speter 29490087Sobrien/* Return the number of slots filled in the current 29518334Speter delayed branch sequence (we don't count the insn needing the 29618334Speter delay slot). Zero if not in a delayed branch sequence. */ 29718334Speter 29818334Speter#ifdef DELAY_SLOTS 29918334Speterint 300132727Skandbr_sequence_length (void) 30118334Speter{ 30218334Speter if (final_sequence != 0) 30318334Speter return XVECLEN (final_sequence, 0) - 1; 30418334Speter else 30518334Speter return 0; 30618334Speter} 30718334Speter#endif 30818334Speter 30918334Speter/* The next two pages contain routines used to compute the length of an insn 31018334Speter and to shorten branches. */ 31118334Speter 31218334Speter/* Arrays for insn lengths, and addresses. The latter is referenced by 31318334Speter `insn_current_length'. */ 31418334Speter 31590087Sobrienstatic int *insn_lengths; 31618334Speter 31790087Sobrienvarray_type insn_addresses_; 31890087Sobrien 31952515Sobrien/* Max uid for which the above arrays are valid. */ 32052515Sobrienstatic int insn_lengths_max_uid; 32152515Sobrien 32218334Speter/* Address of insn being processed. Used by `insn_current_length'. */ 32318334Speterint insn_current_address; 32418334Speter 32550503Sobrien/* Address of insn being processed in previous iteration. */ 32650503Sobrienint insn_last_address; 32750503Sobrien 32890087Sobrien/* known invariant alignment of insn being processed. */ 32950503Sobrienint insn_current_align; 33050503Sobrien 33150503Sobrien/* After shorten_branches, for any insn, uid_align[INSN_UID (insn)] 33250503Sobrien gives the next following alignment insn that increases the known 33350503Sobrien alignment, or NULL_RTX if there is no such insn. 33450503Sobrien For any alignment obtained this way, we can again index uid_align with 33550503Sobrien its uid to obtain the next following align that in turn increases the 33650503Sobrien alignment, till we reach NULL_RTX; the sequence obtained this way 33750503Sobrien for each insn we'll call the alignment chain of this insn in the following 33850503Sobrien comments. */ 33950503Sobrien 34090087Sobrienstruct label_alignment 34190087Sobrien{ 34250503Sobrien short alignment; 34350503Sobrien short max_skip; 34450503Sobrien}; 34550503Sobrien 34650503Sobrienstatic rtx *uid_align; 34750503Sobrienstatic int *uid_shuid; 34850503Sobrienstatic struct label_alignment *label_align; 34950503Sobrien 35018334Speter/* Indicate that branch shortening hasn't yet been done. */ 35118334Speter 35218334Spetervoid 353132727Skaninit_insn_lengths (void) 35418334Speter{ 35550503Sobrien if (uid_shuid) 35650503Sobrien { 35750503Sobrien free (uid_shuid); 35850503Sobrien uid_shuid = 0; 35950503Sobrien } 36050503Sobrien if (insn_lengths) 36150503Sobrien { 36250503Sobrien free (insn_lengths); 36350503Sobrien insn_lengths = 0; 36452515Sobrien insn_lengths_max_uid = 0; 36550503Sobrien } 36690087Sobrien#ifdef HAVE_ATTR_length 36790087Sobrien INSN_ADDRESSES_FREE (); 36890087Sobrien#endif 36950503Sobrien if (uid_align) 37050503Sobrien { 37150503Sobrien free (uid_align); 37250503Sobrien uid_align = 0; 37350503Sobrien } 37418334Speter} 37518334Speter 37618334Speter/* Obtain the current length of an insn. If branch shortening has been done, 37718334Speter get its actual length. Otherwise, get its maximum length. */ 37818334Speter 37918334Speterint 380132727Skanget_attr_length (rtx insn ATTRIBUTE_UNUSED) 38118334Speter{ 38218334Speter#ifdef HAVE_ATTR_length 38318334Speter rtx body; 38418334Speter int i; 38518334Speter int length = 0; 38618334Speter 38752515Sobrien if (insn_lengths_max_uid > INSN_UID (insn)) 38818334Speter return insn_lengths[INSN_UID (insn)]; 38918334Speter else 39018334Speter switch (GET_CODE (insn)) 39118334Speter { 39218334Speter case NOTE: 39318334Speter case BARRIER: 39418334Speter case CODE_LABEL: 39518334Speter return 0; 39618334Speter 39718334Speter case CALL_INSN: 39818334Speter length = insn_default_length (insn); 39918334Speter break; 40018334Speter 40118334Speter case JUMP_INSN: 40218334Speter body = PATTERN (insn); 403117404Skan if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) 40418334Speter { 40550503Sobrien /* Alignment is machine-dependent and should be handled by 40650503Sobrien ADDR_VEC_ALIGN. */ 40718334Speter } 40818334Speter else 40918334Speter length = insn_default_length (insn); 41018334Speter break; 41118334Speter 41218334Speter case INSN: 41318334Speter body = PATTERN (insn); 41418334Speter if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER) 41518334Speter return 0; 41618334Speter 41718334Speter else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0) 41818334Speter length = asm_insn_count (body) * insn_default_length (insn); 41918334Speter else if (GET_CODE (body) == SEQUENCE) 42018334Speter for (i = 0; i < XVECLEN (body, 0); i++) 42118334Speter length += get_attr_length (XVECEXP (body, 0, i)); 42218334Speter else 42318334Speter length = insn_default_length (insn); 42450503Sobrien break; 42550503Sobrien 42650503Sobrien default: 42750503Sobrien break; 42818334Speter } 42918334Speter 43018334Speter#ifdef ADJUST_INSN_LENGTH 43118334Speter ADJUST_INSN_LENGTH (insn, length); 43218334Speter#endif 43318334Speter return length; 43418334Speter#else /* not HAVE_ATTR_length */ 43518334Speter return 0; 43618334Speter#endif /* not HAVE_ATTR_length */ 43718334Speter} 43818334Speter 43950503Sobrien/* Code to handle alignment inside shorten_branches. */ 44050503Sobrien 44150503Sobrien/* Here is an explanation how the algorithm in align_fuzz can give 44250503Sobrien proper results: 44350503Sobrien 44450503Sobrien Call a sequence of instructions beginning with alignment point X 44550503Sobrien and continuing until the next alignment point `block X'. When `X' 44690087Sobrien is used in an expression, it means the alignment value of the 44750503Sobrien alignment point. 44890087Sobrien 44950503Sobrien Call the distance between the start of the first insn of block X, and 45050503Sobrien the end of the last insn of block X `IX', for the `inner size of X'. 45150503Sobrien This is clearly the sum of the instruction lengths. 45290087Sobrien 45350503Sobrien Likewise with the next alignment-delimited block following X, which we 45450503Sobrien shall call block Y. 45590087Sobrien 45650503Sobrien Call the distance between the start of the first insn of block X, and 45750503Sobrien the start of the first insn of block Y `OX', for the `outer size of X'. 45890087Sobrien 45950503Sobrien The estimated padding is then OX - IX. 46090087Sobrien 46150503Sobrien OX can be safely estimated as 46290087Sobrien 46350503Sobrien if (X >= Y) 46450503Sobrien OX = round_up(IX, Y) 46550503Sobrien else 46650503Sobrien OX = round_up(IX, X) + Y - X 46790087Sobrien 46850503Sobrien Clearly est(IX) >= real(IX), because that only depends on the 46950503Sobrien instruction lengths, and those being overestimated is a given. 47090087Sobrien 47150503Sobrien Clearly round_up(foo, Z) >= round_up(bar, Z) if foo >= bar, so 47250503Sobrien we needn't worry about that when thinking about OX. 47390087Sobrien 47450503Sobrien When X >= Y, the alignment provided by Y adds no uncertainty factor 47550503Sobrien for branch ranges starting before X, so we can just round what we have. 47650503Sobrien But when X < Y, we don't know anything about the, so to speak, 47750503Sobrien `middle bits', so we have to assume the worst when aligning up from an 47850503Sobrien address mod X to one mod Y, which is Y - X. */ 47950503Sobrien 48050503Sobrien#ifndef LABEL_ALIGN 48190087Sobrien#define LABEL_ALIGN(LABEL) align_labels_log 48250503Sobrien#endif 48350503Sobrien 48450503Sobrien#ifndef LABEL_ALIGN_MAX_SKIP 48590087Sobrien#define LABEL_ALIGN_MAX_SKIP align_labels_max_skip 48650503Sobrien#endif 48750503Sobrien 48850503Sobrien#ifndef LOOP_ALIGN 48990087Sobrien#define LOOP_ALIGN(LABEL) align_loops_log 49050503Sobrien#endif 49150503Sobrien 49250503Sobrien#ifndef LOOP_ALIGN_MAX_SKIP 49390087Sobrien#define LOOP_ALIGN_MAX_SKIP align_loops_max_skip 49450503Sobrien#endif 49550503Sobrien 49650503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER 49750503Sobrien#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0 49850503Sobrien#endif 49950503Sobrien 50050503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 50150503Sobrien#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0 50250503Sobrien#endif 50350503Sobrien 50490087Sobrien#ifndef JUMP_ALIGN 50590087Sobrien#define JUMP_ALIGN(LABEL) align_jumps_log 50690087Sobrien#endif 50790087Sobrien 50890087Sobrien#ifndef JUMP_ALIGN_MAX_SKIP 50990087Sobrien#define JUMP_ALIGN_MAX_SKIP align_jumps_max_skip 51090087Sobrien#endif 51190087Sobrien 51250503Sobrien#ifndef ADDR_VEC_ALIGN 51390087Sobrienstatic int 514132727Skanfinal_addr_vec_align (rtx addr_vec) 51550503Sobrien{ 51690087Sobrien int align = GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec))); 51750503Sobrien 51850503Sobrien if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT) 51950503Sobrien align = BIGGEST_ALIGNMENT / BITS_PER_UNIT; 52090087Sobrien return exact_log2 (align); 52150503Sobrien 52250503Sobrien} 52390087Sobrien 52450503Sobrien#define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC) 52550503Sobrien#endif 52650503Sobrien 52750503Sobrien#ifndef INSN_LENGTH_ALIGNMENT 52850503Sobrien#define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log 52950503Sobrien#endif 53050503Sobrien 53150503Sobrien#define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)]) 53250503Sobrien 53350503Sobrienstatic int min_labelno, max_labelno; 53450503Sobrien 53550503Sobrien#define LABEL_TO_ALIGNMENT(LABEL) \ 53650503Sobrien (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].alignment) 53750503Sobrien 53850503Sobrien#define LABEL_TO_MAX_SKIP(LABEL) \ 53950503Sobrien (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].max_skip) 54050503Sobrien 54150503Sobrien/* For the benefit of port specific code do this also as a function. */ 54290087Sobrien 54350503Sobrienint 544132727Skanlabel_to_alignment (rtx label) 54550503Sobrien{ 54650503Sobrien return LABEL_TO_ALIGNMENT (label); 54750503Sobrien} 54850503Sobrien 54950503Sobrien#ifdef HAVE_ATTR_length 55050503Sobrien/* The differences in addresses 55150503Sobrien between a branch and its target might grow or shrink depending on 55250503Sobrien the alignment the start insn of the range (the branch for a forward 55350503Sobrien branch or the label for a backward branch) starts out on; if these 55450503Sobrien differences are used naively, they can even oscillate infinitely. 55550503Sobrien We therefore want to compute a 'worst case' address difference that 55650503Sobrien is independent of the alignment the start insn of the range end 55750503Sobrien up on, and that is at least as large as the actual difference. 55850503Sobrien The function align_fuzz calculates the amount we have to add to the 55950503Sobrien naively computed difference, by traversing the part of the alignment 56050503Sobrien chain of the start insn of the range that is in front of the end insn 56150503Sobrien of the range, and considering for each alignment the maximum amount 56250503Sobrien that it might contribute to a size increase. 56350503Sobrien 56450503Sobrien For casesi tables, we also want to know worst case minimum amounts of 56550503Sobrien address difference, in case a machine description wants to introduce 56650503Sobrien some common offset that is added to all offsets in a table. 56790087Sobrien For this purpose, align_fuzz with a growth argument of 0 computes the 56850503Sobrien appropriate adjustment. */ 56950503Sobrien 57050503Sobrien/* Compute the maximum delta by which the difference of the addresses of 57150503Sobrien START and END might grow / shrink due to a different address for start 57250503Sobrien which changes the size of alignment insns between START and END. 57350503Sobrien KNOWN_ALIGN_LOG is the alignment known for START. 57450503Sobrien GROWTH should be ~0 if the objective is to compute potential code size 57550503Sobrien increase, and 0 if the objective is to compute potential shrink. 57650503Sobrien The return value is undefined for any other value of GROWTH. */ 57790087Sobrien 57890087Sobrienstatic int 579132727Skanalign_fuzz (rtx start, rtx end, int known_align_log, unsigned int growth) 58050503Sobrien{ 58150503Sobrien int uid = INSN_UID (start); 58250503Sobrien rtx align_label; 58350503Sobrien int known_align = 1 << known_align_log; 58450503Sobrien int end_shuid = INSN_SHUID (end); 58550503Sobrien int fuzz = 0; 58650503Sobrien 58750503Sobrien for (align_label = uid_align[uid]; align_label; align_label = uid_align[uid]) 58850503Sobrien { 58950503Sobrien int align_addr, new_align; 59050503Sobrien 59150503Sobrien uid = INSN_UID (align_label); 59290087Sobrien align_addr = INSN_ADDRESSES (uid) - insn_lengths[uid]; 59350503Sobrien if (uid_shuid[uid] > end_shuid) 59450503Sobrien break; 59550503Sobrien known_align_log = LABEL_TO_ALIGNMENT (align_label); 59650503Sobrien new_align = 1 << known_align_log; 59750503Sobrien if (new_align < known_align) 59850503Sobrien continue; 59950503Sobrien fuzz += (-align_addr ^ growth) & (new_align - known_align); 60050503Sobrien known_align = new_align; 60150503Sobrien } 60250503Sobrien return fuzz; 60350503Sobrien} 60450503Sobrien 60550503Sobrien/* Compute a worst-case reference address of a branch so that it 60650503Sobrien can be safely used in the presence of aligned labels. Since the 60750503Sobrien size of the branch itself is unknown, the size of the branch is 60850503Sobrien not included in the range. I.e. for a forward branch, the reference 60950503Sobrien address is the end address of the branch as known from the previous 61050503Sobrien branch shortening pass, minus a value to account for possible size 61150503Sobrien increase due to alignment. For a backward branch, it is the start 61250503Sobrien address of the branch as known from the current pass, plus a value 61350503Sobrien to account for possible size increase due to alignment. 61450503Sobrien NB.: Therefore, the maximum offset allowed for backward branches needs 61550503Sobrien to exclude the branch size. */ 61690087Sobrien 61750503Sobrienint 618132727Skaninsn_current_reference_address (rtx branch) 61950503Sobrien{ 62090087Sobrien rtx dest, seq; 62190087Sobrien int seq_uid; 62290087Sobrien 62390087Sobrien if (! INSN_ADDRESSES_SET_P ()) 62490087Sobrien return 0; 62590087Sobrien 62690087Sobrien seq = NEXT_INSN (PREV_INSN (branch)); 62790087Sobrien seq_uid = INSN_UID (seq); 62850503Sobrien if (GET_CODE (branch) != JUMP_INSN) 62950503Sobrien /* This can happen for example on the PA; the objective is to know the 63050503Sobrien offset to address something in front of the start of the function. 63150503Sobrien Thus, we can treat it like a backward branch. 63250503Sobrien We assume here that FUNCTION_BOUNDARY / BITS_PER_UNIT is larger than 63350503Sobrien any alignment we'd encounter, so we skip the call to align_fuzz. */ 63450503Sobrien return insn_current_address; 63550503Sobrien dest = JUMP_LABEL (branch); 63690087Sobrien 63790087Sobrien /* BRANCH has no proper alignment chain set, so use SEQ. 63890087Sobrien BRANCH also has no INSN_SHUID. */ 63990087Sobrien if (INSN_SHUID (seq) < INSN_SHUID (dest)) 64050503Sobrien { 64190087Sobrien /* Forward branch. */ 64250503Sobrien return (insn_last_address + insn_lengths[seq_uid] 64350503Sobrien - align_fuzz (seq, dest, length_unit_log, ~0)); 64450503Sobrien } 64550503Sobrien else 64650503Sobrien { 64790087Sobrien /* Backward branch. */ 64850503Sobrien return (insn_current_address 64950503Sobrien + align_fuzz (dest, seq, length_unit_log, ~0)); 65050503Sobrien } 65150503Sobrien} 65250503Sobrien#endif /* HAVE_ATTR_length */ 65350503Sobrien 65490087Sobrienvoid 655132727Skancompute_alignments (void) 65690087Sobrien{ 65790087Sobrien int log, max_skip, max_log; 658117404Skan basic_block bb; 65990087Sobrien 66090087Sobrien if (label_align) 66190087Sobrien { 66290087Sobrien free (label_align); 66390087Sobrien label_align = 0; 66490087Sobrien } 66590087Sobrien 66690087Sobrien max_labelno = max_label_num (); 66790087Sobrien min_labelno = get_first_label_num (); 668132727Skan label_align = xcalloc (max_labelno - min_labelno + 1, 669132727Skan sizeof (struct label_alignment)); 67090087Sobrien 67190087Sobrien /* If not optimizing or optimizing for size, don't assign any alignments. */ 67290087Sobrien if (! optimize || optimize_size) 67390087Sobrien return; 67490087Sobrien 675117404Skan FOR_EACH_BB (bb) 67690087Sobrien { 677132727Skan rtx label = BB_HEAD (bb); 67890087Sobrien int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0; 67990087Sobrien edge e; 68090087Sobrien 681132727Skan if (GET_CODE (label) != CODE_LABEL 682132727Skan || probably_never_executed_bb_p (bb)) 68390087Sobrien continue; 68490087Sobrien max_log = LABEL_ALIGN (label); 68590087Sobrien max_skip = LABEL_ALIGN_MAX_SKIP; 68690087Sobrien 68790087Sobrien for (e = bb->pred; e; e = e->pred_next) 68890087Sobrien { 68990087Sobrien if (e->flags & EDGE_FALLTHRU) 69090087Sobrien has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e); 69190087Sobrien else 69290087Sobrien branch_frequency += EDGE_FREQUENCY (e); 69390087Sobrien } 69490087Sobrien 69590087Sobrien /* There are two purposes to align block with no fallthru incoming edge: 69690087Sobrien 1) to avoid fetch stalls when branch destination is near cache boundary 69790087Sobrien 2) to improve cache efficiency in case the previous block is not executed 69890087Sobrien (so it does not need to be in the cache). 69990087Sobrien 70090087Sobrien We to catch first case, we align frequently executed blocks. 70190087Sobrien To catch the second, we align blocks that are executed more frequently 70290087Sobrien than the predecessor and the predecessor is likely to not be executed 70390087Sobrien when function is called. */ 70490087Sobrien 70590087Sobrien if (!has_fallthru 70690087Sobrien && (branch_frequency > BB_FREQ_MAX / 10 707117404Skan || (bb->frequency > bb->prev_bb->frequency * 10 708117404Skan && (bb->prev_bb->frequency 70990087Sobrien <= ENTRY_BLOCK_PTR->frequency / 2)))) 71090087Sobrien { 71190087Sobrien log = JUMP_ALIGN (label); 71290087Sobrien if (max_log < log) 71390087Sobrien { 71490087Sobrien max_log = log; 71590087Sobrien max_skip = JUMP_ALIGN_MAX_SKIP; 71690087Sobrien } 71790087Sobrien } 71890087Sobrien /* In case block is frequent and reached mostly by non-fallthru edge, 719117404Skan align it. It is most likely a first block of loop. */ 72090087Sobrien if (has_fallthru 721132727Skan && maybe_hot_bb_p (bb) 72290087Sobrien && branch_frequency + fallthru_frequency > BB_FREQ_MAX / 10 723117404Skan && branch_frequency > fallthru_frequency * 2) 72490087Sobrien { 72590087Sobrien log = LOOP_ALIGN (label); 72690087Sobrien if (max_log < log) 72790087Sobrien { 72890087Sobrien max_log = log; 72990087Sobrien max_skip = LOOP_ALIGN_MAX_SKIP; 73090087Sobrien } 73190087Sobrien } 73290087Sobrien LABEL_TO_ALIGNMENT (label) = max_log; 73390087Sobrien LABEL_TO_MAX_SKIP (label) = max_skip; 73490087Sobrien } 73590087Sobrien} 73690087Sobrien 73718334Speter/* Make a pass over all insns and compute their actual lengths by shortening 73818334Speter any branches of variable length if possible. */ 73918334Speter 74050503Sobrien/* shorten_branches might be called multiple times: for example, the SH 74150503Sobrien port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG. 74250503Sobrien In order to do this, it needs proper length information, which it obtains 74350503Sobrien by calling shorten_branches. This cannot be collapsed with 74490087Sobrien shorten_branches itself into a single pass unless we also want to integrate 74550503Sobrien reorg.c, since the branch splitting exposes new instructions with delay 74650503Sobrien slots. */ 74750503Sobrien 74818334Spetervoid 749132727Skanshorten_branches (rtx first ATTRIBUTE_UNUSED) 75018334Speter{ 75150503Sobrien rtx insn; 75250503Sobrien int max_uid; 75350503Sobrien int i; 75450503Sobrien int max_log; 75550503Sobrien int max_skip; 75618334Speter#ifdef HAVE_ATTR_length 75750503Sobrien#define MAX_CODE_ALIGN 16 75850503Sobrien rtx seq; 75918334Speter int something_changed = 1; 76018334Speter char *varying_length; 76118334Speter rtx body; 76218334Speter int uid; 76350503Sobrien rtx align_tab[MAX_CODE_ALIGN]; 76418334Speter 76550503Sobrien#endif 76618334Speter 76750503Sobrien /* Compute maximum UID and allocate label_align / uid_shuid. */ 76850503Sobrien max_uid = get_max_uid (); 76950503Sobrien 770132727Skan uid_shuid = xmalloc (max_uid * sizeof *uid_shuid); 77150503Sobrien 77290087Sobrien if (max_labelno != max_label_num ()) 77390087Sobrien { 77490087Sobrien int old = max_labelno; 77590087Sobrien int n_labels; 77690087Sobrien int n_old_labels; 77790087Sobrien 77890087Sobrien max_labelno = max_label_num (); 77990087Sobrien 78090087Sobrien n_labels = max_labelno - min_labelno + 1; 78190087Sobrien n_old_labels = old - min_labelno + 1; 78290087Sobrien 783132727Skan label_align = xrealloc (label_align, 784132727Skan n_labels * sizeof (struct label_alignment)); 78590087Sobrien 78690087Sobrien /* Range of labels grows monotonically in the function. Abort here 78790087Sobrien means that the initialization of array got lost. */ 78890087Sobrien if (n_old_labels > n_labels) 78990087Sobrien abort (); 79090087Sobrien 79190087Sobrien memset (label_align + n_old_labels, 0, 79290087Sobrien (n_labels - n_old_labels) * sizeof (struct label_alignment)); 79390087Sobrien } 79490087Sobrien 79550503Sobrien /* Initialize label_align and set up uid_shuid to be strictly 79650503Sobrien monotonically rising with insn order. */ 79750503Sobrien /* We use max_log here to keep track of the maximum alignment we want to 79850503Sobrien impose on the next CODE_LABEL (or the current one if we are processing 79950503Sobrien the CODE_LABEL itself). */ 80090087Sobrien 80150503Sobrien max_log = 0; 80250503Sobrien max_skip = 0; 80350503Sobrien 80450503Sobrien for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn)) 80550503Sobrien { 80650503Sobrien int log; 80750503Sobrien 80850503Sobrien INSN_SHUID (insn) = i++; 80990087Sobrien if (INSN_P (insn)) 81050503Sobrien { 81150503Sobrien /* reorg might make the first insn of a loop being run once only, 81250503Sobrien and delete the label in front of it. Then we want to apply 81350503Sobrien the loop alignment to the new label created by reorg, which 81450503Sobrien is separated by the former loop start insn from the 81550503Sobrien NOTE_INSN_LOOP_BEG. */ 81650503Sobrien } 81750503Sobrien else if (GET_CODE (insn) == CODE_LABEL) 81850503Sobrien { 81950503Sobrien rtx next; 82050503Sobrien 82190087Sobrien /* Merge in alignments computed by compute_alignments. */ 82290087Sobrien log = LABEL_TO_ALIGNMENT (insn); 82390087Sobrien if (max_log < log) 82490087Sobrien { 82590087Sobrien max_log = log; 82690087Sobrien max_skip = LABEL_TO_MAX_SKIP (insn); 82790087Sobrien } 82890087Sobrien 82950503Sobrien log = LABEL_ALIGN (insn); 83050503Sobrien if (max_log < log) 83150503Sobrien { 83250503Sobrien max_log = log; 83350503Sobrien max_skip = LABEL_ALIGN_MAX_SKIP; 83450503Sobrien } 83550503Sobrien next = NEXT_INSN (insn); 83650503Sobrien /* ADDR_VECs only take room if read-only data goes into the text 83750503Sobrien section. */ 838117404Skan if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION) 83950503Sobrien if (next && GET_CODE (next) == JUMP_INSN) 84050503Sobrien { 84150503Sobrien rtx nextbody = PATTERN (next); 84250503Sobrien if (GET_CODE (nextbody) == ADDR_VEC 84350503Sobrien || GET_CODE (nextbody) == ADDR_DIFF_VEC) 84450503Sobrien { 84550503Sobrien log = ADDR_VEC_ALIGN (next); 84650503Sobrien if (max_log < log) 84750503Sobrien { 84850503Sobrien max_log = log; 84950503Sobrien max_skip = LABEL_ALIGN_MAX_SKIP; 85050503Sobrien } 85150503Sobrien } 85250503Sobrien } 85350503Sobrien LABEL_TO_ALIGNMENT (insn) = max_log; 85450503Sobrien LABEL_TO_MAX_SKIP (insn) = max_skip; 85550503Sobrien max_log = 0; 85650503Sobrien max_skip = 0; 85750503Sobrien } 85850503Sobrien else if (GET_CODE (insn) == BARRIER) 85950503Sobrien { 86050503Sobrien rtx label; 86150503Sobrien 86290087Sobrien for (label = insn; label && ! INSN_P (label); 86350503Sobrien label = NEXT_INSN (label)) 86450503Sobrien if (GET_CODE (label) == CODE_LABEL) 86550503Sobrien { 86650503Sobrien log = LABEL_ALIGN_AFTER_BARRIER (insn); 86750503Sobrien if (max_log < log) 86850503Sobrien { 86950503Sobrien max_log = log; 87050503Sobrien max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP; 87150503Sobrien } 87250503Sobrien break; 87350503Sobrien } 87450503Sobrien } 87550503Sobrien } 87650503Sobrien#ifdef HAVE_ATTR_length 87750503Sobrien 87850503Sobrien /* Allocate the rest of the arrays. */ 879132727Skan insn_lengths = xmalloc (max_uid * sizeof (*insn_lengths)); 88052515Sobrien insn_lengths_max_uid = max_uid; 88150503Sobrien /* Syntax errors can lead to labels being outside of the main insn stream. 88250503Sobrien Initialize insn_addresses, so that we get reproducible results. */ 88390087Sobrien INSN_ADDRESSES_ALLOC (max_uid); 88450503Sobrien 885132727Skan varying_length = xcalloc (max_uid, sizeof (char)); 88650503Sobrien 88750503Sobrien /* Initialize uid_align. We scan instructions 88850503Sobrien from end to start, and keep in align_tab[n] the last seen insn 88950503Sobrien that does an alignment of at least n+1, i.e. the successor 89050503Sobrien in the alignment chain for an insn that does / has a known 89150503Sobrien alignment of n. */ 892132727Skan uid_align = xcalloc (max_uid, sizeof *uid_align); 89350503Sobrien 89490087Sobrien for (i = MAX_CODE_ALIGN; --i >= 0;) 89550503Sobrien align_tab[i] = NULL_RTX; 89650503Sobrien seq = get_last_insn (); 89750503Sobrien for (; seq; seq = PREV_INSN (seq)) 89850503Sobrien { 89950503Sobrien int uid = INSN_UID (seq); 90050503Sobrien int log; 90150503Sobrien log = (GET_CODE (seq) == CODE_LABEL ? LABEL_TO_ALIGNMENT (seq) : 0); 90250503Sobrien uid_align[uid] = align_tab[0]; 90350503Sobrien if (log) 90450503Sobrien { 90550503Sobrien /* Found an alignment label. */ 90650503Sobrien uid_align[uid] = align_tab[log]; 90750503Sobrien for (i = log - 1; i >= 0; i--) 90850503Sobrien align_tab[i] = seq; 90950503Sobrien } 91050503Sobrien } 91150503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE 91250503Sobrien if (optimize) 91350503Sobrien { 91450503Sobrien /* Look for ADDR_DIFF_VECs, and initialize their minimum and maximum 91550503Sobrien label fields. */ 91650503Sobrien 91750503Sobrien int min_shuid = INSN_SHUID (get_insns ()) - 1; 91850503Sobrien int max_shuid = INSN_SHUID (get_last_insn ()) + 1; 91950503Sobrien int rel; 92050503Sobrien 92150503Sobrien for (insn = first; insn != 0; insn = NEXT_INSN (insn)) 92250503Sobrien { 92350503Sobrien rtx min_lab = NULL_RTX, max_lab = NULL_RTX, pat; 92450503Sobrien int len, i, min, max, insn_shuid; 92550503Sobrien int min_align; 92650503Sobrien addr_diff_vec_flags flags; 92750503Sobrien 92850503Sobrien if (GET_CODE (insn) != JUMP_INSN 92950503Sobrien || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC) 93050503Sobrien continue; 93150503Sobrien pat = PATTERN (insn); 93250503Sobrien len = XVECLEN (pat, 1); 93350503Sobrien if (len <= 0) 93450503Sobrien abort (); 93550503Sobrien min_align = MAX_CODE_ALIGN; 93650503Sobrien for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--) 93750503Sobrien { 93850503Sobrien rtx lab = XEXP (XVECEXP (pat, 1, i), 0); 93950503Sobrien int shuid = INSN_SHUID (lab); 94050503Sobrien if (shuid < min) 94150503Sobrien { 94250503Sobrien min = shuid; 94350503Sobrien min_lab = lab; 94450503Sobrien } 94550503Sobrien if (shuid > max) 94650503Sobrien { 94750503Sobrien max = shuid; 94850503Sobrien max_lab = lab; 94950503Sobrien } 95050503Sobrien if (min_align > LABEL_TO_ALIGNMENT (lab)) 95150503Sobrien min_align = LABEL_TO_ALIGNMENT (lab); 95250503Sobrien } 95350503Sobrien XEXP (pat, 2) = gen_rtx_LABEL_REF (VOIDmode, min_lab); 95450503Sobrien XEXP (pat, 3) = gen_rtx_LABEL_REF (VOIDmode, max_lab); 95550503Sobrien insn_shuid = INSN_SHUID (insn); 95650503Sobrien rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0)); 95750503Sobrien flags.min_align = min_align; 95850503Sobrien flags.base_after_vec = rel > insn_shuid; 95950503Sobrien flags.min_after_vec = min > insn_shuid; 96050503Sobrien flags.max_after_vec = max > insn_shuid; 96150503Sobrien flags.min_after_base = min > rel; 96250503Sobrien flags.max_after_base = max > rel; 96350503Sobrien ADDR_DIFF_VEC_FLAGS (pat) = flags; 96450503Sobrien } 96550503Sobrien } 96650503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */ 96750503Sobrien 96818334Speter /* Compute initial lengths, addresses, and varying flags for each insn. */ 969132727Skan for (insn_current_address = 0, insn = first; 97018334Speter insn != 0; 97118334Speter insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn)) 97218334Speter { 97318334Speter uid = INSN_UID (insn); 97450503Sobrien 97550503Sobrien insn_lengths[uid] = 0; 97650503Sobrien 97750503Sobrien if (GET_CODE (insn) == CODE_LABEL) 97850503Sobrien { 97950503Sobrien int log = LABEL_TO_ALIGNMENT (insn); 98050503Sobrien if (log) 98150503Sobrien { 98250503Sobrien int align = 1 << log; 98350503Sobrien int new_address = (insn_current_address + align - 1) & -align; 98450503Sobrien insn_lengths[uid] = new_address - insn_current_address; 98550503Sobrien } 98650503Sobrien } 98750503Sobrien 988117404Skan INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid]; 98990087Sobrien 99018334Speter if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER 99118334Speter || GET_CODE (insn) == CODE_LABEL) 99218334Speter continue; 99350503Sobrien if (INSN_DELETED_P (insn)) 99450503Sobrien continue; 99518334Speter 99618334Speter body = PATTERN (insn); 99718334Speter if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) 99818334Speter { 99918334Speter /* This only takes room if read-only data goes into the text 100018334Speter section. */ 1001117404Skan if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION) 100250503Sobrien insn_lengths[uid] = (XVECLEN (body, 100350503Sobrien GET_CODE (body) == ADDR_DIFF_VEC) 100450503Sobrien * GET_MODE_SIZE (GET_MODE (body))); 100550503Sobrien /* Alignment is handled by ADDR_VEC_ALIGN. */ 100618334Speter } 100790087Sobrien else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0) 100818334Speter insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn); 100918334Speter else if (GET_CODE (body) == SEQUENCE) 101018334Speter { 101118334Speter int i; 101218334Speter int const_delay_slots; 101318334Speter#ifdef DELAY_SLOTS 101418334Speter const_delay_slots = const_num_delay_slots (XVECEXP (body, 0, 0)); 101518334Speter#else 101618334Speter const_delay_slots = 0; 101718334Speter#endif 101818334Speter /* Inside a delay slot sequence, we do not do any branch shortening 101918334Speter if the shortening could change the number of delay slots 102050503Sobrien of the branch. */ 102118334Speter for (i = 0; i < XVECLEN (body, 0); i++) 102218334Speter { 102318334Speter rtx inner_insn = XVECEXP (body, 0, i); 102418334Speter int inner_uid = INSN_UID (inner_insn); 102518334Speter int inner_length; 102618334Speter 102790087Sobrien if (GET_CODE (body) == ASM_INPUT 102890087Sobrien || asm_noperands (PATTERN (XVECEXP (body, 0, i))) >= 0) 102918334Speter inner_length = (asm_insn_count (PATTERN (inner_insn)) 103018334Speter * insn_default_length (inner_insn)); 103118334Speter else 103218334Speter inner_length = insn_default_length (inner_insn); 103390087Sobrien 103418334Speter insn_lengths[inner_uid] = inner_length; 103518334Speter if (const_delay_slots) 103618334Speter { 103718334Speter if ((varying_length[inner_uid] 103818334Speter = insn_variable_length_p (inner_insn)) != 0) 103918334Speter varying_length[uid] = 1; 104090087Sobrien INSN_ADDRESSES (inner_uid) = (insn_current_address 104190087Sobrien + insn_lengths[uid]); 104218334Speter } 104318334Speter else 104418334Speter varying_length[inner_uid] = 0; 104518334Speter insn_lengths[uid] += inner_length; 104618334Speter } 104718334Speter } 104818334Speter else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER) 104918334Speter { 105018334Speter insn_lengths[uid] = insn_default_length (insn); 105118334Speter varying_length[uid] = insn_variable_length_p (insn); 105218334Speter } 105318334Speter 105418334Speter /* If needed, do any adjustment. */ 105518334Speter#ifdef ADJUST_INSN_LENGTH 105618334Speter ADJUST_INSN_LENGTH (insn, insn_lengths[uid]); 105752515Sobrien if (insn_lengths[uid] < 0) 105890087Sobrien fatal_insn ("negative insn length", insn); 105918334Speter#endif 106018334Speter } 106118334Speter 106218334Speter /* Now loop over all the insns finding varying length insns. For each, 106318334Speter get the current insn length. If it has changed, reflect the change. 106418334Speter When nothing changes for a full pass, we are done. */ 106518334Speter 106618334Speter while (something_changed) 106718334Speter { 106818334Speter something_changed = 0; 106950503Sobrien insn_current_align = MAX_CODE_ALIGN - 1; 1070132727Skan for (insn_current_address = 0, insn = first; 107118334Speter insn != 0; 107218334Speter insn = NEXT_INSN (insn)) 107318334Speter { 107418334Speter int new_length; 107550503Sobrien#ifdef ADJUST_INSN_LENGTH 107618334Speter int tmp_length; 107750503Sobrien#endif 107850503Sobrien int length_align; 107918334Speter 108018334Speter uid = INSN_UID (insn); 108150503Sobrien 108250503Sobrien if (GET_CODE (insn) == CODE_LABEL) 108350503Sobrien { 108450503Sobrien int log = LABEL_TO_ALIGNMENT (insn); 108550503Sobrien if (log > insn_current_align) 108650503Sobrien { 108750503Sobrien int align = 1 << log; 108850503Sobrien int new_address= (insn_current_address + align - 1) & -align; 108950503Sobrien insn_lengths[uid] = new_address - insn_current_address; 109050503Sobrien insn_current_align = log; 109150503Sobrien insn_current_address = new_address; 109250503Sobrien } 109350503Sobrien else 109450503Sobrien insn_lengths[uid] = 0; 109590087Sobrien INSN_ADDRESSES (uid) = insn_current_address; 109650503Sobrien continue; 109750503Sobrien } 109850503Sobrien 109950503Sobrien length_align = INSN_LENGTH_ALIGNMENT (insn); 110050503Sobrien if (length_align < insn_current_align) 110150503Sobrien insn_current_align = length_align; 110250503Sobrien 110390087Sobrien insn_last_address = INSN_ADDRESSES (uid); 110490087Sobrien INSN_ADDRESSES (uid) = insn_current_address; 110550503Sobrien 110650503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE 110750503Sobrien if (optimize && GET_CODE (insn) == JUMP_INSN 110850503Sobrien && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC) 110918334Speter { 111050503Sobrien rtx body = PATTERN (insn); 111150503Sobrien int old_length = insn_lengths[uid]; 111250503Sobrien rtx rel_lab = XEXP (XEXP (body, 0), 0); 111350503Sobrien rtx min_lab = XEXP (XEXP (body, 2), 0); 111450503Sobrien rtx max_lab = XEXP (XEXP (body, 3), 0); 111590087Sobrien int rel_addr = INSN_ADDRESSES (INSN_UID (rel_lab)); 111690087Sobrien int min_addr = INSN_ADDRESSES (INSN_UID (min_lab)); 111790087Sobrien int max_addr = INSN_ADDRESSES (INSN_UID (max_lab)); 111850503Sobrien rtx prev; 111950503Sobrien int rel_align = 0; 112090087Sobrien addr_diff_vec_flags flags; 112150503Sobrien 112290087Sobrien /* Avoid automatic aggregate initialization. */ 112390087Sobrien flags = ADDR_DIFF_VEC_FLAGS (body); 112490087Sobrien 112550503Sobrien /* Try to find a known alignment for rel_lab. */ 112650503Sobrien for (prev = rel_lab; 112750503Sobrien prev 112850503Sobrien && ! insn_lengths[INSN_UID (prev)] 112950503Sobrien && ! (varying_length[INSN_UID (prev)] & 1); 113050503Sobrien prev = PREV_INSN (prev)) 113150503Sobrien if (varying_length[INSN_UID (prev)] & 2) 113250503Sobrien { 113350503Sobrien rel_align = LABEL_TO_ALIGNMENT (prev); 113450503Sobrien break; 113550503Sobrien } 113650503Sobrien 113750503Sobrien /* See the comment on addr_diff_vec_flags in rtl.h for the 113850503Sobrien meaning of the flags values. base: REL_LAB vec: INSN */ 113950503Sobrien /* Anything after INSN has still addresses from the last 114050503Sobrien pass; adjust these so that they reflect our current 114150503Sobrien estimate for this pass. */ 114250503Sobrien if (flags.base_after_vec) 114350503Sobrien rel_addr += insn_current_address - insn_last_address; 114450503Sobrien if (flags.min_after_vec) 114550503Sobrien min_addr += insn_current_address - insn_last_address; 114650503Sobrien if (flags.max_after_vec) 114750503Sobrien max_addr += insn_current_address - insn_last_address; 114850503Sobrien /* We want to know the worst case, i.e. lowest possible value 114950503Sobrien for the offset of MIN_LAB. If MIN_LAB is after REL_LAB, 115050503Sobrien its offset is positive, and we have to be wary of code shrink; 115150503Sobrien otherwise, it is negative, and we have to be vary of code 115250503Sobrien size increase. */ 115350503Sobrien if (flags.min_after_base) 115450503Sobrien { 115550503Sobrien /* If INSN is between REL_LAB and MIN_LAB, the size 115650503Sobrien changes we are about to make can change the alignment 115750503Sobrien within the observed offset, therefore we have to break 115850503Sobrien it up into two parts that are independent. */ 115950503Sobrien if (! flags.base_after_vec && flags.min_after_vec) 116050503Sobrien { 116150503Sobrien min_addr -= align_fuzz (rel_lab, insn, rel_align, 0); 116250503Sobrien min_addr -= align_fuzz (insn, min_lab, 0, 0); 116350503Sobrien } 116450503Sobrien else 116550503Sobrien min_addr -= align_fuzz (rel_lab, min_lab, rel_align, 0); 116650503Sobrien } 116750503Sobrien else 116850503Sobrien { 116950503Sobrien if (flags.base_after_vec && ! flags.min_after_vec) 117050503Sobrien { 117150503Sobrien min_addr -= align_fuzz (min_lab, insn, 0, ~0); 117250503Sobrien min_addr -= align_fuzz (insn, rel_lab, 0, ~0); 117350503Sobrien } 117450503Sobrien else 117550503Sobrien min_addr -= align_fuzz (min_lab, rel_lab, 0, ~0); 117650503Sobrien } 117750503Sobrien /* Likewise, determine the highest lowest possible value 117850503Sobrien for the offset of MAX_LAB. */ 117950503Sobrien if (flags.max_after_base) 118050503Sobrien { 118150503Sobrien if (! flags.base_after_vec && flags.max_after_vec) 118250503Sobrien { 118350503Sobrien max_addr += align_fuzz (rel_lab, insn, rel_align, ~0); 118450503Sobrien max_addr += align_fuzz (insn, max_lab, 0, ~0); 118550503Sobrien } 118650503Sobrien else 118750503Sobrien max_addr += align_fuzz (rel_lab, max_lab, rel_align, ~0); 118850503Sobrien } 118950503Sobrien else 119050503Sobrien { 119150503Sobrien if (flags.base_after_vec && ! flags.max_after_vec) 119250503Sobrien { 119350503Sobrien max_addr += align_fuzz (max_lab, insn, 0, 0); 119450503Sobrien max_addr += align_fuzz (insn, rel_lab, 0, 0); 119550503Sobrien } 119650503Sobrien else 119750503Sobrien max_addr += align_fuzz (max_lab, rel_lab, 0, 0); 119850503Sobrien } 119950503Sobrien PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr, 120050503Sobrien max_addr - rel_addr, 120150503Sobrien body)); 1202117404Skan if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION) 120350503Sobrien { 120450503Sobrien insn_lengths[uid] 120550503Sobrien = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body))); 120650503Sobrien insn_current_address += insn_lengths[uid]; 120750503Sobrien if (insn_lengths[uid] != old_length) 120850503Sobrien something_changed = 1; 120950503Sobrien } 121050503Sobrien 121150503Sobrien continue; 121250503Sobrien } 121350503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */ 121450503Sobrien 121550503Sobrien if (! (varying_length[uid])) 121650503Sobrien { 121790087Sobrien if (GET_CODE (insn) == INSN 121890087Sobrien && GET_CODE (PATTERN (insn)) == SEQUENCE) 121990087Sobrien { 122090087Sobrien int i; 122190087Sobrien 122290087Sobrien body = PATTERN (insn); 122390087Sobrien for (i = 0; i < XVECLEN (body, 0); i++) 122490087Sobrien { 122590087Sobrien rtx inner_insn = XVECEXP (body, 0, i); 122690087Sobrien int inner_uid = INSN_UID (inner_insn); 122790087Sobrien 122890087Sobrien INSN_ADDRESSES (inner_uid) = insn_current_address; 122990087Sobrien 123090087Sobrien insn_current_address += insn_lengths[inner_uid]; 123190087Sobrien } 1232117404Skan } 123390087Sobrien else 123490087Sobrien insn_current_address += insn_lengths[uid]; 123590087Sobrien 123618334Speter continue; 123718334Speter } 123890087Sobrien 123918334Speter if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) 124018334Speter { 124118334Speter int i; 124290087Sobrien 124318334Speter body = PATTERN (insn); 124418334Speter new_length = 0; 124518334Speter for (i = 0; i < XVECLEN (body, 0); i++) 124618334Speter { 124718334Speter rtx inner_insn = XVECEXP (body, 0, i); 124818334Speter int inner_uid = INSN_UID (inner_insn); 124918334Speter int inner_length; 125018334Speter 125190087Sobrien INSN_ADDRESSES (inner_uid) = insn_current_address; 125218334Speter 125318334Speter /* insn_current_length returns 0 for insns with a 125418334Speter non-varying length. */ 125518334Speter if (! varying_length[inner_uid]) 125618334Speter inner_length = insn_lengths[inner_uid]; 125718334Speter else 125818334Speter inner_length = insn_current_length (inner_insn); 125918334Speter 126018334Speter if (inner_length != insn_lengths[inner_uid]) 126118334Speter { 126218334Speter insn_lengths[inner_uid] = inner_length; 126318334Speter something_changed = 1; 126418334Speter } 126518334Speter insn_current_address += insn_lengths[inner_uid]; 126618334Speter new_length += inner_length; 126718334Speter } 126818334Speter } 126918334Speter else 127018334Speter { 127118334Speter new_length = insn_current_length (insn); 127218334Speter insn_current_address += new_length; 127318334Speter } 127418334Speter 127518334Speter#ifdef ADJUST_INSN_LENGTH 127618334Speter /* If needed, do any adjustment. */ 127718334Speter tmp_length = new_length; 127818334Speter ADJUST_INSN_LENGTH (insn, new_length); 127918334Speter insn_current_address += (new_length - tmp_length); 128018334Speter#endif 128118334Speter 128218334Speter if (new_length != insn_lengths[uid]) 128318334Speter { 128418334Speter insn_lengths[uid] = new_length; 128518334Speter something_changed = 1; 128618334Speter } 128718334Speter } 128818334Speter /* For a non-optimizing compile, do only a single pass. */ 128918334Speter if (!optimize) 129018334Speter break; 129118334Speter } 129250503Sobrien 129350503Sobrien free (varying_length); 129450503Sobrien 129518334Speter#endif /* HAVE_ATTR_length */ 129618334Speter} 129718334Speter 129818334Speter#ifdef HAVE_ATTR_length 129918334Speter/* Given the body of an INSN known to be generated by an ASM statement, return 130018334Speter the number of machine instructions likely to be generated for this insn. 130118334Speter This is used to compute its length. */ 130218334Speter 130318334Speterstatic int 1304132727Skanasm_insn_count (rtx body) 130518334Speter{ 130690087Sobrien const char *template; 130718334Speter int count = 1; 130818334Speter 130918334Speter if (GET_CODE (body) == ASM_INPUT) 131018334Speter template = XSTR (body, 0); 131118334Speter else 131290087Sobrien template = decode_asm_operands (body, NULL, NULL, NULL, NULL); 131318334Speter 131490087Sobrien for (; *template; template++) 131590087Sobrien if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n') 131618334Speter count++; 131718334Speter 131818334Speter return count; 131918334Speter} 132018334Speter#endif 132118334Speter 132218334Speter/* Output assembler code for the start of a function, 132318334Speter and initialize some of the variables in this file 132418334Speter for the new function. The label for the function and associated 132518334Speter assembler pseudo-ops have already been output in `assemble_start_function'. 132618334Speter 132718334Speter FIRST is the first insn of the rtl for the function being compiled. 132818334Speter FILE is the file to write assembler code to. 132918334Speter OPTIMIZE is nonzero if we should eliminate redundant 133018334Speter test and compare insns. */ 133118334Speter 133218334Spetervoid 1333132727Skanfinal_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file, 1334132727Skan int optimize ATTRIBUTE_UNUSED) 133518334Speter{ 133618334Speter block_depth = 0; 133718334Speter 133818334Speter this_is_asm_operands = 0; 133918334Speter 1340132727Skan last_filename = locator_file (prologue_locator); 1341132727Skan last_linenum = locator_line (prologue_locator); 134218334Speter 134390087Sobrien high_block_linenum = high_function_linenum = last_linenum; 134418334Speter 134590087Sobrien (*debug_hooks->begin_prologue) (last_linenum, last_filename); 134650503Sobrien 134790087Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (IA64_UNWIND_INFO) 134890087Sobrien if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG) 134990087Sobrien dwarf2out_begin_prologue (0, NULL); 135018334Speter#endif 135118334Speter 135218334Speter#ifdef LEAF_REG_REMAP 135352515Sobrien if (current_function_uses_only_leaf_regs) 135418334Speter leaf_renumber_regs (first); 135518334Speter#endif 135618334Speter 135718334Speter /* The Sun386i and perhaps other machines don't work right 135818334Speter if the profiling code comes after the prologue. */ 135918334Speter#ifdef PROFILE_BEFORE_PROLOGUE 136090087Sobrien if (current_function_profile) 136118334Speter profile_function (file); 136218334Speter#endif /* PROFILE_BEFORE_PROLOGUE */ 136318334Speter 136450503Sobrien#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue) 136550503Sobrien if (dwarf2out_do_frame ()) 136650503Sobrien dwarf2out_frame_debug (NULL_RTX); 136750503Sobrien#endif 136850503Sobrien 136990087Sobrien /* If debugging, assign block numbers to all of the blocks in this 137090087Sobrien function. */ 137190087Sobrien if (write_symbols) 137290087Sobrien { 137390087Sobrien remove_unnecessary_notes (); 1374132727Skan reemit_insn_block_notes (); 137590087Sobrien number_blocks (current_function_decl); 137690087Sobrien /* We never actually put out begin/end notes for the top-level 137790087Sobrien block in the function. But, conceptually, that block is 137890087Sobrien always needed. */ 137990087Sobrien TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1; 138090087Sobrien } 138190087Sobrien 138218334Speter /* First output the function prologue: code to set up the stack frame. */ 138390087Sobrien (*targetm.asm_out.function_prologue) (file, get_frame_size ()); 138418334Speter 138518334Speter /* If the machine represents the prologue as RTL, the profiling code must 138618334Speter be emitted when NOTE_INSN_PROLOGUE_END is scanned. */ 138718334Speter#ifdef HAVE_prologue 138818334Speter if (! HAVE_prologue) 138918334Speter#endif 139018334Speter profile_after_prologue (file); 139118334Speter} 139218334Speter 139318334Speterstatic void 1394132727Skanprofile_after_prologue (FILE *file ATTRIBUTE_UNUSED) 139518334Speter{ 139618334Speter#ifndef PROFILE_BEFORE_PROLOGUE 139790087Sobrien if (current_function_profile) 139818334Speter profile_function (file); 139918334Speter#endif /* not PROFILE_BEFORE_PROLOGUE */ 140018334Speter} 140118334Speter 140218334Speterstatic void 1403132727Skanprofile_function (FILE *file ATTRIBUTE_UNUSED) 140418334Speter{ 140574478Sobrien#ifndef NO_PROFILE_COUNTERS 1406132727Skan# define NO_PROFILE_COUNTERS 0 140774478Sobrien#endif 140850503Sobrien#if defined(ASM_OUTPUT_REG_PUSH) 140918334Speter int sval = current_function_returns_struct; 1410132727Skan rtx svrtx = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl), 1); 141150503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM) 141218334Speter int cxt = current_function_needs_context; 141350503Sobrien#endif 141450503Sobrien#endif /* ASM_OUTPUT_REG_PUSH */ 141518334Speter 1416132727Skan if (! NO_PROFILE_COUNTERS) 1417132727Skan { 1418132727Skan int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE); 1419132727Skan data_section (); 1420132727Skan ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT)); 1421132727Skan (*targetm.asm_out.internal_label) (file, "LP", current_function_funcdef_no); 1422132727Skan assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1); 1423132727Skan } 142418334Speter 142550503Sobrien function_section (current_function_decl); 142618334Speter 1427132727Skan#if defined(ASM_OUTPUT_REG_PUSH) 1428132727Skan if (sval && svrtx != NULL_RTX && GET_CODE (svrtx) == REG) 1429132727Skan ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx)); 143018334Speter#endif 143118334Speter 143250503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 143318334Speter if (cxt) 143418334Speter ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM); 143518334Speter#else 143650503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 143718334Speter if (cxt) 143850503Sobrien { 143950503Sobrien ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM); 144050503Sobrien } 144118334Speter#endif 144218334Speter#endif 144318334Speter 1444117404Skan FUNCTION_PROFILER (file, current_function_funcdef_no); 144518334Speter 144650503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 144718334Speter if (cxt) 144818334Speter ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM); 144918334Speter#else 145050503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 145118334Speter if (cxt) 145250503Sobrien { 145350503Sobrien ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM); 145450503Sobrien } 145518334Speter#endif 145618334Speter#endif 145718334Speter 1458132727Skan#if defined(ASM_OUTPUT_REG_PUSH) 1459132727Skan if (sval && svrtx != NULL_RTX && GET_CODE (svrtx) == REG) 1460132727Skan ASM_OUTPUT_REG_POP (file, REGNO (svrtx)); 146118334Speter#endif 146218334Speter} 146318334Speter 146418334Speter/* Output assembler code for the end of a function. 146518334Speter For clarity, args are same as those of `final_start_function' 146618334Speter even though not all of them are needed. */ 146718334Speter 146818334Spetervoid 1469132727Skanfinal_end_function (void) 147018334Speter{ 147190087Sobrien app_disable (); 147218334Speter 147390087Sobrien (*debug_hooks->end_function) (high_function_linenum); 147418334Speter 147518334Speter /* Finally, output the function epilogue: 147618334Speter code to restore the stack frame and return to the caller. */ 147790087Sobrien (*targetm.asm_out.function_epilogue) (asm_out_file, get_frame_size ()); 147818334Speter 147990087Sobrien /* And debug output. */ 1480117404Skan (*debug_hooks->end_epilogue) (last_linenum, last_filename); 148190087Sobrien 148290087Sobrien#if defined (DWARF2_UNWIND_INFO) 148390087Sobrien if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG 148490087Sobrien && dwarf2out_do_frame ()) 1485117404Skan dwarf2out_end_epilogue (last_linenum, last_filename); 148650503Sobrien#endif 148718334Speter} 148818334Speter 148918334Speter/* Output assembler code for some insns: all or part of a function. 149018334Speter For description of args, see `final_start_function', above. 149118334Speter 149218334Speter PRESCAN is 1 if we are not really outputting, 149318334Speter just scanning as if we were outputting. 149418334Speter Prescanning deletes and rearranges insns just like ordinary output. 149518334Speter PRESCAN is -2 if we are outputting after having prescanned. 149618334Speter In this case, don't try to delete or rearrange insns 149718334Speter because that has already been done. 149818334Speter Prescanning is done only on certain machines. */ 149918334Speter 150018334Spetervoid 1501132727Skanfinal (rtx first, FILE *file, int optimize, int prescan) 150218334Speter{ 150390087Sobrien rtx insn; 150450503Sobrien int max_uid = 0; 1505132727Skan int seen = 0; 150618334Speter 150718334Speter last_ignored_compare = 0; 150818334Speter 1509132727Skan#ifdef SDB_DEBUGGING_INFO 1510132727Skan /* When producing SDB debugging info, delete troublesome line number 151118334Speter notes from inlined functions in other files as well as duplicate 151218334Speter line number notes. */ 151318334Speter if (write_symbols == SDB_DEBUG) 151418334Speter { 151518334Speter rtx last = 0; 151618334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 151718334Speter if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) 151818334Speter { 151918334Speter if ((RTX_INTEGRATED_P (insn) 152018334Speter && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0) 1521132727Skan || (last != 0 1522132727Skan && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last) 1523132727Skan && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last))) 152418334Speter { 152590087Sobrien delete_insn (insn); /* Use delete_note. */ 152618334Speter continue; 152718334Speter } 152818334Speter last = insn; 152918334Speter } 153018334Speter } 153118334Speter#endif 153218334Speter 153318334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 153450503Sobrien { 1535132727Skan if (INSN_UID (insn) > max_uid) /* Find largest UID. */ 153690087Sobrien max_uid = INSN_UID (insn); 153752515Sobrien#ifdef HAVE_cc0 153852515Sobrien /* If CC tracking across branches is enabled, record the insn which 153952515Sobrien jumps to each branch only reached from one place. */ 154052515Sobrien if (optimize && GET_CODE (insn) == JUMP_INSN) 154152515Sobrien { 154252515Sobrien rtx lab = JUMP_LABEL (insn); 154352515Sobrien if (lab && LABEL_NUSES (lab) == 1) 154452515Sobrien { 154552515Sobrien LABEL_REFS (lab) = insn; 154652515Sobrien } 154752515Sobrien } 154852515Sobrien#endif 154950503Sobrien } 155018334Speter 155118334Speter init_recog (); 155218334Speter 155318334Speter CC_STATUS_INIT; 155418334Speter 155518334Speter /* Output the insns. */ 155618334Speter for (insn = NEXT_INSN (first); insn;) 155750503Sobrien { 155850503Sobrien#ifdef HAVE_ATTR_length 155990087Sobrien if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ()) 156090087Sobrien { 156190087Sobrien /* This can be triggered by bugs elsewhere in the compiler if 156290087Sobrien new insns are created after init_insn_lengths is called. */ 1563117404Skan if (GET_CODE (insn) == NOTE) 1564117404Skan insn_current_address = -1; 1565117404Skan else 1566117404Skan abort (); 156790087Sobrien } 156890087Sobrien else 156990087Sobrien insn_current_address = INSN_ADDRESSES (INSN_UID (insn)); 157090087Sobrien#endif /* HAVE_ATTR_length */ 157190087Sobrien 1572132727Skan insn = final_scan_insn (insn, file, optimize, prescan, 0, &seen); 157350503Sobrien } 157490087Sobrien} 157590087Sobrien 157690087Sobrienconst char * 1577132727Skanget_insn_template (int code, rtx insn) 157890087Sobrien{ 157990087Sobrien switch (insn_data[code].output_format) 158090087Sobrien { 158190087Sobrien case INSN_OUTPUT_FORMAT_SINGLE: 1582132727Skan return insn_data[code].output.single; 158390087Sobrien case INSN_OUTPUT_FORMAT_MULTI: 1584132727Skan return insn_data[code].output.multi[which_alternative]; 158590087Sobrien case INSN_OUTPUT_FORMAT_FUNCTION: 158690087Sobrien if (insn == NULL) 158790087Sobrien abort (); 1588132727Skan return (*insn_data[code].output.function) (recog_data.operand, insn); 158950503Sobrien 159090087Sobrien default: 159190087Sobrien abort (); 159290087Sobrien } 159318334Speter} 159490087Sobrien 1595117404Skan/* Emit the appropriate declaration for an alternate-entry-point 1596117404Skan symbol represented by INSN, to FILE. INSN is a CODE_LABEL with 1597117404Skan LABEL_KIND != LABEL_NORMAL. 1598117404Skan 1599117404Skan The case fall-through in this function is intentional. */ 1600117404Skanstatic void 1601132727Skanoutput_alternate_entry_point (FILE *file, rtx insn) 1602117404Skan{ 1603117404Skan const char *name = LABEL_NAME (insn); 1604117404Skan 1605117404Skan switch (LABEL_KIND (insn)) 1606117404Skan { 1607117404Skan case LABEL_WEAK_ENTRY: 1608117404Skan#ifdef ASM_WEAKEN_LABEL 1609117404Skan ASM_WEAKEN_LABEL (file, name); 1610117404Skan#endif 1611117404Skan case LABEL_GLOBAL_ENTRY: 1612117404Skan (*targetm.asm_out.globalize_label) (file, name); 1613117404Skan case LABEL_STATIC_ENTRY: 1614117404Skan#ifdef ASM_OUTPUT_TYPE_DIRECTIVE 1615117404Skan ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function"); 1616117404Skan#endif 1617117404Skan ASM_OUTPUT_LABEL (file, name); 1618117404Skan break; 1619117404Skan 1620117404Skan case LABEL_NORMAL: 1621117404Skan default: 1622117404Skan abort (); 1623117404Skan } 1624117404Skan} 1625117404Skan 162618334Speter/* The final scan for one insn, INSN. 162718334Speter Args are same as in `final', except that INSN 162818334Speter is the insn being scanned. 162918334Speter Value returned is the next insn to be scanned. 163018334Speter 163118334Speter NOPEEPHOLES is the flag to disallow peephole processing (currently 1632132727Skan used for within delayed branch sequence output). 163318334Speter 1634132727Skan SEEN is used to track the end of the prologue, for emitting 1635132727Skan debug information. We force the emission of a line note after 1636132727Skan both NOTE_INSN_PROLOGUE_END and NOTE_INSN_FUNCTION_BEG, or 1637132727Skan at the beginning of the second basic block, whichever comes 1638132727Skan first. */ 1639132727Skan 164018334Speterrtx 1641132727Skanfinal_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, 1642132727Skan int prescan, int nopeepholes ATTRIBUTE_UNUSED, 1643132727Skan int *seen) 164418334Speter{ 164550503Sobrien#ifdef HAVE_cc0 164650503Sobrien rtx set; 164750503Sobrien#endif 164850503Sobrien 164918334Speter insn_counter++; 165018334Speter 165118334Speter /* Ignore deleted insns. These can occur when we split insns (due to a 165218334Speter template of "#") while not optimizing. */ 165318334Speter if (INSN_DELETED_P (insn)) 165418334Speter return NEXT_INSN (insn); 165518334Speter 165618334Speter switch (GET_CODE (insn)) 165718334Speter { 165818334Speter case NOTE: 165918334Speter if (prescan > 0) 166018334Speter break; 166118334Speter 166290087Sobrien switch (NOTE_LINE_NUMBER (insn)) 166318334Speter { 166490087Sobrien case NOTE_INSN_DELETED: 166590087Sobrien case NOTE_INSN_LOOP_BEG: 166690087Sobrien case NOTE_INSN_LOOP_END: 166796281Sobrien case NOTE_INSN_LOOP_END_TOP_COND: 166890087Sobrien case NOTE_INSN_LOOP_CONT: 166990087Sobrien case NOTE_INSN_LOOP_VTOP: 167090087Sobrien case NOTE_INSN_FUNCTION_END: 167190087Sobrien case NOTE_INSN_REPEATED_LINE_NUMBER: 167290087Sobrien case NOTE_INSN_EXPECTED_VALUE: 167318334Speter break; 167418334Speter 167590087Sobrien case NOTE_INSN_BASIC_BLOCK: 167690087Sobrien#ifdef IA64_UNWIND_INFO 167790087Sobrien IA64_UNWIND_EMIT (asm_out_file, insn); 167850503Sobrien#endif 167990087Sobrien if (flag_debug_asm) 168090087Sobrien fprintf (asm_out_file, "\t%s basic block %d\n", 168190087Sobrien ASM_COMMENT_START, NOTE_BASIC_BLOCK (insn)->index); 1682132727Skan 1683132727Skan if ((*seen & (SEEN_EMITTED | SEEN_BB)) == SEEN_BB) 1684132727Skan { 1685132727Skan *seen |= SEEN_EMITTED; 1686132727Skan last_filename = NULL; 1687132727Skan } 1688132727Skan else 1689132727Skan *seen |= SEEN_BB; 1690132727Skan 169150503Sobrien break; 169250503Sobrien 169390087Sobrien case NOTE_INSN_EH_REGION_BEG: 169490087Sobrien ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHB", 169590087Sobrien NOTE_EH_HANDLER (insn)); 169690087Sobrien break; 169790087Sobrien 169890087Sobrien case NOTE_INSN_EH_REGION_END: 169990087Sobrien ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHE", 170090087Sobrien NOTE_EH_HANDLER (insn)); 170190087Sobrien break; 170290087Sobrien 170390087Sobrien case NOTE_INSN_PROLOGUE_END: 170490087Sobrien (*targetm.asm_out.function_end_prologue) (file); 170518334Speter profile_after_prologue (file); 1706132727Skan 1707132727Skan if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE) 1708132727Skan { 1709132727Skan *seen |= SEEN_EMITTED; 1710132727Skan last_filename = NULL; 1711132727Skan } 1712132727Skan else 1713132727Skan *seen |= SEEN_NOTE; 1714132727Skan 171518334Speter break; 171618334Speter 171790087Sobrien case NOTE_INSN_EPILOGUE_BEG: 171890087Sobrien (*targetm.asm_out.function_begin_epilogue) (file); 171918334Speter break; 172018334Speter 172190087Sobrien case NOTE_INSN_FUNCTION_BEG: 172290087Sobrien app_disable (); 1723117404Skan (*debug_hooks->end_prologue) (last_linenum, last_filename); 1724132727Skan 1725132727Skan if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE) 1726132727Skan { 1727132727Skan *seen |= SEEN_EMITTED; 1728132727Skan last_filename = NULL; 1729132727Skan } 1730132727Skan else 1731132727Skan *seen |= SEEN_NOTE; 1732132727Skan 173318334Speter break; 173490087Sobrien 173590087Sobrien case NOTE_INSN_BLOCK_BEG: 173690087Sobrien if (debug_info_level == DINFO_LEVEL_NORMAL 173718334Speter || debug_info_level == DINFO_LEVEL_VERBOSE 173818334Speter || write_symbols == DWARF_DEBUG 173990087Sobrien || write_symbols == DWARF2_DEBUG 174090087Sobrien || write_symbols == VMS_AND_DWARF2_DEBUG 174190087Sobrien || write_symbols == VMS_DEBUG) 174290087Sobrien { 174390087Sobrien int n = BLOCK_NUMBER (NOTE_BLOCK (insn)); 174418334Speter 174590087Sobrien app_disable (); 174690087Sobrien ++block_depth; 174790087Sobrien high_block_linenum = last_linenum; 174890087Sobrien 174990087Sobrien /* Output debugging info about the symbol-block beginning. */ 175090087Sobrien (*debug_hooks->begin_block) (last_linenum, n); 175190087Sobrien 175290087Sobrien /* Mark this block as output. */ 175390087Sobrien TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1; 175418334Speter } 175590087Sobrien break; 175618334Speter 175790087Sobrien case NOTE_INSN_BLOCK_END: 175890087Sobrien if (debug_info_level == DINFO_LEVEL_NORMAL 175990087Sobrien || debug_info_level == DINFO_LEVEL_VERBOSE 176090087Sobrien || write_symbols == DWARF_DEBUG 176190087Sobrien || write_symbols == DWARF2_DEBUG 176290087Sobrien || write_symbols == VMS_AND_DWARF2_DEBUG 176390087Sobrien || write_symbols == VMS_DEBUG) 176490087Sobrien { 176590087Sobrien int n = BLOCK_NUMBER (NOTE_BLOCK (insn)); 176618334Speter 176790087Sobrien app_disable (); 176818334Speter 176990087Sobrien /* End of a symbol-block. */ 177090087Sobrien --block_depth; 177190087Sobrien if (block_depth < 0) 177290087Sobrien abort (); 177318334Speter 177490087Sobrien (*debug_hooks->end_block) (high_block_linenum, n); 177590087Sobrien } 177690087Sobrien break; 177718334Speter 177890087Sobrien case NOTE_INSN_DELETED_LABEL: 177990087Sobrien /* Emit the label. We may have deleted the CODE_LABEL because 178090087Sobrien the label could be proved to be unreachable, though still 178190087Sobrien referenced (in the form of having its address taken. */ 178290087Sobrien ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); 178390087Sobrien break; 178418334Speter 178590087Sobrien case 0: 178690087Sobrien break; 178718334Speter 178890087Sobrien default: 178990087Sobrien if (NOTE_LINE_NUMBER (insn) <= 0) 179090087Sobrien abort (); 179190087Sobrien break; 179218334Speter } 179318334Speter break; 179418334Speter 179518334Speter case BARRIER: 179690087Sobrien#if defined (DWARF2_UNWIND_INFO) 179790087Sobrien if (dwarf2out_do_frame ()) 179890087Sobrien dwarf2out_frame_debug (insn); 179918334Speter#endif 180018334Speter break; 180118334Speter 180218334Speter case CODE_LABEL: 180350503Sobrien /* The target port might emit labels in the output function for 180450503Sobrien some insn, e.g. sh.c output_branchy_insn. */ 180550503Sobrien if (CODE_LABEL_NUMBER (insn) <= max_labelno) 180650503Sobrien { 180750503Sobrien int align = LABEL_TO_ALIGNMENT (insn); 180850503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN 180950503Sobrien int max_skip = LABEL_TO_MAX_SKIP (insn); 181050503Sobrien#endif 181150503Sobrien 181250503Sobrien if (align && NEXT_INSN (insn)) 181390087Sobrien { 181450503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN 181590087Sobrien ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip); 181650503Sobrien#else 1817117404Skan#ifdef ASM_OUTPUT_ALIGN_WITH_NOP 1818117404Skan ASM_OUTPUT_ALIGN_WITH_NOP (file, align); 1819117404Skan#else 182090087Sobrien ASM_OUTPUT_ALIGN (file, align); 182150503Sobrien#endif 1822117404Skan#endif 182390087Sobrien } 182450503Sobrien } 182552515Sobrien#ifdef HAVE_cc0 182618334Speter CC_STATUS_INIT; 182752515Sobrien /* If this label is reached from only one place, set the condition 182852515Sobrien codes from the instruction just before the branch. */ 182952515Sobrien 183052515Sobrien /* Disabled because some insns set cc_status in the C output code 183152515Sobrien and NOTICE_UPDATE_CC alone can set incorrect status. */ 183252515Sobrien if (0 /* optimize && LABEL_NUSES (insn) == 1*/) 183352515Sobrien { 183452515Sobrien rtx jump = LABEL_REFS (insn); 183552515Sobrien rtx barrier = prev_nonnote_insn (insn); 183652515Sobrien rtx prev; 183752515Sobrien /* If the LABEL_REFS field of this label has been set to point 183852515Sobrien at a branch, the predecessor of the branch is a regular 183952515Sobrien insn, and that branch is the only way to reach this label, 184052515Sobrien set the condition codes based on the branch and its 184152515Sobrien predecessor. */ 184252515Sobrien if (barrier && GET_CODE (barrier) == BARRIER 184352515Sobrien && jump && GET_CODE (jump) == JUMP_INSN 184452515Sobrien && (prev = prev_nonnote_insn (jump)) 184552515Sobrien && GET_CODE (prev) == INSN) 184652515Sobrien { 184752515Sobrien NOTICE_UPDATE_CC (PATTERN (prev), prev); 184852515Sobrien NOTICE_UPDATE_CC (PATTERN (jump), jump); 184952515Sobrien } 185052515Sobrien } 185152515Sobrien#endif 185218334Speter if (prescan > 0) 185318334Speter break; 185450503Sobrien 185590087Sobrien if (LABEL_NAME (insn)) 185690087Sobrien (*debug_hooks->label) (insn); 185790087Sobrien 185818334Speter if (app_on) 185918334Speter { 186050503Sobrien fputs (ASM_APP_OFF, file); 186118334Speter app_on = 0; 186218334Speter } 186318334Speter if (NEXT_INSN (insn) != 0 186418334Speter && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN) 186518334Speter { 186618334Speter rtx nextbody = PATTERN (NEXT_INSN (insn)); 186718334Speter 186818334Speter /* If this label is followed by a jump-table, 186918334Speter make sure we put the label in the read-only section. Also 187018334Speter possibly write the label and jump table together. */ 187118334Speter 187218334Speter if (GET_CODE (nextbody) == ADDR_VEC 187318334Speter || GET_CODE (nextbody) == ADDR_DIFF_VEC) 187418334Speter { 187552515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC) 187652515Sobrien /* In this case, the case vector is being moved by the 187752515Sobrien target, so don't output the label at all. Leave that 187852515Sobrien to the back end macros. */ 187952515Sobrien#else 188050503Sobrien if (! JUMP_TABLES_IN_TEXT_SECTION) 188150503Sobrien { 188290087Sobrien int log_align; 188390087Sobrien 188450503Sobrien readonly_data_section (); 188590087Sobrien 188690087Sobrien#ifdef ADDR_VEC_ALIGN 188790087Sobrien log_align = ADDR_VEC_ALIGN (NEXT_INSN (insn)); 188890087Sobrien#else 188990087Sobrien log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT); 189090087Sobrien#endif 189190087Sobrien ASM_OUTPUT_ALIGN (file, log_align); 189250503Sobrien } 189350503Sobrien else 189450503Sobrien function_section (current_function_decl); 189550503Sobrien 189618334Speter#ifdef ASM_OUTPUT_CASE_LABEL 189718334Speter ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), 189818334Speter NEXT_INSN (insn)); 189918334Speter#else 1900132727Skan (*targetm.asm_out.internal_label) (file, "L", CODE_LABEL_NUMBER (insn)); 190118334Speter#endif 190252515Sobrien#endif 190318334Speter break; 190418334Speter } 190518334Speter } 1906117404Skan if (LABEL_ALT_ENTRY_P (insn)) 1907117404Skan output_alternate_entry_point (file, insn); 190890087Sobrien else 1909132727Skan (*targetm.asm_out.internal_label) (file, "L", CODE_LABEL_NUMBER (insn)); 191018334Speter break; 191118334Speter 191218334Speter default: 191318334Speter { 191490087Sobrien rtx body = PATTERN (insn); 191518334Speter int insn_code_number; 191652515Sobrien const char *template; 191718334Speter rtx note; 191818334Speter 191918334Speter /* An INSN, JUMP_INSN or CALL_INSN. 192018334Speter First check for special kinds that recog doesn't recognize. */ 192118334Speter 1922132727Skan if (GET_CODE (body) == USE /* These are just declarations. */ 192318334Speter || GET_CODE (body) == CLOBBER) 192418334Speter break; 192518334Speter 192618334Speter#ifdef HAVE_cc0 192718334Speter /* If there is a REG_CC_SETTER note on this insn, it means that 192818334Speter the setting of the condition code was done in the delay slot 192918334Speter of the insn that branched here. So recover the cc status 193018334Speter from the insn that set it. */ 193118334Speter 193218334Speter note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX); 193318334Speter if (note) 193418334Speter { 193518334Speter NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0)); 193618334Speter cc_prev_status = cc_status; 193718334Speter } 193818334Speter#endif 193918334Speter 194018334Speter /* Detect insns that are really jump-tables 194118334Speter and output them as such. */ 194218334Speter 194318334Speter if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) 194418334Speter { 194552515Sobrien#if !(defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)) 194690087Sobrien int vlen, idx; 194752515Sobrien#endif 194818334Speter 194918334Speter if (prescan > 0) 195018334Speter break; 195118334Speter 195218334Speter if (app_on) 195318334Speter { 195450503Sobrien fputs (ASM_APP_OFF, file); 195518334Speter app_on = 0; 195618334Speter } 195718334Speter 195852515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC) 195952515Sobrien if (GET_CODE (body) == ADDR_VEC) 196052515Sobrien { 196152515Sobrien#ifdef ASM_OUTPUT_ADDR_VEC 196252515Sobrien ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body); 196352515Sobrien#else 196490087Sobrien abort (); 196552515Sobrien#endif 196652515Sobrien } 196752515Sobrien else 196852515Sobrien { 196952515Sobrien#ifdef ASM_OUTPUT_ADDR_DIFF_VEC 197052515Sobrien ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body); 197152515Sobrien#else 197290087Sobrien abort (); 197352515Sobrien#endif 197452515Sobrien } 197552515Sobrien#else 197618334Speter vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC); 197718334Speter for (idx = 0; idx < vlen; idx++) 197818334Speter { 197918334Speter if (GET_CODE (body) == ADDR_VEC) 198018334Speter { 198118334Speter#ifdef ASM_OUTPUT_ADDR_VEC_ELT 198218334Speter ASM_OUTPUT_ADDR_VEC_ELT 198318334Speter (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0))); 198418334Speter#else 198518334Speter abort (); 198618334Speter#endif 198718334Speter } 198818334Speter else 198918334Speter { 199018334Speter#ifdef ASM_OUTPUT_ADDR_DIFF_ELT 199118334Speter ASM_OUTPUT_ADDR_DIFF_ELT 199218334Speter (file, 199350503Sobrien body, 199418334Speter CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)), 199518334Speter CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0))); 199618334Speter#else 199718334Speter abort (); 199818334Speter#endif 199918334Speter } 200018334Speter } 200118334Speter#ifdef ASM_OUTPUT_CASE_END 200218334Speter ASM_OUTPUT_CASE_END (file, 200318334Speter CODE_LABEL_NUMBER (PREV_INSN (insn)), 200418334Speter insn); 200518334Speter#endif 200652515Sobrien#endif 200718334Speter 200818334Speter function_section (current_function_decl); 200918334Speter 201018334Speter break; 201118334Speter } 2012132727Skan /* Output this line note if it is the first or the last line 2013132727Skan note in a row. */ 2014132727Skan if (notice_source_line (insn)) 2015132727Skan { 2016132727Skan (*debug_hooks->source_line) (last_linenum, last_filename); 2017132727Skan } 201818334Speter 201918334Speter if (GET_CODE (body) == ASM_INPUT) 202018334Speter { 202190087Sobrien const char *string = XSTR (body, 0); 202290087Sobrien 202318334Speter /* There's no telling what that did to the condition codes. */ 202418334Speter CC_STATUS_INIT; 202518334Speter if (prescan > 0) 202618334Speter break; 202790087Sobrien 202890087Sobrien if (string[0]) 202918334Speter { 203090087Sobrien if (! app_on) 203190087Sobrien { 203290087Sobrien fputs (ASM_APP_ON, file); 203390087Sobrien app_on = 1; 203490087Sobrien } 203590087Sobrien fprintf (asm_out_file, "\t%s\n", string); 203618334Speter } 203718334Speter break; 203818334Speter } 203918334Speter 204018334Speter /* Detect `asm' construct with operands. */ 204118334Speter if (asm_noperands (body) >= 0) 204218334Speter { 204350503Sobrien unsigned int noperands = asm_noperands (body); 2044132727Skan rtx *ops = alloca (noperands * sizeof (rtx)); 204590087Sobrien const char *string; 204618334Speter 204718334Speter /* There's no telling what that did to the condition codes. */ 204818334Speter CC_STATUS_INIT; 204918334Speter if (prescan > 0) 205018334Speter break; 205118334Speter 205218334Speter /* Get out the operand values. */ 205390087Sobrien string = decode_asm_operands (body, ops, NULL, NULL, NULL); 205418334Speter /* Inhibit aborts on what would otherwise be compiler bugs. */ 205518334Speter insn_noperands = noperands; 205618334Speter this_is_asm_operands = insn; 205718334Speter 2058132727Skan#ifdef FINAL_PRESCAN_INSN 2059132727Skan FINAL_PRESCAN_INSN (insn, ops, insn_noperands); 2060132727Skan#endif 2061132727Skan 206218334Speter /* Output the insn using them. */ 206390087Sobrien if (string[0]) 206490087Sobrien { 206590087Sobrien if (! app_on) 206690087Sobrien { 206790087Sobrien fputs (ASM_APP_ON, file); 206890087Sobrien app_on = 1; 206990087Sobrien } 207090087Sobrien output_asm_insn (string, ops); 207190087Sobrien } 207290087Sobrien 207318334Speter this_is_asm_operands = 0; 207418334Speter break; 207518334Speter } 207618334Speter 207718334Speter if (prescan <= 0 && app_on) 207818334Speter { 207950503Sobrien fputs (ASM_APP_OFF, file); 208018334Speter app_on = 0; 208118334Speter } 208218334Speter 208318334Speter if (GET_CODE (body) == SEQUENCE) 208418334Speter { 208518334Speter /* A delayed-branch sequence */ 208690087Sobrien int i; 208718334Speter rtx next; 208818334Speter 208918334Speter if (prescan > 0) 209018334Speter break; 209118334Speter final_sequence = body; 209218334Speter 2093132727Skan /* Record the delay slots' frame information before the branch. 2094132727Skan This is needed for delayed calls: see execute_cfa_program(). */ 2095132727Skan#if defined (DWARF2_UNWIND_INFO) 2096132727Skan if (dwarf2out_do_frame ()) 2097132727Skan for (i = 1; i < XVECLEN (body, 0); i++) 2098132727Skan dwarf2out_frame_debug (XVECEXP (body, 0, i)); 2099132727Skan#endif 2100132727Skan 210118334Speter /* The first insn in this SEQUENCE might be a JUMP_INSN that will 210218334Speter force the restoration of a comparison that was previously 210318334Speter thought unnecessary. If that happens, cancel this sequence 210418334Speter and cause that insn to be restored. */ 210518334Speter 2106132727Skan next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1, seen); 210718334Speter if (next != XVECEXP (body, 0, 1)) 210818334Speter { 210918334Speter final_sequence = 0; 211018334Speter return next; 211118334Speter } 211218334Speter 211318334Speter for (i = 1; i < XVECLEN (body, 0); i++) 211418334Speter { 211518334Speter rtx insn = XVECEXP (body, 0, i); 211618334Speter rtx next = NEXT_INSN (insn); 211718334Speter /* We loop in case any instruction in a delay slot gets 211818334Speter split. */ 211918334Speter do 2120132727Skan insn = final_scan_insn (insn, file, 0, prescan, 1, seen); 212118334Speter while (insn != next); 212218334Speter } 212318334Speter#ifdef DBR_OUTPUT_SEQEND 212418334Speter DBR_OUTPUT_SEQEND (file); 212518334Speter#endif 212618334Speter final_sequence = 0; 212718334Speter 212818334Speter /* If the insn requiring the delay slot was a CALL_INSN, the 212918334Speter insns in the delay slot are actually executed before the 213018334Speter called function. Hence we don't preserve any CC-setting 213118334Speter actions in these insns and the CC must be marked as being 213218334Speter clobbered by the function. */ 213318334Speter if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN) 213450503Sobrien { 213550503Sobrien CC_STATUS_INIT; 213650503Sobrien } 213718334Speter break; 213818334Speter } 213918334Speter 214018334Speter /* We have a real machine instruction as rtl. */ 214118334Speter 214218334Speter body = PATTERN (insn); 214318334Speter 214418334Speter#ifdef HAVE_cc0 214590087Sobrien set = single_set (insn); 214650503Sobrien 214718334Speter /* Check for redundant test and compare instructions 214818334Speter (when the condition codes are already set up as desired). 214918334Speter This is done only when optimizing; if not optimizing, 215018334Speter it should be possible for the user to alter a variable 215118334Speter with the debugger in between statements 215218334Speter and the next statement should reexamine the variable 215318334Speter to compute the condition codes. */ 215418334Speter 215550503Sobrien if (optimize) 215618334Speter { 215750503Sobrien if (set 215850503Sobrien && GET_CODE (SET_DEST (set)) == CC0 215950503Sobrien && insn != last_ignored_compare) 216018334Speter { 216150503Sobrien if (GET_CODE (SET_SRC (set)) == SUBREG) 216290087Sobrien SET_SRC (set) = alter_subreg (&SET_SRC (set)); 216350503Sobrien else if (GET_CODE (SET_SRC (set)) == COMPARE) 216418334Speter { 216550503Sobrien if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG) 216650503Sobrien XEXP (SET_SRC (set), 0) 216790087Sobrien = alter_subreg (&XEXP (SET_SRC (set), 0)); 216850503Sobrien if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG) 216950503Sobrien XEXP (SET_SRC (set), 1) 217090087Sobrien = alter_subreg (&XEXP (SET_SRC (set), 1)); 217118334Speter } 217250503Sobrien if ((cc_status.value1 != 0 217350503Sobrien && rtx_equal_p (SET_SRC (set), cc_status.value1)) 217450503Sobrien || (cc_status.value2 != 0 217550503Sobrien && rtx_equal_p (SET_SRC (set), cc_status.value2))) 217650503Sobrien { 217750503Sobrien /* Don't delete insn if it has an addressing side-effect. */ 217890087Sobrien if (! FIND_REG_INC_NOTE (insn, NULL_RTX) 217950503Sobrien /* or if anything in it is volatile. */ 218050503Sobrien && ! volatile_refs_p (PATTERN (insn))) 218150503Sobrien { 218250503Sobrien /* We don't really delete the insn; just ignore it. */ 218350503Sobrien last_ignored_compare = insn; 218450503Sobrien break; 218550503Sobrien } 218650503Sobrien } 218718334Speter } 218818334Speter } 218918334Speter#endif 219018334Speter 219118334Speter#ifndef STACK_REGS 219218334Speter /* Don't bother outputting obvious no-ops, even without -O. 219318334Speter This optimization is fast and doesn't interfere with debugging. 219418334Speter Don't do this if the insn is in a delay slot, since this 219518334Speter will cause an improper number of delay insns to be written. */ 219618334Speter if (final_sequence == 0 219718334Speter && prescan >= 0 219818334Speter && GET_CODE (insn) == INSN && GET_CODE (body) == SET 219918334Speter && GET_CODE (SET_SRC (body)) == REG 220018334Speter && GET_CODE (SET_DEST (body)) == REG 220118334Speter && REGNO (SET_SRC (body)) == REGNO (SET_DEST (body))) 220218334Speter break; 220318334Speter#endif 220418334Speter 220518334Speter#ifdef HAVE_cc0 220618334Speter /* If this is a conditional branch, maybe modify it 220718334Speter if the cc's are in a nonstandard state 220818334Speter so that it accomplishes the same thing that it would 220918334Speter do straightforwardly if the cc's were set up normally. */ 221018334Speter 221118334Speter if (cc_status.flags != 0 221218334Speter && GET_CODE (insn) == JUMP_INSN 221318334Speter && GET_CODE (body) == SET 221418334Speter && SET_DEST (body) == pc_rtx 221518334Speter && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE 221618334Speter && GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (body), 0))) == '<' 221718334Speter && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx 221818334Speter /* This is done during prescan; it is not done again 221918334Speter in final scan when prescan has been done. */ 222018334Speter && prescan >= 0) 222118334Speter { 222218334Speter /* This function may alter the contents of its argument 222318334Speter and clear some of the cc_status.flags bits. 222418334Speter It may also return 1 meaning condition now always true 222518334Speter or -1 meaning condition now always false 222618334Speter or 2 meaning condition nontrivial but altered. */ 222790087Sobrien int result = alter_cond (XEXP (SET_SRC (body), 0)); 222818334Speter /* If condition now has fixed value, replace the IF_THEN_ELSE 222918334Speter with its then-operand or its else-operand. */ 223018334Speter if (result == 1) 223118334Speter SET_SRC (body) = XEXP (SET_SRC (body), 1); 223218334Speter if (result == -1) 223318334Speter SET_SRC (body) = XEXP (SET_SRC (body), 2); 223418334Speter 223518334Speter /* The jump is now either unconditional or a no-op. 223618334Speter If it has become a no-op, don't try to output it. 223718334Speter (It would not be recognized.) */ 223818334Speter if (SET_SRC (body) == pc_rtx) 223918334Speter { 224090087Sobrien delete_insn (insn); 224118334Speter break; 224218334Speter } 224318334Speter else if (GET_CODE (SET_SRC (body)) == RETURN) 224418334Speter /* Replace (set (pc) (return)) with (return). */ 224518334Speter PATTERN (insn) = body = SET_SRC (body); 224618334Speter 224718334Speter /* Rerecognize the instruction if it has changed. */ 224818334Speter if (result != 0) 224918334Speter INSN_CODE (insn) = -1; 225018334Speter } 225118334Speter 225218334Speter /* Make same adjustments to instructions that examine the 225350503Sobrien condition codes without jumping and instructions that 225450503Sobrien handle conditional moves (if this machine has either one). */ 225518334Speter 225618334Speter if (cc_status.flags != 0 225750503Sobrien && set != 0) 225818334Speter { 225950503Sobrien rtx cond_rtx, then_rtx, else_rtx; 226090087Sobrien 226150503Sobrien if (GET_CODE (insn) != JUMP_INSN 226250503Sobrien && GET_CODE (SET_SRC (set)) == IF_THEN_ELSE) 226318334Speter { 226450503Sobrien cond_rtx = XEXP (SET_SRC (set), 0); 226550503Sobrien then_rtx = XEXP (SET_SRC (set), 1); 226650503Sobrien else_rtx = XEXP (SET_SRC (set), 2); 226750503Sobrien } 226850503Sobrien else 226950503Sobrien { 227050503Sobrien cond_rtx = SET_SRC (set); 227150503Sobrien then_rtx = const_true_rtx; 227250503Sobrien else_rtx = const0_rtx; 227350503Sobrien } 227490087Sobrien 227550503Sobrien switch (GET_CODE (cond_rtx)) 227650503Sobrien { 227718334Speter case GTU: 227818334Speter case GT: 227918334Speter case LTU: 228018334Speter case LT: 228118334Speter case GEU: 228218334Speter case GE: 228318334Speter case LEU: 228418334Speter case LE: 228518334Speter case EQ: 228618334Speter case NE: 228718334Speter { 228890087Sobrien int result; 228950503Sobrien if (XEXP (cond_rtx, 0) != cc0_rtx) 229018334Speter break; 229150503Sobrien result = alter_cond (cond_rtx); 229218334Speter if (result == 1) 229350503Sobrien validate_change (insn, &SET_SRC (set), then_rtx, 0); 229418334Speter else if (result == -1) 229550503Sobrien validate_change (insn, &SET_SRC (set), else_rtx, 0); 229618334Speter else if (result == 2) 229718334Speter INSN_CODE (insn) = -1; 229850503Sobrien if (SET_DEST (set) == SET_SRC (set)) 229990087Sobrien delete_insn (insn); 230018334Speter } 230150503Sobrien break; 230250503Sobrien 230350503Sobrien default: 230450503Sobrien break; 230518334Speter } 230618334Speter } 230750503Sobrien 230818334Speter#endif 230918334Speter 231090087Sobrien#ifdef HAVE_peephole 231118334Speter /* Do machine-specific peephole optimizations if desired. */ 231218334Speter 231318334Speter if (optimize && !flag_no_peephole && !nopeepholes) 231418334Speter { 231518334Speter rtx next = peephole (insn); 231618334Speter /* When peepholing, if there were notes within the peephole, 231718334Speter emit them before the peephole. */ 231818334Speter if (next != 0 && next != NEXT_INSN (insn)) 231918334Speter { 232018334Speter rtx prev = PREV_INSN (insn); 232118334Speter 232218334Speter for (note = NEXT_INSN (insn); note != next; 232318334Speter note = NEXT_INSN (note)) 2324132727Skan final_scan_insn (note, file, optimize, prescan, nopeepholes, seen); 232518334Speter 232618334Speter /* In case this is prescan, put the notes 232718334Speter in proper position for later rescan. */ 232818334Speter note = NEXT_INSN (insn); 232918334Speter PREV_INSN (note) = prev; 233018334Speter NEXT_INSN (prev) = note; 233118334Speter NEXT_INSN (PREV_INSN (next)) = insn; 233218334Speter PREV_INSN (insn) = PREV_INSN (next); 233318334Speter NEXT_INSN (insn) = next; 233418334Speter PREV_INSN (next) = insn; 233518334Speter } 233618334Speter 233718334Speter /* PEEPHOLE might have changed this. */ 233818334Speter body = PATTERN (insn); 233918334Speter } 234090087Sobrien#endif 234118334Speter 234218334Speter /* Try to recognize the instruction. 234318334Speter If successful, verify that the operands satisfy the 234418334Speter constraints for the instruction. Crash if they don't, 234518334Speter since `reload' should have changed them so that they do. */ 234618334Speter 234718334Speter insn_code_number = recog_memoized (insn); 234852515Sobrien cleanup_subreg_operands (insn); 234918334Speter 2350117404Skan /* Dump the insn in the assembly for debugging. */ 2351117404Skan if (flag_dump_rtl_in_asm) 2352117404Skan { 2353117404Skan print_rtx_head = ASM_COMMENT_START; 2354117404Skan print_rtl_single (asm_out_file, insn); 2355117404Skan print_rtx_head = ""; 2356117404Skan } 235790087Sobrien 235890087Sobrien if (! constrain_operands_cached (1)) 235918334Speter fatal_insn_not_found (insn); 236018334Speter 236118334Speter /* Some target machines need to prescan each insn before 236218334Speter it is output. */ 236318334Speter 236418334Speter#ifdef FINAL_PRESCAN_INSN 236590087Sobrien FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands); 236618334Speter#endif 236718334Speter 236890087Sobrien#ifdef HAVE_conditional_execution 236990087Sobrien if (GET_CODE (PATTERN (insn)) == COND_EXEC) 237090087Sobrien current_insn_predicate = COND_EXEC_TEST (PATTERN (insn)); 237190087Sobrien else 237290087Sobrien current_insn_predicate = NULL_RTX; 237390087Sobrien#endif 237490087Sobrien 237518334Speter#ifdef HAVE_cc0 237618334Speter cc_prev_status = cc_status; 237718334Speter 237818334Speter /* Update `cc_status' for this instruction. 237918334Speter The instruction's output routine may change it further. 238018334Speter If the output routine for a jump insn needs to depend 238118334Speter on the cc status, it should look at cc_prev_status. */ 238218334Speter 238318334Speter NOTICE_UPDATE_CC (body, insn); 238418334Speter#endif 238518334Speter 238690087Sobrien current_output_insn = debug_insn = insn; 238718334Speter 238890087Sobrien#if defined (DWARF2_UNWIND_INFO) 238950503Sobrien if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ()) 239050503Sobrien dwarf2out_frame_debug (insn); 239150503Sobrien#endif 239250503Sobrien 239390087Sobrien /* Find the proper template for this insn. */ 239490087Sobrien template = get_insn_template (insn_code_number, insn); 239518334Speter 239690087Sobrien /* If the C code returns 0, it means that it is a jump insn 239790087Sobrien which follows a deleted test insn, and that test insn 239890087Sobrien needs to be reinserted. */ 239918334Speter if (template == 0) 240018334Speter { 240190087Sobrien rtx prev; 240218334Speter 240390087Sobrien if (prev_nonnote_insn (insn) != last_ignored_compare) 240490087Sobrien abort (); 240590087Sobrien 240690087Sobrien /* We have already processed the notes between the setter and 240790087Sobrien the user. Make sure we don't process them again, this is 240890087Sobrien particularly important if one of the notes is a block 240990087Sobrien scope note or an EH note. */ 241090087Sobrien for (prev = insn; 241190087Sobrien prev != last_ignored_compare; 241290087Sobrien prev = PREV_INSN (prev)) 241318334Speter { 241490087Sobrien if (GET_CODE (prev) == NOTE) 241590087Sobrien delete_insn (prev); /* Use delete_note. */ 241618334Speter } 241790087Sobrien 241890087Sobrien return prev; 241918334Speter } 242018334Speter 242118334Speter /* If the template is the string "#", it means that this insn must 242218334Speter be split. */ 242318334Speter if (template[0] == '#' && template[1] == '\0') 242418334Speter { 242518334Speter rtx new = try_split (body, insn, 0); 242618334Speter 242718334Speter /* If we didn't split the insn, go away. */ 242818334Speter if (new == insn && PATTERN (new) == body) 242990087Sobrien fatal_insn ("could not split insn", insn); 243090087Sobrien 243150503Sobrien#ifdef HAVE_ATTR_length 243250503Sobrien /* This instruction should have been split in shorten_branches, 243350503Sobrien to ensure that we would have valid length info for the 243450503Sobrien splitees. */ 243550503Sobrien abort (); 243650503Sobrien#endif 243750503Sobrien 243818334Speter return new; 243918334Speter } 244090087Sobrien 244118334Speter if (prescan > 0) 244218334Speter break; 244318334Speter 244490087Sobrien#ifdef IA64_UNWIND_INFO 244590087Sobrien IA64_UNWIND_EMIT (asm_out_file, insn); 244690087Sobrien#endif 244718334Speter /* Output assembler code from the template. */ 244818334Speter 244990087Sobrien output_asm_insn (template, recog_data.operand); 245018334Speter 2451132727Skan /* If necessary, report the effect that the instruction has on 2452132727Skan the unwind info. We've already done this for delay slots 2453132727Skan and call instructions. */ 245450503Sobrien#if defined (DWARF2_UNWIND_INFO) 2455132727Skan if (GET_CODE (insn) == INSN 2456132727Skan#if !defined (HAVE_prologue) 2457132727Skan && !ACCUMULATE_OUTGOING_ARGS 2458132727Skan#endif 2459132727Skan && final_sequence == 0 246090087Sobrien && dwarf2out_do_frame ()) 246150503Sobrien dwarf2out_frame_debug (insn); 246250503Sobrien#endif 246350503Sobrien 246418334Speter#if 0 2465132727Skan /* It's not at all clear why we did this and doing so used to 2466132727Skan interfere with tests that used REG_WAS_0 notes, which are 2467132727Skan now gone, so let's try with this out. */ 246818334Speter 246918334Speter /* Mark this insn as having been output. */ 247018334Speter INSN_DELETED_P (insn) = 1; 247118334Speter#endif 247218334Speter 247390087Sobrien /* Emit information for vtable gc. */ 247490087Sobrien note = find_reg_note (insn, REG_VTABLE_REF, NULL_RTX); 247590087Sobrien 247690087Sobrien current_output_insn = debug_insn = 0; 247718334Speter } 247818334Speter } 247918334Speter return NEXT_INSN (insn); 248018334Speter} 248118334Speter 248218334Speter/* Output debugging info to the assembler file FILE 248318334Speter based on the NOTE-insn INSN, assumed to be a line number. */ 248418334Speter 2485132727Skanstatic bool 2486132727Skannotice_source_line (rtx insn) 248718334Speter{ 2488132727Skan const char *filename = insn_file (insn); 2489132727Skan int linenum = insn_line (insn); 249018334Speter 2491132727Skan if (filename && (filename != last_filename || last_linenum != linenum)) 2492132727Skan { 2493132727Skan last_filename = filename; 2494132727Skan last_linenum = linenum; 2495132727Skan high_block_linenum = MAX (last_linenum, high_block_linenum); 2496132727Skan high_function_linenum = MAX (last_linenum, high_function_linenum); 2497132727Skan return true; 2498132727Skan } 2499132727Skan return false; 250018334Speter} 250118334Speter 250252515Sobrien/* For each operand in INSN, simplify (subreg (reg)) so that it refers 250352515Sobrien directly to the desired hard register. */ 250490087Sobrien 250552515Sobrienvoid 2506132727Skancleanup_subreg_operands (rtx insn) 250752515Sobrien{ 250852515Sobrien int i; 250990087Sobrien extract_insn_cached (insn); 251090087Sobrien for (i = 0; i < recog_data.n_operands; i++) 251152515Sobrien { 2512132727Skan /* The following test cannot use recog_data.operand when testing 251390087Sobrien for a SUBREG: the underlying object might have been changed 251490087Sobrien already if we are inside a match_operator expression that 251590087Sobrien matches the else clause. Instead we test the underlying 251690087Sobrien expression directly. */ 251790087Sobrien if (GET_CODE (*recog_data.operand_loc[i]) == SUBREG) 251890087Sobrien recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]); 251990087Sobrien else if (GET_CODE (recog_data.operand[i]) == PLUS 252090087Sobrien || GET_CODE (recog_data.operand[i]) == MULT 252190087Sobrien || GET_CODE (recog_data.operand[i]) == MEM) 252290087Sobrien recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i]); 252352515Sobrien } 252452515Sobrien 252590087Sobrien for (i = 0; i < recog_data.n_dups; i++) 252652515Sobrien { 252790087Sobrien if (GET_CODE (*recog_data.dup_loc[i]) == SUBREG) 252890087Sobrien *recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]); 252990087Sobrien else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS 253090087Sobrien || GET_CODE (*recog_data.dup_loc[i]) == MULT 253190087Sobrien || GET_CODE (*recog_data.dup_loc[i]) == MEM) 253290087Sobrien *recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]); 253352515Sobrien } 253452515Sobrien} 253552515Sobrien 253618334Speter/* If X is a SUBREG, replace it with a REG or a MEM, 253718334Speter based on the thing it is a subreg of. */ 253818334Speter 253918334Speterrtx 2540132727Skanalter_subreg (rtx *xp) 254118334Speter{ 254290087Sobrien rtx x = *xp; 254390087Sobrien rtx y = SUBREG_REG (x); 254450503Sobrien 254590087Sobrien /* simplify_subreg does not remove subreg from volatile references. 254690087Sobrien We are required to. */ 254790087Sobrien if (GET_CODE (y) == MEM) 254890087Sobrien *xp = adjust_address (y, GET_MODE (x), SUBREG_BYTE (x)); 254990087Sobrien else 255018334Speter { 255190087Sobrien rtx new = simplify_subreg (GET_MODE (x), y, GET_MODE (y), 255290087Sobrien SUBREG_BYTE (x)); 255350503Sobrien 255490087Sobrien if (new != 0) 255590087Sobrien *xp = new; 255690087Sobrien /* Simplify_subreg can't handle some REG cases, but we have to. */ 255790087Sobrien else if (GET_CODE (y) == REG) 255890087Sobrien { 255990087Sobrien unsigned int regno = subreg_hard_regno (x, 1); 2560132727Skan *xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, SUBREG_BYTE (x)); 256190087Sobrien } 256290087Sobrien else 256390087Sobrien abort (); 256418334Speter } 256518334Speter 256690087Sobrien return *xp; 256718334Speter} 256818334Speter 256918334Speter/* Do alter_subreg on all the SUBREGs contained in X. */ 257018334Speter 257118334Speterstatic rtx 2572132727Skanwalk_alter_subreg (rtx *xp) 257318334Speter{ 257490087Sobrien rtx x = *xp; 257518334Speter switch (GET_CODE (x)) 257618334Speter { 257718334Speter case PLUS: 257818334Speter case MULT: 257990087Sobrien XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0)); 258090087Sobrien XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1)); 258118334Speter break; 258218334Speter 258318334Speter case MEM: 258490087Sobrien XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0)); 258518334Speter break; 258618334Speter 258718334Speter case SUBREG: 258890087Sobrien return alter_subreg (xp); 258990087Sobrien 259050503Sobrien default: 259150503Sobrien break; 259218334Speter } 259318334Speter 259490087Sobrien return *xp; 259518334Speter} 259618334Speter 259718334Speter#ifdef HAVE_cc0 259818334Speter 259918334Speter/* Given BODY, the body of a jump instruction, alter the jump condition 260018334Speter as required by the bits that are set in cc_status.flags. 260118334Speter Not all of the bits there can be handled at this level in all cases. 260218334Speter 260318334Speter The value is normally 0. 260418334Speter 1 means that the condition has become always true. 260518334Speter -1 means that the condition has become always false. 260618334Speter 2 means that COND has been altered. */ 260718334Speter 260818334Speterstatic int 2609132727Skanalter_cond (rtx cond) 261018334Speter{ 261118334Speter int value = 0; 261218334Speter 261318334Speter if (cc_status.flags & CC_REVERSED) 261418334Speter { 261518334Speter value = 2; 261618334Speter PUT_CODE (cond, swap_condition (GET_CODE (cond))); 261718334Speter } 261818334Speter 261918334Speter if (cc_status.flags & CC_INVERTED) 262018334Speter { 262118334Speter value = 2; 262218334Speter PUT_CODE (cond, reverse_condition (GET_CODE (cond))); 262318334Speter } 262418334Speter 262518334Speter if (cc_status.flags & CC_NOT_POSITIVE) 262618334Speter switch (GET_CODE (cond)) 262718334Speter { 262818334Speter case LE: 262918334Speter case LEU: 263018334Speter case GEU: 263118334Speter /* Jump becomes unconditional. */ 263218334Speter return 1; 263318334Speter 263418334Speter case GT: 263518334Speter case GTU: 263618334Speter case LTU: 263718334Speter /* Jump becomes no-op. */ 263818334Speter return -1; 263918334Speter 264018334Speter case GE: 264118334Speter PUT_CODE (cond, EQ); 264218334Speter value = 2; 264318334Speter break; 264418334Speter 264518334Speter case LT: 264618334Speter PUT_CODE (cond, NE); 264718334Speter value = 2; 264818334Speter break; 264990087Sobrien 265050503Sobrien default: 265150503Sobrien break; 265218334Speter } 265318334Speter 265418334Speter if (cc_status.flags & CC_NOT_NEGATIVE) 265518334Speter switch (GET_CODE (cond)) 265618334Speter { 265718334Speter case GE: 265818334Speter case GEU: 265918334Speter /* Jump becomes unconditional. */ 266018334Speter return 1; 266118334Speter 266218334Speter case LT: 266318334Speter case LTU: 266418334Speter /* Jump becomes no-op. */ 266518334Speter return -1; 266618334Speter 266718334Speter case LE: 266818334Speter case LEU: 266918334Speter PUT_CODE (cond, EQ); 267018334Speter value = 2; 267118334Speter break; 267218334Speter 267318334Speter case GT: 267418334Speter case GTU: 267518334Speter PUT_CODE (cond, NE); 267618334Speter value = 2; 267718334Speter break; 267890087Sobrien 267950503Sobrien default: 268050503Sobrien break; 268118334Speter } 268218334Speter 268318334Speter if (cc_status.flags & CC_NO_OVERFLOW) 268418334Speter switch (GET_CODE (cond)) 268518334Speter { 268618334Speter case GEU: 268718334Speter /* Jump becomes unconditional. */ 268818334Speter return 1; 268918334Speter 269018334Speter case LEU: 269118334Speter PUT_CODE (cond, EQ); 269218334Speter value = 2; 269318334Speter break; 269418334Speter 269518334Speter case GTU: 269618334Speter PUT_CODE (cond, NE); 269718334Speter value = 2; 269818334Speter break; 269918334Speter 270018334Speter case LTU: 270118334Speter /* Jump becomes no-op. */ 270218334Speter return -1; 270390087Sobrien 270450503Sobrien default: 270550503Sobrien break; 270618334Speter } 270718334Speter 270818334Speter if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N)) 270918334Speter switch (GET_CODE (cond)) 271018334Speter { 271150503Sobrien default: 271218334Speter abort (); 271318334Speter 271418334Speter case NE: 271518334Speter PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT); 271618334Speter value = 2; 271718334Speter break; 271818334Speter 271918334Speter case EQ: 272018334Speter PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE); 272118334Speter value = 2; 272218334Speter break; 272318334Speter } 272418334Speter 272518334Speter if (cc_status.flags & CC_NOT_SIGNED) 272618334Speter /* The flags are valid if signed condition operators are converted 272718334Speter to unsigned. */ 272818334Speter switch (GET_CODE (cond)) 272918334Speter { 273018334Speter case LE: 273118334Speter PUT_CODE (cond, LEU); 273218334Speter value = 2; 273318334Speter break; 273418334Speter 273518334Speter case LT: 273618334Speter PUT_CODE (cond, LTU); 273718334Speter value = 2; 273818334Speter break; 273918334Speter 274018334Speter case GT: 274118334Speter PUT_CODE (cond, GTU); 274218334Speter value = 2; 274318334Speter break; 274418334Speter 274518334Speter case GE: 274618334Speter PUT_CODE (cond, GEU); 274718334Speter value = 2; 274818334Speter break; 274950503Sobrien 275050503Sobrien default: 275150503Sobrien break; 275218334Speter } 275318334Speter 275418334Speter return value; 275518334Speter} 275618334Speter#endif 275718334Speter 275818334Speter/* Report inconsistency between the assembler template and the operands. 275918334Speter In an `asm', it's the user's fault; otherwise, the compiler's fault. */ 276018334Speter 276118334Spetervoid 2762132727Skanoutput_operand_lossage (const char *msgid, ...) 276318334Speter{ 276496281Sobrien char *fmt_string; 276596281Sobrien char *new_message; 276696281Sobrien const char *pfx_str; 2767132727Skan va_list ap; 276896281Sobrien 2769132727Skan va_start (ap, msgid); 2770132727Skan 277196281Sobrien pfx_str = this_is_asm_operands ? _("invalid `asm': ") : "output_operand: "; 277296281Sobrien asprintf (&fmt_string, "%s%s", pfx_str, _(msgid)); 277396281Sobrien vasprintf (&new_message, fmt_string, ap); 2774117404Skan 277518334Speter if (this_is_asm_operands) 277696281Sobrien error_for_asm (this_is_asm_operands, "%s", new_message); 277718334Speter else 277896281Sobrien internal_error ("%s", new_message); 277996281Sobrien 278096281Sobrien free (fmt_string); 278196281Sobrien free (new_message); 2782132727Skan va_end (ap); 278318334Speter} 278418334Speter 278518334Speter/* Output of assembler code from a template, and its subroutines. */ 278618334Speter 278790087Sobrien/* Annotate the assembly with a comment describing the pattern and 278890087Sobrien alternative used. */ 278990087Sobrien 279090087Sobrienstatic void 2791132727Skanoutput_asm_name (void) 279290087Sobrien{ 279390087Sobrien if (debug_insn) 279490087Sobrien { 279590087Sobrien int num = INSN_CODE (debug_insn); 279690087Sobrien fprintf (asm_out_file, "\t%s %d\t%s", 279790087Sobrien ASM_COMMENT_START, INSN_UID (debug_insn), 279890087Sobrien insn_data[num].name); 279990087Sobrien if (insn_data[num].n_alternatives > 1) 280090087Sobrien fprintf (asm_out_file, "/%d", which_alternative + 1); 280190087Sobrien#ifdef HAVE_ATTR_length 280290087Sobrien fprintf (asm_out_file, "\t[length = %d]", 280390087Sobrien get_attr_length (debug_insn)); 280490087Sobrien#endif 280590087Sobrien /* Clear this so only the first assembler insn 280690087Sobrien of any rtl insn will get the special comment for -dp. */ 280790087Sobrien debug_insn = 0; 280890087Sobrien } 280990087Sobrien} 281090087Sobrien 281190087Sobrien/* If OP is a REG or MEM and we can find a MEM_EXPR corresponding to it 281290087Sobrien or its address, return that expr . Set *PADDRESSP to 1 if the expr 281390087Sobrien corresponds to the address of the object and 0 if to the object. */ 281490087Sobrien 281590087Sobrienstatic tree 2816132727Skanget_mem_expr_from_op (rtx op, int *paddressp) 281790087Sobrien{ 281890087Sobrien tree expr; 281990087Sobrien int inner_addressp; 282090087Sobrien 282190087Sobrien *paddressp = 0; 282290087Sobrien 2823132727Skan if (GET_CODE (op) == REG) 2824132727Skan return REG_EXPR (op); 282590087Sobrien else if (GET_CODE (op) != MEM) 282690087Sobrien return 0; 282790087Sobrien 282890087Sobrien if (MEM_EXPR (op) != 0) 282990087Sobrien return MEM_EXPR (op); 283090087Sobrien 283190087Sobrien /* Otherwise we have an address, so indicate it and look at the address. */ 283290087Sobrien *paddressp = 1; 283390087Sobrien op = XEXP (op, 0); 283490087Sobrien 283590087Sobrien /* First check if we have a decl for the address, then look at the right side 283690087Sobrien if it is a PLUS. Otherwise, strip off arithmetic and keep looking. 283790087Sobrien But don't allow the address to itself be indirect. */ 283890087Sobrien if ((expr = get_mem_expr_from_op (op, &inner_addressp)) && ! inner_addressp) 283990087Sobrien return expr; 284090087Sobrien else if (GET_CODE (op) == PLUS 284190087Sobrien && (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp))) 284290087Sobrien return expr; 284390087Sobrien 284490087Sobrien while (GET_RTX_CLASS (GET_CODE (op)) == '1' 284590087Sobrien || GET_RTX_CLASS (GET_CODE (op)) == '2') 284690087Sobrien op = XEXP (op, 0); 284790087Sobrien 284890087Sobrien expr = get_mem_expr_from_op (op, &inner_addressp); 284990087Sobrien return inner_addressp ? 0 : expr; 285090087Sobrien} 285190087Sobrien 285290087Sobrien/* Output operand names for assembler instructions. OPERANDS is the 285390087Sobrien operand vector, OPORDER is the order to write the operands, and NOPS 285490087Sobrien is the number of operands to write. */ 285590087Sobrien 285690087Sobrienstatic void 2857132727Skanoutput_asm_operand_names (rtx *operands, int *oporder, int nops) 285890087Sobrien{ 285990087Sobrien int wrote = 0; 286090087Sobrien int i; 286190087Sobrien 286290087Sobrien for (i = 0; i < nops; i++) 286390087Sobrien { 286490087Sobrien int addressp; 2865132727Skan rtx op = operands[oporder[i]]; 2866132727Skan tree expr = get_mem_expr_from_op (op, &addressp); 286790087Sobrien 2868132727Skan fprintf (asm_out_file, "%c%s", 2869132727Skan wrote ? ',' : '\t', wrote ? "" : ASM_COMMENT_START); 2870132727Skan wrote = 1; 287190087Sobrien if (expr) 287290087Sobrien { 2873132727Skan fprintf (asm_out_file, "%s", 287490087Sobrien addressp ? "*" : ""); 287590087Sobrien print_mem_expr (asm_out_file, expr); 287690087Sobrien wrote = 1; 287790087Sobrien } 2878132727Skan else if (REG_P (op) && ORIGINAL_REGNO (op) 2879132727Skan && ORIGINAL_REGNO (op) != REGNO (op)) 2880132727Skan fprintf (asm_out_file, " tmp%i", ORIGINAL_REGNO (op)); 288190087Sobrien } 288290087Sobrien} 288390087Sobrien 288418334Speter/* Output text from TEMPLATE to the assembler output file, 288518334Speter obeying %-directions to substitute operands taken from 288618334Speter the vector OPERANDS. 288718334Speter 288818334Speter %N (for N a digit) means print operand N in usual manner. 288918334Speter %lN means require operand N to be a CODE_LABEL or LABEL_REF 289018334Speter and print the label name with no punctuation. 289118334Speter %cN means require operand N to be a constant 289218334Speter and print the constant expression with no punctuation. 289318334Speter %aN means expect operand N to be a memory address 289418334Speter (not a memory reference!) and print a reference 289518334Speter to that address. 289618334Speter %nN means expect operand N to be a constant 289718334Speter and print a constant expression for minus the value 289818334Speter of the operand, with no other punctuation. */ 289918334Speter 290018334Spetervoid 2901132727Skanoutput_asm_insn (const char *template, rtx *operands) 290218334Speter{ 290390087Sobrien const char *p; 290490087Sobrien int c; 290590087Sobrien#ifdef ASSEMBLER_DIALECT 290690087Sobrien int dialect = 0; 290790087Sobrien#endif 290890087Sobrien int oporder[MAX_RECOG_OPERANDS]; 290990087Sobrien char opoutput[MAX_RECOG_OPERANDS]; 291090087Sobrien int ops = 0; 291118334Speter 291218334Speter /* An insn may return a null string template 291318334Speter in a case where no assembler code is needed. */ 291418334Speter if (*template == 0) 291518334Speter return; 291618334Speter 291790087Sobrien memset (opoutput, 0, sizeof opoutput); 291818334Speter p = template; 291918334Speter putc ('\t', asm_out_file); 292018334Speter 292118334Speter#ifdef ASM_OUTPUT_OPCODE 292218334Speter ASM_OUTPUT_OPCODE (asm_out_file, p); 292318334Speter#endif 292418334Speter 292550503Sobrien while ((c = *p++)) 292618334Speter switch (c) 292718334Speter { 292818334Speter case '\n': 292990087Sobrien if (flag_verbose_asm) 293090087Sobrien output_asm_operand_names (operands, oporder, ops); 293190087Sobrien if (flag_print_asm_name) 293290087Sobrien output_asm_name (); 293390087Sobrien 293490087Sobrien ops = 0; 293590087Sobrien memset (opoutput, 0, sizeof opoutput); 293690087Sobrien 293718334Speter putc (c, asm_out_file); 293818334Speter#ifdef ASM_OUTPUT_OPCODE 293918334Speter while ((c = *p) == '\t') 294018334Speter { 294118334Speter putc (c, asm_out_file); 294218334Speter p++; 294318334Speter } 294418334Speter ASM_OUTPUT_OPCODE (asm_out_file, p); 294518334Speter#endif 294618334Speter break; 294718334Speter 294818334Speter#ifdef ASSEMBLER_DIALECT 294918334Speter case '{': 295050503Sobrien { 295190087Sobrien int i; 295290087Sobrien 295390087Sobrien if (dialect) 295490087Sobrien output_operand_lossage ("nested assembly dialect alternatives"); 295590087Sobrien else 295690087Sobrien dialect = 1; 295790087Sobrien 295850503Sobrien /* If we want the first dialect, do nothing. Otherwise, skip 295950503Sobrien DIALECT_NUMBER of strings ending with '|'. */ 296050503Sobrien for (i = 0; i < dialect_number; i++) 296150503Sobrien { 296290087Sobrien while (*p && *p != '}' && *p++ != '|') 296350503Sobrien ; 296490087Sobrien if (*p == '}') 296590087Sobrien break; 296650503Sobrien if (*p == '|') 296750503Sobrien p++; 296850503Sobrien } 296990087Sobrien 297090087Sobrien if (*p == '\0') 297190087Sobrien output_operand_lossage ("unterminated assembly dialect alternative"); 297250503Sobrien } 297318334Speter break; 297418334Speter 297518334Speter case '|': 297690087Sobrien if (dialect) 297790087Sobrien { 297890087Sobrien /* Skip to close brace. */ 297990087Sobrien do 298090087Sobrien { 298190087Sobrien if (*p == '\0') 298290087Sobrien { 298390087Sobrien output_operand_lossage ("unterminated assembly dialect alternative"); 298490087Sobrien break; 298590087Sobrien } 298690087Sobrien } 298790087Sobrien while (*p++ != '}'); 298890087Sobrien dialect = 0; 298990087Sobrien } 299090087Sobrien else 299190087Sobrien putc (c, asm_out_file); 299218334Speter break; 299318334Speter 299418334Speter case '}': 299590087Sobrien if (! dialect) 299690087Sobrien putc (c, asm_out_file); 299790087Sobrien dialect = 0; 299818334Speter break; 299918334Speter#endif 300018334Speter 300118334Speter case '%': 300218334Speter /* %% outputs a single %. */ 300318334Speter if (*p == '%') 300418334Speter { 300518334Speter p++; 300618334Speter putc (c, asm_out_file); 300718334Speter } 300818334Speter /* %= outputs a number which is unique to each insn in the entire 300918334Speter compilation. This is useful for making local labels that are 301018334Speter referred to more than once in a given insn. */ 301118334Speter else if (*p == '=') 301218334Speter { 301318334Speter p++; 301418334Speter fprintf (asm_out_file, "%d", insn_counter); 301518334Speter } 301618334Speter /* % followed by a letter and some digits 301718334Speter outputs an operand in a special way depending on the letter. 301818334Speter Letters `acln' are implemented directly. 301918334Speter Other letters are passed to `output_operand' so that 302018334Speter the PRINT_OPERAND macro can define them. */ 302190087Sobrien else if (ISALPHA (*p)) 302218334Speter { 302318334Speter int letter = *p++; 302418334Speter c = atoi (p); 302518334Speter 302690087Sobrien if (! ISDIGIT (*p)) 302796281Sobrien output_operand_lossage ("operand number missing after %%-letter"); 302890087Sobrien else if (this_is_asm_operands 302990087Sobrien && (c < 0 || (unsigned int) c >= insn_noperands)) 303018334Speter output_operand_lossage ("operand number out of range"); 303118334Speter else if (letter == 'l') 303218334Speter output_asm_label (operands[c]); 303318334Speter else if (letter == 'a') 303418334Speter output_address (operands[c]); 303518334Speter else if (letter == 'c') 303618334Speter { 303718334Speter if (CONSTANT_ADDRESS_P (operands[c])) 303818334Speter output_addr_const (asm_out_file, operands[c]); 303918334Speter else 304018334Speter output_operand (operands[c], 'c'); 304118334Speter } 304218334Speter else if (letter == 'n') 304318334Speter { 304418334Speter if (GET_CODE (operands[c]) == CONST_INT) 304550503Sobrien fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, 304618334Speter - INTVAL (operands[c])); 304718334Speter else 304818334Speter { 304918334Speter putc ('-', asm_out_file); 305018334Speter output_addr_const (asm_out_file, operands[c]); 305118334Speter } 305218334Speter } 305318334Speter else 305418334Speter output_operand (operands[c], letter); 305590087Sobrien 305690087Sobrien if (!opoutput[c]) 305790087Sobrien oporder[ops++] = c; 305890087Sobrien opoutput[c] = 1; 305990087Sobrien 306090087Sobrien while (ISDIGIT (c = *p)) 306190087Sobrien p++; 306218334Speter } 306318334Speter /* % followed by a digit outputs an operand the default way. */ 306490087Sobrien else if (ISDIGIT (*p)) 306518334Speter { 306618334Speter c = atoi (p); 306790087Sobrien if (this_is_asm_operands 306890087Sobrien && (c < 0 || (unsigned int) c >= insn_noperands)) 306918334Speter output_operand_lossage ("operand number out of range"); 307018334Speter else 307118334Speter output_operand (operands[c], 0); 307290087Sobrien 307390087Sobrien if (!opoutput[c]) 307490087Sobrien oporder[ops++] = c; 307590087Sobrien opoutput[c] = 1; 307690087Sobrien 307790087Sobrien while (ISDIGIT (c = *p)) 307890087Sobrien p++; 307918334Speter } 308018334Speter /* % followed by punctuation: output something for that 308118334Speter punctuation character alone, with no operand. 308218334Speter The PRINT_OPERAND macro decides what is actually done. */ 308318334Speter#ifdef PRINT_OPERAND_PUNCT_VALID_P 308490087Sobrien else if (PRINT_OPERAND_PUNCT_VALID_P ((unsigned char) *p)) 308518334Speter output_operand (NULL_RTX, *p++); 308618334Speter#endif 308718334Speter else 308818334Speter output_operand_lossage ("invalid %%-code"); 308918334Speter break; 309018334Speter 309118334Speter default: 309218334Speter putc (c, asm_out_file); 309318334Speter } 309418334Speter 309590087Sobrien /* Write out the variable names for operands, if we know them. */ 309690087Sobrien if (flag_verbose_asm) 309790087Sobrien output_asm_operand_names (operands, oporder, ops); 309890087Sobrien if (flag_print_asm_name) 309990087Sobrien output_asm_name (); 310018334Speter 310118334Speter putc ('\n', asm_out_file); 310218334Speter} 310318334Speter 310418334Speter/* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol. */ 310518334Speter 310618334Spetervoid 3107132727Skanoutput_asm_label (rtx x) 310818334Speter{ 310918334Speter char buf[256]; 311018334Speter 311118334Speter if (GET_CODE (x) == LABEL_REF) 311290087Sobrien x = XEXP (x, 0); 311390087Sobrien if (GET_CODE (x) == CODE_LABEL 311490087Sobrien || (GET_CODE (x) == NOTE 311590087Sobrien && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL)) 311618334Speter ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); 311718334Speter else 311896281Sobrien output_operand_lossage ("`%%l' operand isn't a label"); 311918334Speter 312018334Speter assemble_name (asm_out_file, buf); 312118334Speter} 312218334Speter 312318334Speter/* Print operand X using machine-dependent assembler syntax. 312418334Speter The macro PRINT_OPERAND is defined just to control this function. 312518334Speter CODE is a non-digit that preceded the operand-number in the % spec, 312618334Speter such as 'z' if the spec was `%z3'. CODE is 0 if there was no char 312718334Speter between the % and the digits. 312818334Speter When CODE is a non-letter, X is 0. 312918334Speter 313018334Speter The meanings of the letters are machine-dependent and controlled 313118334Speter by PRINT_OPERAND. */ 313218334Speter 313318334Speterstatic void 3134132727Skanoutput_operand (rtx x, int code ATTRIBUTE_UNUSED) 313518334Speter{ 313618334Speter if (x && GET_CODE (x) == SUBREG) 313790087Sobrien x = alter_subreg (&x); 313818334Speter 313918334Speter /* If X is a pseudo-register, abort now rather than writing trash to the 314018334Speter assembler file. */ 314118334Speter 314218334Speter if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER) 314318334Speter abort (); 314418334Speter 314518334Speter PRINT_OPERAND (asm_out_file, x, code); 314618334Speter} 314718334Speter 314818334Speter/* Print a memory reference operand for address X 314918334Speter using machine-dependent assembler syntax. 315018334Speter The macro PRINT_OPERAND_ADDRESS exists just to control this function. */ 315118334Speter 315218334Spetervoid 3153132727Skanoutput_address (rtx x) 315418334Speter{ 315590087Sobrien walk_alter_subreg (&x); 315618334Speter PRINT_OPERAND_ADDRESS (asm_out_file, x); 315718334Speter} 315818334Speter 315918334Speter/* Print an integer constant expression in assembler syntax. 316018334Speter Addition and subtraction are the only arithmetic 316118334Speter that may appear in these expressions. */ 316218334Speter 316318334Spetervoid 3164132727Skanoutput_addr_const (FILE *file, rtx x) 316518334Speter{ 316618334Speter char buf[256]; 316718334Speter 316818334Speter restart: 316918334Speter switch (GET_CODE (x)) 317018334Speter { 317118334Speter case PC: 317290087Sobrien putc ('.', file); 317318334Speter break; 317418334Speter 317518334Speter case SYMBOL_REF: 317690087Sobrien#ifdef ASM_OUTPUT_SYMBOL_REF 317790087Sobrien ASM_OUTPUT_SYMBOL_REF (file, x); 317890087Sobrien#else 317918334Speter assemble_name (file, XSTR (x, 0)); 318090087Sobrien#endif 318118334Speter break; 318218334Speter 318318334Speter case LABEL_REF: 318490087Sobrien x = XEXP (x, 0); 318590087Sobrien /* Fall through. */ 318618334Speter case CODE_LABEL: 318718334Speter ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); 318890087Sobrien#ifdef ASM_OUTPUT_LABEL_REF 318990087Sobrien ASM_OUTPUT_LABEL_REF (file, buf); 319090087Sobrien#else 319118334Speter assemble_name (file, buf); 319290087Sobrien#endif 319318334Speter break; 319418334Speter 319518334Speter case CONST_INT: 319650503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); 319718334Speter break; 319818334Speter 319918334Speter case CONST: 320018334Speter /* This used to output parentheses around the expression, 320118334Speter but that does not work on the 386 (either ATT or BSD assembler). */ 320218334Speter output_addr_const (file, XEXP (x, 0)); 320318334Speter break; 320418334Speter 320518334Speter case CONST_DOUBLE: 320618334Speter if (GET_MODE (x) == VOIDmode) 320718334Speter { 320818334Speter /* We can use %d if the number is one word and positive. */ 320918334Speter if (CONST_DOUBLE_HIGH (x)) 321050503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX, 321118334Speter CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x)); 321290087Sobrien else if (CONST_DOUBLE_LOW (x) < 0) 321350503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x)); 321418334Speter else 321550503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x)); 321618334Speter } 321718334Speter else 321818334Speter /* We can't handle floating point constants; 321918334Speter PRINT_OPERAND must handle them. */ 322018334Speter output_operand_lossage ("floating constant misused"); 322118334Speter break; 322218334Speter 322318334Speter case PLUS: 322418334Speter /* Some assemblers need integer constants to appear last (eg masm). */ 322518334Speter if (GET_CODE (XEXP (x, 0)) == CONST_INT) 322618334Speter { 322718334Speter output_addr_const (file, XEXP (x, 1)); 322818334Speter if (INTVAL (XEXP (x, 0)) >= 0) 322918334Speter fprintf (file, "+"); 323018334Speter output_addr_const (file, XEXP (x, 0)); 323118334Speter } 323218334Speter else 323318334Speter { 323418334Speter output_addr_const (file, XEXP (x, 0)); 323590087Sobrien if (GET_CODE (XEXP (x, 1)) != CONST_INT 323690087Sobrien || INTVAL (XEXP (x, 1)) >= 0) 323718334Speter fprintf (file, "+"); 323818334Speter output_addr_const (file, XEXP (x, 1)); 323918334Speter } 324018334Speter break; 324118334Speter 324218334Speter case MINUS: 324318334Speter /* Avoid outputting things like x-x or x+5-x, 324418334Speter since some assemblers can't handle that. */ 324518334Speter x = simplify_subtraction (x); 324618334Speter if (GET_CODE (x) != MINUS) 324718334Speter goto restart; 324818334Speter 324918334Speter output_addr_const (file, XEXP (x, 0)); 325018334Speter fprintf (file, "-"); 325190087Sobrien if ((GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0) 325290087Sobrien || GET_CODE (XEXP (x, 1)) == PC 325390087Sobrien || GET_CODE (XEXP (x, 1)) == SYMBOL_REF) 325490087Sobrien output_addr_const (file, XEXP (x, 1)); 325590087Sobrien else 325618334Speter { 325790087Sobrien fputs (targetm.asm_out.open_paren, file); 325818334Speter output_addr_const (file, XEXP (x, 1)); 325990087Sobrien fputs (targetm.asm_out.close_paren, file); 326018334Speter } 326118334Speter break; 326218334Speter 326318334Speter case ZERO_EXTEND: 326418334Speter case SIGN_EXTEND: 326596281Sobrien case SUBREG: 326618334Speter output_addr_const (file, XEXP (x, 0)); 326718334Speter break; 326818334Speter 326918334Speter default: 327090087Sobrien#ifdef OUTPUT_ADDR_CONST_EXTRA 327190087Sobrien OUTPUT_ADDR_CONST_EXTRA (file, x, fail); 327290087Sobrien break; 327390087Sobrien 327490087Sobrien fail: 327590087Sobrien#endif 327618334Speter output_operand_lossage ("invalid expression as operand"); 327718334Speter } 327818334Speter} 327918334Speter 328018334Speter/* A poor man's fprintf, with the added features of %I, %R, %L, and %U. 328118334Speter %R prints the value of REGISTER_PREFIX. 328218334Speter %L prints the value of LOCAL_LABEL_PREFIX. 328318334Speter %U prints the value of USER_LABEL_PREFIX. 328418334Speter %I prints the value of IMMEDIATE_PREFIX. 328518334Speter %O runs ASM_OUTPUT_OPCODE to transform what follows in the string. 3286132727Skan Also supported are %d, %i, %u, %x, %X, %o, %c, %s and %%. 328718334Speter 328818334Speter We handle alternate assembler dialects here, just like output_asm_insn. */ 328918334Speter 329018334Spetervoid 3291132727Skanasm_fprintf (FILE *file, const char *p, ...) 329218334Speter{ 329318334Speter char buf[10]; 329418334Speter char *q, c; 3295132727Skan va_list argptr; 329618334Speter 3297132727Skan va_start (argptr, p); 329818334Speter 329918334Speter buf[0] = '%'; 330018334Speter 330150503Sobrien while ((c = *p++)) 330218334Speter switch (c) 330318334Speter { 330418334Speter#ifdef ASSEMBLER_DIALECT 330518334Speter case '{': 330650503Sobrien { 330750503Sobrien int i; 330818334Speter 330950503Sobrien /* If we want the first dialect, do nothing. Otherwise, skip 331050503Sobrien DIALECT_NUMBER of strings ending with '|'. */ 331150503Sobrien for (i = 0; i < dialect_number; i++) 331250503Sobrien { 331350503Sobrien while (*p && *p++ != '|') 331450503Sobrien ; 331550503Sobrien 331650503Sobrien if (*p == '|') 331750503Sobrien p++; 331890087Sobrien } 331950503Sobrien } 332018334Speter break; 332118334Speter 332218334Speter case '|': 332318334Speter /* Skip to close brace. */ 332418334Speter while (*p && *p++ != '}') 332518334Speter ; 332618334Speter break; 332718334Speter 332818334Speter case '}': 332918334Speter break; 333018334Speter#endif 333118334Speter 333218334Speter case '%': 333318334Speter c = *p++; 333418334Speter q = &buf[1]; 3335132727Skan while (strchr ("-+ #0", c)) 3336132727Skan { 3337132727Skan *q++ = c; 3338132727Skan c = *p++; 3339132727Skan } 334090087Sobrien while (ISDIGIT (c) || c == '.') 334118334Speter { 334218334Speter *q++ = c; 334318334Speter c = *p++; 334418334Speter } 334518334Speter switch (c) 334618334Speter { 334718334Speter case '%': 3348132727Skan putc ('%', file); 334918334Speter break; 335018334Speter 335118334Speter case 'd': case 'i': case 'u': 3352132727Skan case 'x': case 'X': case 'o': 3353132727Skan case 'c': 335418334Speter *q++ = c; 335518334Speter *q = 0; 335618334Speter fprintf (file, buf, va_arg (argptr, int)); 335718334Speter break; 335818334Speter 335918334Speter case 'w': 3360132727Skan /* This is a prefix to the 'd', 'i', 'u', 'x', 'X', and 3361132727Skan 'o' cases, but we do not check for those cases. It 3362132727Skan means that the value is a HOST_WIDE_INT, which may be 3363132727Skan either `long' or `long long'. */ 3364132727Skan memcpy (q, HOST_WIDE_INT_PRINT, strlen (HOST_WIDE_INT_PRINT)); 3365132727Skan q += strlen (HOST_WIDE_INT_PRINT); 336618334Speter *q++ = *p++; 336718334Speter *q = 0; 336818334Speter fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT)); 336918334Speter break; 337018334Speter 337118334Speter case 'l': 337218334Speter *q++ = c; 3373132727Skan#ifdef HAVE_LONG_LONG 3374132727Skan if (*p == 'l') 3375132727Skan { 3376132727Skan *q++ = *p++; 3377132727Skan *q++ = *p++; 3378132727Skan *q = 0; 3379132727Skan fprintf (file, buf, va_arg (argptr, long long)); 3380132727Skan } 3381132727Skan else 3382132727Skan#endif 3383132727Skan { 3384132727Skan *q++ = *p++; 3385132727Skan *q = 0; 3386132727Skan fprintf (file, buf, va_arg (argptr, long)); 3387132727Skan } 338818334Speter 338918334Speter break; 339018334Speter 339118334Speter case 's': 339218334Speter *q++ = c; 339318334Speter *q = 0; 339418334Speter fprintf (file, buf, va_arg (argptr, char *)); 339518334Speter break; 339618334Speter 339718334Speter case 'O': 339818334Speter#ifdef ASM_OUTPUT_OPCODE 339918334Speter ASM_OUTPUT_OPCODE (asm_out_file, p); 340018334Speter#endif 340118334Speter break; 340218334Speter 340318334Speter case 'R': 340418334Speter#ifdef REGISTER_PREFIX 340518334Speter fprintf (file, "%s", REGISTER_PREFIX); 340618334Speter#endif 340718334Speter break; 340818334Speter 340918334Speter case 'I': 341018334Speter#ifdef IMMEDIATE_PREFIX 341118334Speter fprintf (file, "%s", IMMEDIATE_PREFIX); 341218334Speter#endif 341318334Speter break; 341418334Speter 341518334Speter case 'L': 341618334Speter#ifdef LOCAL_LABEL_PREFIX 341718334Speter fprintf (file, "%s", LOCAL_LABEL_PREFIX); 341818334Speter#endif 341918334Speter break; 342018334Speter 342118334Speter case 'U': 342252515Sobrien fputs (user_label_prefix, file); 342318334Speter break; 342418334Speter 342590087Sobrien#ifdef ASM_FPRINTF_EXTENSIONS 3426132727Skan /* Uppercase letters are reserved for general use by asm_fprintf 342790087Sobrien and so are not available to target specific code. In order to 342890087Sobrien prevent the ASM_FPRINTF_EXTENSIONS macro from using them then, 342990087Sobrien they are defined here. As they get turned into real extensions 343090087Sobrien to asm_fprintf they should be removed from this list. */ 343190087Sobrien case 'A': case 'B': case 'C': case 'D': case 'E': 343290087Sobrien case 'F': case 'G': case 'H': case 'J': case 'K': 343390087Sobrien case 'M': case 'N': case 'P': case 'Q': case 'S': 343490087Sobrien case 'T': case 'V': case 'W': case 'Y': case 'Z': 343590087Sobrien break; 343690087Sobrien 343790087Sobrien ASM_FPRINTF_EXTENSIONS (file, argptr, p) 343890087Sobrien#endif 343918334Speter default: 344018334Speter abort (); 344118334Speter } 344218334Speter break; 344318334Speter 344418334Speter default: 3445132727Skan putc (c, file); 344618334Speter } 3447132727Skan va_end (argptr); 344818334Speter} 344918334Speter 345018334Speter/* Split up a CONST_DOUBLE or integer constant rtx 345118334Speter into two rtx's for single words, 345218334Speter storing in *FIRST the word that comes first in memory in the target 345318334Speter and in *SECOND the other. */ 345418334Speter 345518334Spetervoid 3456132727Skansplit_double (rtx value, rtx *first, rtx *second) 345718334Speter{ 345818334Speter if (GET_CODE (value) == CONST_INT) 345918334Speter { 346018334Speter if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD)) 346118334Speter { 346218334Speter /* In this case the CONST_INT holds both target words. 346350503Sobrien Extract the bits from it into two word-sized pieces. 346450503Sobrien Sign extend each half to HOST_WIDE_INT. */ 346590087Sobrien unsigned HOST_WIDE_INT low, high; 346690087Sobrien unsigned HOST_WIDE_INT mask, sign_bit, sign_extend; 346718334Speter 346890087Sobrien /* Set sign_bit to the most significant bit of a word. */ 346990087Sobrien sign_bit = 1; 347090087Sobrien sign_bit <<= BITS_PER_WORD - 1; 347190087Sobrien 347290087Sobrien /* Set mask so that all bits of the word are set. We could 347390087Sobrien have used 1 << BITS_PER_WORD instead of basing the 347490087Sobrien calculation on sign_bit. However, on machines where 347590087Sobrien HOST_BITS_PER_WIDE_INT == BITS_PER_WORD, it could cause a 347690087Sobrien compiler warning, even though the code would never be 347790087Sobrien executed. */ 347890087Sobrien mask = sign_bit << 1; 347990087Sobrien mask--; 348090087Sobrien 348190087Sobrien /* Set sign_extend as any remaining bits. */ 348290087Sobrien sign_extend = ~mask; 348390087Sobrien 348490087Sobrien /* Pick the lower word and sign-extend it. */ 348590087Sobrien low = INTVAL (value); 348690087Sobrien low &= mask; 348790087Sobrien if (low & sign_bit) 348890087Sobrien low |= sign_extend; 348990087Sobrien 349090087Sobrien /* Pick the higher word, shifted to the least significant 349190087Sobrien bits, and sign-extend it. */ 349290087Sobrien high = INTVAL (value); 349390087Sobrien high >>= BITS_PER_WORD - 1; 349490087Sobrien high >>= 1; 349590087Sobrien high &= mask; 349690087Sobrien if (high & sign_bit) 349790087Sobrien high |= sign_extend; 349890087Sobrien 349990087Sobrien /* Store the words in the target machine order. */ 350018334Speter if (WORDS_BIG_ENDIAN) 350118334Speter { 350290087Sobrien *first = GEN_INT (high); 350390087Sobrien *second = GEN_INT (low); 350418334Speter } 350518334Speter else 350618334Speter { 350790087Sobrien *first = GEN_INT (low); 350890087Sobrien *second = GEN_INT (high); 350918334Speter } 351018334Speter } 351118334Speter else 351218334Speter { 351318334Speter /* The rule for using CONST_INT for a wider mode 351418334Speter is that we regard the value as signed. 351518334Speter So sign-extend it. */ 351618334Speter rtx high = (INTVAL (value) < 0 ? constm1_rtx : const0_rtx); 351718334Speter if (WORDS_BIG_ENDIAN) 351818334Speter { 351918334Speter *first = high; 352018334Speter *second = value; 352118334Speter } 352218334Speter else 352318334Speter { 352418334Speter *first = value; 352518334Speter *second = high; 352618334Speter } 352718334Speter } 352818334Speter } 352918334Speter else if (GET_CODE (value) != CONST_DOUBLE) 353018334Speter { 353118334Speter if (WORDS_BIG_ENDIAN) 353218334Speter { 353318334Speter *first = const0_rtx; 353418334Speter *second = value; 353518334Speter } 353618334Speter else 353718334Speter { 353818334Speter *first = value; 353918334Speter *second = const0_rtx; 354018334Speter } 354118334Speter } 354218334Speter else if (GET_MODE (value) == VOIDmode 354318334Speter /* This is the old way we did CONST_DOUBLE integers. */ 354418334Speter || GET_MODE_CLASS (GET_MODE (value)) == MODE_INT) 354518334Speter { 354618334Speter /* In an integer, the words are defined as most and least significant. 354718334Speter So order them by the target's convention. */ 354818334Speter if (WORDS_BIG_ENDIAN) 354918334Speter { 355018334Speter *first = GEN_INT (CONST_DOUBLE_HIGH (value)); 355118334Speter *second = GEN_INT (CONST_DOUBLE_LOW (value)); 355218334Speter } 355318334Speter else 355418334Speter { 355518334Speter *first = GEN_INT (CONST_DOUBLE_LOW (value)); 355618334Speter *second = GEN_INT (CONST_DOUBLE_HIGH (value)); 355718334Speter } 355818334Speter } 355918334Speter else 356018334Speter { 356190087Sobrien REAL_VALUE_TYPE r; 356290087Sobrien long l[2]; 356318334Speter REAL_VALUE_FROM_CONST_DOUBLE (r, value); 356418334Speter 356518334Speter /* Note, this converts the REAL_VALUE_TYPE to the target's 356618334Speter format, splits up the floating point double and outputs 356718334Speter exactly 32 bits of it into each of l[0] and l[1] -- 356850503Sobrien not necessarily BITS_PER_WORD bits. */ 356918334Speter REAL_VALUE_TO_TARGET_DOUBLE (r, l); 357018334Speter 357152515Sobrien /* If 32 bits is an entire word for the target, but not for the host, 357252515Sobrien then sign-extend on the host so that the number will look the same 357352515Sobrien way on the host that it would on the target. See for instance 357452515Sobrien simplify_unary_operation. The #if is needed to avoid compiler 357552515Sobrien warnings. */ 357652515Sobrien 357752515Sobrien#if HOST_BITS_PER_LONG > 32 357852515Sobrien if (BITS_PER_WORD < HOST_BITS_PER_LONG && BITS_PER_WORD == 32) 357952515Sobrien { 358052515Sobrien if (l[0] & ((long) 1 << 31)) 358152515Sobrien l[0] |= ((long) (-1) << 32); 358252515Sobrien if (l[1] & ((long) 1 << 31)) 358352515Sobrien l[1] |= ((long) (-1) << 32); 358452515Sobrien } 358552515Sobrien#endif 358652515Sobrien 358718334Speter *first = GEN_INT ((HOST_WIDE_INT) l[0]); 358818334Speter *second = GEN_INT ((HOST_WIDE_INT) l[1]); 358918334Speter } 359018334Speter} 359118334Speter 359218334Speter/* Return nonzero if this function has no function calls. */ 359318334Speter 359418334Speterint 3595132727Skanleaf_function_p (void) 359618334Speter{ 359718334Speter rtx insn; 359890087Sobrien rtx link; 359918334Speter 360090087Sobrien if (current_function_profile || profile_arc_flag) 360118334Speter return 0; 360218334Speter 360318334Speter for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 360418334Speter { 360590087Sobrien if (GET_CODE (insn) == CALL_INSN 360690087Sobrien && ! SIBLING_CALL_P (insn)) 360718334Speter return 0; 360818334Speter if (GET_CODE (insn) == INSN 360918334Speter && GET_CODE (PATTERN (insn)) == SEQUENCE 361090087Sobrien && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN 361190087Sobrien && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0))) 361218334Speter return 0; 361318334Speter } 361490087Sobrien for (link = current_function_epilogue_delay_list; 361590087Sobrien link; 361690087Sobrien link = XEXP (link, 1)) 361718334Speter { 361890087Sobrien insn = XEXP (link, 0); 361990087Sobrien 362090087Sobrien if (GET_CODE (insn) == CALL_INSN 362190087Sobrien && ! SIBLING_CALL_P (insn)) 362218334Speter return 0; 362390087Sobrien if (GET_CODE (insn) == INSN 362490087Sobrien && GET_CODE (PATTERN (insn)) == SEQUENCE 362590087Sobrien && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN 362690087Sobrien && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0))) 362718334Speter return 0; 362818334Speter } 362918334Speter 363018334Speter return 1; 363118334Speter} 363218334Speter 3633117404Skan/* Return 1 if branch is a forward branch. 363490087Sobrien Uses insn_shuid array, so it works only in the final pass. May be used by 363590087Sobrien output templates to customary add branch prediction hints. 363690087Sobrien */ 363790087Sobrienint 3638132727Skanfinal_forward_branch_p (rtx insn) 363990087Sobrien{ 364090087Sobrien int insn_id, label_id; 364190087Sobrien if (!uid_shuid) 364290087Sobrien abort (); 364390087Sobrien insn_id = INSN_SHUID (insn); 364490087Sobrien label_id = INSN_SHUID (JUMP_LABEL (insn)); 364590087Sobrien /* We've hit some insns that does not have id information available. */ 364690087Sobrien if (!insn_id || !label_id) 364790087Sobrien abort (); 364890087Sobrien return insn_id < label_id; 364990087Sobrien} 365090087Sobrien 365118334Speter/* On some machines, a function with no call insns 365218334Speter can run faster if it doesn't create its own register window. 365318334Speter When output, the leaf function should use only the "output" 365418334Speter registers. Ordinarily, the function would be compiled to use 365518334Speter the "input" registers to find its arguments; it is a candidate 365618334Speter for leaf treatment if it uses only the "input" registers. 365718334Speter Leaf function treatment means renumbering so the function 365818334Speter uses the "output" registers instead. */ 365918334Speter 366018334Speter#ifdef LEAF_REGISTERS 366118334Speter 366218334Speter/* Return 1 if this function uses only the registers that can be 366318334Speter safely renumbered. */ 366418334Speter 366518334Speterint 3666132727Skanonly_leaf_regs_used (void) 366718334Speter{ 366818334Speter int i; 3669132727Skan const char *const permitted_reg_in_leaf_functions = LEAF_REGISTERS; 367018334Speter 367118334Speter for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 367250503Sobrien if ((regs_ever_live[i] || global_regs[i]) 367350503Sobrien && ! permitted_reg_in_leaf_functions[i]) 367450503Sobrien return 0; 367550503Sobrien 367650503Sobrien if (current_function_uses_pic_offset_table 367750503Sobrien && pic_offset_table_rtx != 0 367850503Sobrien && GET_CODE (pic_offset_table_rtx) == REG 367950503Sobrien && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)]) 368050503Sobrien return 0; 368150503Sobrien 368218334Speter return 1; 368318334Speter} 368418334Speter 368518334Speter/* Scan all instructions and renumber all registers into those 368618334Speter available in leaf functions. */ 368718334Speter 368818334Speterstatic void 3689132727Skanleaf_renumber_regs (rtx first) 369018334Speter{ 369118334Speter rtx insn; 369218334Speter 369318334Speter /* Renumber only the actual patterns. 369418334Speter The reg-notes can contain frame pointer refs, 369518334Speter and renumbering them could crash, and should not be needed. */ 369618334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 369790087Sobrien if (INSN_P (insn)) 369818334Speter leaf_renumber_regs_insn (PATTERN (insn)); 369990087Sobrien for (insn = current_function_epilogue_delay_list; 370090087Sobrien insn; 370190087Sobrien insn = XEXP (insn, 1)) 370290087Sobrien if (INSN_P (XEXP (insn, 0))) 370318334Speter leaf_renumber_regs_insn (PATTERN (XEXP (insn, 0))); 370418334Speter} 370518334Speter 370618334Speter/* Scan IN_RTX and its subexpressions, and renumber all regs into those 370718334Speter available in leaf functions. */ 370818334Speter 370918334Spetervoid 3710132727Skanleaf_renumber_regs_insn (rtx in_rtx) 371118334Speter{ 371290087Sobrien int i, j; 371390087Sobrien const char *format_ptr; 371418334Speter 371518334Speter if (in_rtx == 0) 371618334Speter return; 371718334Speter 371818334Speter /* Renumber all input-registers into output-registers. 371918334Speter renumbered_regs would be 1 for an output-register; 372018334Speter they */ 372118334Speter 372218334Speter if (GET_CODE (in_rtx) == REG) 372318334Speter { 372418334Speter int newreg; 372518334Speter 372618334Speter /* Don't renumber the same reg twice. */ 372718334Speter if (in_rtx->used) 372818334Speter return; 372918334Speter 373018334Speter newreg = REGNO (in_rtx); 373118334Speter /* Don't try to renumber pseudo regs. It is possible for a pseudo reg 373218334Speter to reach here as part of a REG_NOTE. */ 373318334Speter if (newreg >= FIRST_PSEUDO_REGISTER) 373418334Speter { 373518334Speter in_rtx->used = 1; 373618334Speter return; 373718334Speter } 373818334Speter newreg = LEAF_REG_REMAP (newreg); 373918334Speter if (newreg < 0) 374018334Speter abort (); 374118334Speter regs_ever_live[REGNO (in_rtx)] = 0; 374218334Speter regs_ever_live[newreg] = 1; 374318334Speter REGNO (in_rtx) = newreg; 374418334Speter in_rtx->used = 1; 374518334Speter } 374618334Speter 374790087Sobrien if (INSN_P (in_rtx)) 374818334Speter { 374918334Speter /* Inside a SEQUENCE, we find insns. 375018334Speter Renumber just the patterns of these insns, 375118334Speter just as we do for the top-level insns. */ 375218334Speter leaf_renumber_regs_insn (PATTERN (in_rtx)); 375318334Speter return; 375418334Speter } 375518334Speter 375618334Speter format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx)); 375718334Speter 375818334Speter for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++) 375918334Speter switch (*format_ptr++) 376018334Speter { 376118334Speter case 'e': 376218334Speter leaf_renumber_regs_insn (XEXP (in_rtx, i)); 376318334Speter break; 376418334Speter 376518334Speter case 'E': 376618334Speter if (NULL != XVEC (in_rtx, i)) 376718334Speter { 376818334Speter for (j = 0; j < XVECLEN (in_rtx, i); j++) 376918334Speter leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j)); 377018334Speter } 377118334Speter break; 377218334Speter 377318334Speter case 'S': 377418334Speter case 's': 377518334Speter case '0': 377618334Speter case 'i': 377718334Speter case 'w': 377818334Speter case 'n': 377918334Speter case 'u': 378018334Speter break; 378118334Speter 378218334Speter default: 378318334Speter abort (); 378418334Speter } 378518334Speter} 378618334Speter#endif 3787132727Skan 3788132727Skan 3789132727Skan/* When -gused is used, emit debug info for only used symbols. But in 3790132727Skan addition to the standard intercepted debug_hooks there are some direct 3791132727Skan calls into this file, i.e., dbxout_symbol, dbxout_parms, and dbxout_reg_params. 3792132727Skan Those routines may also be called from a higher level intercepted routine. So 3793132727Skan to prevent recording data for an inner call to one of these for an intercept, 3794132727Skan we maintain an intercept nesting counter (debug_nesting). We only save the 3795132727Skan intercepted arguments if the nesting is 1. */ 3796132727Skanint debug_nesting = 0; 3797132727Skan 3798132727Skanstatic tree *symbol_queue; 3799132727Skanint symbol_queue_index = 0; 3800132727Skanstatic int symbol_queue_size = 0; 3801132727Skan 3802132727Skan/* Generate the symbols for any queued up type symbols we encountered 3803132727Skan while generating the type info for some originally used symbol. 3804132727Skan This might generate additional entries in the queue. Only when 3805132727Skan the nesting depth goes to 0 is this routine called. */ 3806132727Skan 3807132727Skanvoid 3808132727Skandebug_flush_symbol_queue (void) 3809132727Skan{ 3810132727Skan int i; 3811132727Skan 3812132727Skan /* Make sure that additionally queued items are not flushed 3813132727Skan prematurely. */ 3814132727Skan 3815132727Skan ++debug_nesting; 3816132727Skan 3817132727Skan for (i = 0; i < symbol_queue_index; ++i) 3818132727Skan { 3819132727Skan /* If we pushed queued symbols then such symbols are must be 3820132727Skan output no matter what anyone else says. Specifically, 3821132727Skan we need to make sure dbxout_symbol() thinks the symbol was 3822132727Skan used and also we need to override TYPE_DECL_SUPPRESS_DEBUG 3823132727Skan which may be set for outside reasons. */ 3824132727Skan int saved_tree_used = TREE_USED (symbol_queue[i]); 3825132727Skan int saved_suppress_debug = TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]); 3826132727Skan TREE_USED (symbol_queue[i]) = 1; 3827132727Skan TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = 0; 3828132727Skan 3829132727Skan#ifdef DBX_DEBUGGING_INFO 3830132727Skan dbxout_symbol (symbol_queue[i], 0); 3831132727Skan#endif 3832132727Skan 3833132727Skan TREE_USED (symbol_queue[i]) = saved_tree_used; 3834132727Skan TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = saved_suppress_debug; 3835132727Skan } 3836132727Skan 3837132727Skan symbol_queue_index = 0; 3838132727Skan --debug_nesting; 3839132727Skan} 3840132727Skan 3841132727Skan/* Queue a type symbol needed as part of the definition of a decl 3842132727Skan symbol. These symbols are generated when debug_flush_symbol_queue() 3843132727Skan is called. */ 3844132727Skan 3845132727Skanvoid 3846132727Skandebug_queue_symbol (tree decl) 3847132727Skan{ 3848132727Skan if (symbol_queue_index >= symbol_queue_size) 3849132727Skan { 3850132727Skan symbol_queue_size += 10; 3851132727Skan symbol_queue = xrealloc (symbol_queue, 3852132727Skan symbol_queue_size * sizeof (tree)); 3853132727Skan } 3854132727Skan 3855132727Skan symbol_queue[symbol_queue_index++] = decl; 3856132727Skan} 3857132727Skan 3858132727Skan/* Free symbol queue. */ 3859132727Skanvoid 3860132727Skandebug_free_queue (void) 3861132727Skan{ 3862132727Skan if (symbol_queue) 3863132727Skan { 3864132727Skan free (symbol_queue); 3865132727Skan symbol_queue = NULL; 3866132727Skan symbol_queue_size = 0; 3867132727Skan } 3868132727Skan} 3869