final.c revision 96281
118334Speter/* Convert RTL to assembler code and output it, for GNU compiler. 290087Sobrien Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 390087Sobrien 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. 418334Speter 590087SobrienThis file is part of GCC. 618334Speter 790087SobrienGCC is free software; you can redistribute it and/or modify it under 890087Sobrienthe terms of the GNU General Public License as published by the Free 990087SobrienSoftware Foundation; either version 2, or (at your option) any later 1090087Sobrienversion. 1118334Speter 1290087SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1390087SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1490087SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1590087Sobrienfor more details. 1618334Speter 1718334SpeterYou should have received a copy of the GNU General Public License 1890087Sobrienalong with GCC; see the file COPYING. If not, write to the Free 1990087SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 2090087Sobrien02111-1307, USA. */ 2118334Speter 2252515Sobrien/* $FreeBSD: head/contrib/gcc/final.c 96281 2002-05-09 21:41:12Z obrien $ */ 2318334Speter 2418334Speter/* This is the final pass of the compiler. 2518334Speter It looks at the rtl code for a function and outputs assembler code. 2618334Speter 2718334Speter Call `final_start_function' to output the assembler code for function entry, 2818334Speter `final' to output assembler code for some RTL code, 2918334Speter `final_end_function' to output assembler code for function exit. 3018334Speter If a function is compiled in several pieces, each piece is 3118334Speter output separately with `final'. 3218334Speter 3318334Speter Some optimizations are also done at this level. 3418334Speter Move instructions that were made unnecessary by good register allocation 3518334Speter are detected and omitted from the output. (Though most of these 3618334Speter are removed by the last jump pass.) 3718334Speter 3818334Speter Instructions to set the condition codes are omitted when it can be 3918334Speter seen that the condition codes already had the desired values. 4018334Speter 4118334Speter In some cases it is sufficient if the inherited condition codes 4218334Speter have related values, but this may require the following insn 4318334Speter (the one that tests the condition codes) to be modified. 4418334Speter 4518334Speter The code for the function prologue and epilogue are generated 4690087Sobrien directly in assembler by the target functions function_prologue and 4790087Sobrien function_epilogue. Those instructions never exist as rtl. */ 4818334Speter 4918334Speter#include "config.h" 5050503Sobrien#include "system.h" 5118334Speter 5218334Speter#include "tree.h" 5318334Speter#include "rtl.h" 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" 7318334Speter 7418334Speter#ifdef XCOFF_DEBUGGING_INFO 7590087Sobrien#include "xcoffout.h" /* Needed for external data 7690087Sobrien declarations for e.g. AIX 4.x. */ 7718334Speter#endif 7818334Speter 7950503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO) 8050503Sobrien#include "dwarf2out.h" 8150503Sobrien#endif 8250503Sobrien 8318334Speter/* If we aren't using cc0, CC_STATUS_INIT shouldn't exist. So define a 8418334Speter null default for it to save conditionalization later. */ 8518334Speter#ifndef CC_STATUS_INIT 8618334Speter#define CC_STATUS_INIT 8718334Speter#endif 8818334Speter 8918334Speter/* How to start an assembler comment. */ 9018334Speter#ifndef ASM_COMMENT_START 9118334Speter#define ASM_COMMENT_START ";#" 9218334Speter#endif 9318334Speter 9418334Speter/* Is the given character a logical line separator for the assembler? */ 9518334Speter#ifndef IS_ASM_LOGICAL_LINE_SEPARATOR 9618334Speter#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';') 9718334Speter#endif 9818334Speter 9950503Sobrien#ifndef JUMP_TABLES_IN_TEXT_SECTION 10050503Sobrien#define JUMP_TABLES_IN_TEXT_SECTION 0 10150503Sobrien#endif 10250503Sobrien 10318334Speter/* Last insn processed by final_scan_insn. */ 10490087Sobrienstatic rtx debug_insn; 10590087Sobrienrtx current_output_insn; 10618334Speter 10718334Speter/* Line number of last NOTE. */ 10818334Speterstatic int last_linenum; 10918334Speter 11018334Speter/* Highest line number in current block. */ 11118334Speterstatic int high_block_linenum; 11218334Speter 11318334Speter/* Likewise for function. */ 11418334Speterstatic int high_function_linenum; 11518334Speter 11618334Speter/* Filename of last NOTE. */ 11790087Sobrienstatic const char *last_filename; 11818334Speter 11950503Sobrien/* Number of instrumented arcs when profile_arc_flag is set. */ 12090087Sobrienextern int count_instrumented_edges; 12150503Sobrien 12250503Sobrienextern int length_unit_log; /* This is defined in insn-attrtab.c. */ 12350503Sobrien 12418334Speter/* Nonzero while outputting an `asm' with operands. 12518334Speter This means that inconsistencies are the user's fault, so don't abort. 12618334Speter The precise value is the insn being output, to pass to error_for_asm. */ 12718334Speterstatic rtx this_is_asm_operands; 12818334Speter 12918334Speter/* Number of operands of this insn, for an `asm' with operands. */ 13050503Sobrienstatic unsigned int insn_noperands; 13118334Speter 13218334Speter/* Compare optimization flag. */ 13318334Speter 13418334Speterstatic rtx last_ignored_compare = 0; 13518334Speter 13618334Speter/* Flag indicating this insn is the start of a new basic block. */ 13718334Speter 13818334Speterstatic int new_block = 1; 13918334Speter 14018334Speter/* Assign a unique number to each insn that is output. 14118334Speter This can be used to generate unique local labels. */ 14218334Speter 14318334Speterstatic int insn_counter = 0; 14418334Speter 14518334Speter#ifdef HAVE_cc0 14618334Speter/* This variable contains machine-dependent flags (defined in tm.h) 14718334Speter set and examined by output routines 14818334Speter that describe how to interpret the condition codes properly. */ 14918334Speter 15018334SpeterCC_STATUS cc_status; 15118334Speter 15218334Speter/* During output of an insn, this contains a copy of cc_status 15318334Speter from before the insn. */ 15418334Speter 15518334SpeterCC_STATUS cc_prev_status; 15618334Speter#endif 15718334Speter 15818334Speter/* Indexed by hardware reg number, is 1 if that register is ever 15918334Speter used in the current function. 16018334Speter 16118334Speter In life_analysis, or in stupid_life_analysis, this is set 16218334Speter up to record the hard regs used explicitly. Reload adds 16318334Speter in the hard regs used for holding pseudo regs. Final uses 16418334Speter it to generate the code in the function prologue and epilogue 16518334Speter to save and restore registers as needed. */ 16618334Speter 16718334Speterchar regs_ever_live[FIRST_PSEUDO_REGISTER]; 16818334Speter 16918334Speter/* Nonzero means current function must be given a frame pointer. 17018334Speter Set in stmt.c if anything is allocated on the stack there. 17118334Speter Set in reload1.c if anything is allocated on the stack there. */ 17218334Speter 17318334Speterint frame_pointer_needed; 17418334Speter 17590087Sobrien/* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen. */ 17618334Speter 17718334Speterstatic int block_depth; 17818334Speter 17918334Speter/* Nonzero if have enabled APP processing of our assembler output. */ 18018334Speter 18118334Speterstatic int app_on; 18218334Speter 18318334Speter/* If we are outputting an insn sequence, this contains the sequence rtx. 18418334Speter Zero otherwise. */ 18518334Speter 18618334Speterrtx final_sequence; 18718334Speter 18818334Speter#ifdef ASSEMBLER_DIALECT 18918334Speter 19018334Speter/* Number of the assembler dialect to use, starting at 0. */ 19118334Speterstatic int dialect_number; 19218334Speter#endif 19318334Speter 19418334Speter/* Indexed by line number, nonzero if there is a note for that line. */ 19518334Speter 19618334Speterstatic char *line_note_exists; 19718334Speter 19890087Sobrien#ifdef HAVE_conditional_execution 19990087Sobrien/* Nonnull if the insn currently being emitted was a COND_EXEC pattern. */ 20090087Sobrienrtx current_insn_predicate; 20190087Sobrien#endif 20218334Speter 20350503Sobrien#ifdef HAVE_ATTR_length 20490087Sobrienstatic int asm_insn_count PARAMS ((rtx)); 20550503Sobrien#endif 20690087Sobrienstatic void profile_function PARAMS ((FILE *)); 20790087Sobrienstatic void profile_after_prologue PARAMS ((FILE *)); 20890087Sobrienstatic void notice_source_line PARAMS ((rtx)); 20990087Sobrienstatic rtx walk_alter_subreg PARAMS ((rtx *)); 21090087Sobrienstatic void output_asm_name PARAMS ((void)); 21190087Sobrienstatic tree get_mem_expr_from_op PARAMS ((rtx, int *)); 21290087Sobrienstatic void output_asm_operand_names PARAMS ((rtx *, int *, int)); 21390087Sobrienstatic void output_operand PARAMS ((rtx, int)); 21450503Sobrien#ifdef LEAF_REGISTERS 21590087Sobrienstatic void leaf_renumber_regs PARAMS ((rtx)); 21650503Sobrien#endif 21750503Sobrien#ifdef HAVE_cc0 21890087Sobrienstatic int alter_cond PARAMS ((rtx)); 21950503Sobrien#endif 22090087Sobrien#ifndef ADDR_VEC_ALIGN 22190087Sobrienstatic int final_addr_vec_align PARAMS ((rtx)); 22290087Sobrien#endif 22390087Sobrien#ifdef HAVE_ATTR_length 22490087Sobrienstatic int align_fuzz PARAMS ((rtx, rtx, int, unsigned)); 22590087Sobrien#endif 22618334Speter 22718334Speter/* Initialize data in final at the beginning of a compilation. */ 22818334Speter 22918334Spetervoid 23018334Speterinit_final (filename) 23190087Sobrien const char *filename ATTRIBUTE_UNUSED; 23218334Speter{ 23318334Speter app_on = 0; 23418334Speter final_sequence = 0; 23518334Speter 23618334Speter#ifdef ASSEMBLER_DIALECT 23718334Speter dialect_number = ASSEMBLER_DIALECT; 23818334Speter#endif 23918334Speter} 24018334Speter 24118334Speter/* Called at end of source file, 24218334Speter to output the block-profiling table for this entire compilation. */ 24318334Speter 24418334Spetervoid 24518334Speterend_final (filename) 24690087Sobrien const char *filename; 24718334Speter{ 24890087Sobrien if (profile_arc_flag) 24918334Speter { 25018334Speter char name[20]; 25118334Speter int align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT); 25250503Sobrien int size, rounded; 25350503Sobrien int long_bytes = LONG_TYPE_SIZE / BITS_PER_UNIT; 25490087Sobrien int gcov_type_bytes = GCOV_TYPE_SIZE / BITS_PER_UNIT; 25550503Sobrien int pointer_bytes = POINTER_SIZE / BITS_PER_UNIT; 25690087Sobrien unsigned int align2 = LONG_TYPE_SIZE; 25718334Speter 25890087Sobrien size = gcov_type_bytes * count_instrumented_edges; 25950503Sobrien rounded = size; 26050503Sobrien 26118334Speter rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1; 26218334Speter rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT) 26318334Speter * (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); 26418334Speter 26590087Sobrien /* ??? This _really_ ought to be done with a structure layout 26690087Sobrien and with assemble_constructor. If long_bytes != pointer_bytes 26790087Sobrien we'll be emitting unaligned data at some point. */ 26890087Sobrien if (long_bytes != pointer_bytes) 26990087Sobrien abort (); 27090087Sobrien 27118334Speter data_section (); 27218334Speter 27350503Sobrien /* Output the main header, of 11 words: 27450503Sobrien 0: 1 if this file is initialized, else 0. 27518334Speter 1: address of file name (LPBX1). 27618334Speter 2: address of table of counts (LPBX2). 27718334Speter 3: number of counts in the table. 27818334Speter 4: always 0, for compatibility with Sun. 27918334Speter 28018334Speter The following are GNU extensions: 28118334Speter 28218334Speter 5: address of table of start addrs of basic blocks (LPBX3). 28318334Speter 6: Number of bytes in this header. 28418334Speter 7: address of table of function names (LPBX4). 28518334Speter 8: address of table of line numbers (LPBX5) or 0. 28650503Sobrien 9: address of table of file names (LPBX6) or 0. 28750503Sobrien 10: space reserved for basic block profiling. */ 28818334Speter 28918334Speter ASM_OUTPUT_ALIGN (asm_out_file, align); 29018334Speter 29118334Speter ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0); 29218334Speter 29390087Sobrien /* Zero word. */ 29490087Sobrien assemble_integer (const0_rtx, long_bytes, align2, 1); 29590087Sobrien 29690087Sobrien /* Address of filename. */ 29718334Speter ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 1); 29890087Sobrien assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 29990087Sobrien align2, 1); 30018334Speter 30190087Sobrien /* Address of count table. */ 30218334Speter ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2); 30390087Sobrien assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 30490087Sobrien align2, 1); 30518334Speter 30690087Sobrien /* Count of the # of instrumented arcs. */ 30790087Sobrien assemble_integer (GEN_INT (count_instrumented_edges), 30890087Sobrien long_bytes, align2, 1); 30918334Speter 31090087Sobrien /* Zero word (link field). */ 31190087Sobrien assemble_integer (const0_rtx, pointer_bytes, align2, 1); 31218334Speter 31390087Sobrien assemble_integer (const0_rtx, pointer_bytes, align2, 1); 31418334Speter 31590087Sobrien /* Byte count for extended structure. */ 31690087Sobrien assemble_integer (GEN_INT (11 * UNITS_PER_WORD), long_bytes, align2, 1); 31718334Speter 31890087Sobrien /* Address of function name table. */ 31990087Sobrien assemble_integer (const0_rtx, pointer_bytes, align2, 1); 32018334Speter 32190087Sobrien /* Address of line number and filename tables if debugging. */ 32290087Sobrien assemble_integer (const0_rtx, pointer_bytes, align2, 1); 32390087Sobrien assemble_integer (const0_rtx, pointer_bytes, align2, 1); 32418334Speter 32590087Sobrien /* Space for extension ptr (link field). */ 32690087Sobrien assemble_integer (const0_rtx, UNITS_PER_WORD, align2, 1); 32750503Sobrien 32890087Sobrien /* Output the file name changing the suffix to .d for 32990087Sobrien Sun tcov compatibility. */ 33018334Speter ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1); 33118334Speter { 33218334Speter char *cwd = getpwd (); 33318334Speter int len = strlen (filename) + strlen (cwd) + 1; 33418334Speter char *data_file = (char *) alloca (len + 4); 33518334Speter 33618334Speter strcpy (data_file, cwd); 33718334Speter strcat (data_file, "/"); 33818334Speter strcat (data_file, filename); 33918334Speter strip_off_ending (data_file, len); 34090087Sobrien strcat (data_file, ".da"); 34118334Speter assemble_string (data_file, strlen (data_file) + 1); 34218334Speter } 34318334Speter 34418334Speter /* Make space for the table of counts. */ 34550503Sobrien if (size == 0) 34618334Speter { 34718334Speter /* Realign data section. */ 34818334Speter ASM_OUTPUT_ALIGN (asm_out_file, align); 34918334Speter ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 2); 35018334Speter if (size != 0) 35118334Speter assemble_zeros (size); 35218334Speter } 35318334Speter else 35418334Speter { 35518334Speter ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2); 35618334Speter#ifdef ASM_OUTPUT_SHARED_LOCAL 35718334Speter if (flag_shared_data) 35818334Speter ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded); 35918334Speter else 36018334Speter#endif 36150503Sobrien#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL 36290087Sobrien ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, 36390087Sobrien size, BIGGEST_ALIGNMENT); 36450503Sobrien#else 36518334Speter#ifdef ASM_OUTPUT_ALIGNED_LOCAL 36618334Speter ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, 36718334Speter BIGGEST_ALIGNMENT); 36818334Speter#else 36918334Speter ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded); 37018334Speter#endif 37150503Sobrien#endif 37218334Speter } 37390087Sobrien } 37490087Sobrien} 37518334Speter 37690087Sobrien/* Default target function prologue and epilogue assembler output. 37718334Speter 37890087Sobrien If not overridden for epilogue code, then the function body itself 37990087Sobrien contains return instructions wherever needed. */ 38090087Sobrienvoid 38190087Sobriendefault_function_pro_epilogue (file, size) 38290087Sobrien FILE *file ATTRIBUTE_UNUSED; 38390087Sobrien HOST_WIDE_INT size ATTRIBUTE_UNUSED; 38490087Sobrien{ 38590087Sobrien} 38618334Speter 38790087Sobrien/* Default target hook that outputs nothing to a stream. */ 38890087Sobrienvoid 38990087Sobrienno_asm_to_stream (file) 39090087Sobrien FILE *file ATTRIBUTE_UNUSED; 39190087Sobrien{ 39218334Speter} 39318334Speter 39418334Speter/* Enable APP processing of subsequent output. 39518334Speter Used before the output from an `asm' statement. */ 39618334Speter 39718334Spetervoid 39818334Speterapp_enable () 39918334Speter{ 40018334Speter if (! app_on) 40118334Speter { 40250503Sobrien fputs (ASM_APP_ON, asm_out_file); 40318334Speter app_on = 1; 40418334Speter } 40518334Speter} 40618334Speter 40718334Speter/* Disable APP processing of subsequent output. 40818334Speter Called from varasm.c before most kinds of output. */ 40918334Speter 41018334Spetervoid 41118334Speterapp_disable () 41218334Speter{ 41318334Speter if (app_on) 41418334Speter { 41550503Sobrien fputs (ASM_APP_OFF, asm_out_file); 41618334Speter app_on = 0; 41718334Speter } 41818334Speter} 41918334Speter 42090087Sobrien/* Return the number of slots filled in the current 42118334Speter delayed branch sequence (we don't count the insn needing the 42218334Speter delay slot). Zero if not in a delayed branch sequence. */ 42318334Speter 42418334Speter#ifdef DELAY_SLOTS 42518334Speterint 42618334Speterdbr_sequence_length () 42718334Speter{ 42818334Speter if (final_sequence != 0) 42918334Speter return XVECLEN (final_sequence, 0) - 1; 43018334Speter else 43118334Speter return 0; 43218334Speter} 43318334Speter#endif 43418334Speter 43518334Speter/* The next two pages contain routines used to compute the length of an insn 43618334Speter and to shorten branches. */ 43718334Speter 43818334Speter/* Arrays for insn lengths, and addresses. The latter is referenced by 43918334Speter `insn_current_length'. */ 44018334Speter 44190087Sobrienstatic int *insn_lengths; 44218334Speter 44390087Sobrien#ifdef HAVE_ATTR_length 44490087Sobrienvarray_type insn_addresses_; 44590087Sobrien#endif 44690087Sobrien 44752515Sobrien/* Max uid for which the above arrays are valid. */ 44852515Sobrienstatic int insn_lengths_max_uid; 44952515Sobrien 45018334Speter/* Address of insn being processed. Used by `insn_current_length'. */ 45118334Speterint insn_current_address; 45218334Speter 45350503Sobrien/* Address of insn being processed in previous iteration. */ 45450503Sobrienint insn_last_address; 45550503Sobrien 45690087Sobrien/* known invariant alignment of insn being processed. */ 45750503Sobrienint insn_current_align; 45850503Sobrien 45950503Sobrien/* After shorten_branches, for any insn, uid_align[INSN_UID (insn)] 46050503Sobrien gives the next following alignment insn that increases the known 46150503Sobrien alignment, or NULL_RTX if there is no such insn. 46250503Sobrien For any alignment obtained this way, we can again index uid_align with 46350503Sobrien its uid to obtain the next following align that in turn increases the 46450503Sobrien alignment, till we reach NULL_RTX; the sequence obtained this way 46550503Sobrien for each insn we'll call the alignment chain of this insn in the following 46650503Sobrien comments. */ 46750503Sobrien 46890087Sobrienstruct label_alignment 46990087Sobrien{ 47050503Sobrien short alignment; 47150503Sobrien short max_skip; 47250503Sobrien}; 47350503Sobrien 47450503Sobrienstatic rtx *uid_align; 47550503Sobrienstatic int *uid_shuid; 47650503Sobrienstatic struct label_alignment *label_align; 47750503Sobrien 47818334Speter/* Indicate that branch shortening hasn't yet been done. */ 47918334Speter 48018334Spetervoid 48118334Speterinit_insn_lengths () 48218334Speter{ 48350503Sobrien if (uid_shuid) 48450503Sobrien { 48550503Sobrien free (uid_shuid); 48650503Sobrien uid_shuid = 0; 48750503Sobrien } 48850503Sobrien if (insn_lengths) 48950503Sobrien { 49050503Sobrien free (insn_lengths); 49150503Sobrien insn_lengths = 0; 49252515Sobrien insn_lengths_max_uid = 0; 49350503Sobrien } 49490087Sobrien#ifdef HAVE_ATTR_length 49590087Sobrien INSN_ADDRESSES_FREE (); 49690087Sobrien#endif 49750503Sobrien if (uid_align) 49850503Sobrien { 49950503Sobrien free (uid_align); 50050503Sobrien uid_align = 0; 50150503Sobrien } 50218334Speter} 50318334Speter 50418334Speter/* Obtain the current length of an insn. If branch shortening has been done, 50518334Speter get its actual length. Otherwise, get its maximum length. */ 50618334Speter 50718334Speterint 50818334Speterget_attr_length (insn) 50990087Sobrien rtx insn ATTRIBUTE_UNUSED; 51018334Speter{ 51118334Speter#ifdef HAVE_ATTR_length 51218334Speter rtx body; 51318334Speter int i; 51418334Speter int length = 0; 51518334Speter 51652515Sobrien if (insn_lengths_max_uid > INSN_UID (insn)) 51718334Speter return insn_lengths[INSN_UID (insn)]; 51818334Speter else 51918334Speter switch (GET_CODE (insn)) 52018334Speter { 52118334Speter case NOTE: 52218334Speter case BARRIER: 52318334Speter case CODE_LABEL: 52418334Speter return 0; 52518334Speter 52618334Speter case CALL_INSN: 52718334Speter length = insn_default_length (insn); 52818334Speter break; 52918334Speter 53018334Speter case JUMP_INSN: 53118334Speter body = PATTERN (insn); 53218334Speter if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) 53318334Speter { 53450503Sobrien /* Alignment is machine-dependent and should be handled by 53550503Sobrien ADDR_VEC_ALIGN. */ 53618334Speter } 53718334Speter else 53818334Speter length = insn_default_length (insn); 53918334Speter break; 54018334Speter 54118334Speter case INSN: 54218334Speter body = PATTERN (insn); 54318334Speter if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER) 54418334Speter return 0; 54518334Speter 54618334Speter else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0) 54718334Speter length = asm_insn_count (body) * insn_default_length (insn); 54818334Speter else if (GET_CODE (body) == SEQUENCE) 54918334Speter for (i = 0; i < XVECLEN (body, 0); i++) 55018334Speter length += get_attr_length (XVECEXP (body, 0, i)); 55118334Speter else 55218334Speter length = insn_default_length (insn); 55350503Sobrien break; 55450503Sobrien 55550503Sobrien default: 55650503Sobrien break; 55718334Speter } 55818334Speter 55918334Speter#ifdef ADJUST_INSN_LENGTH 56018334Speter ADJUST_INSN_LENGTH (insn, length); 56118334Speter#endif 56218334Speter return length; 56318334Speter#else /* not HAVE_ATTR_length */ 56418334Speter return 0; 56518334Speter#endif /* not HAVE_ATTR_length */ 56618334Speter} 56718334Speter 56850503Sobrien/* Code to handle alignment inside shorten_branches. */ 56950503Sobrien 57050503Sobrien/* Here is an explanation how the algorithm in align_fuzz can give 57150503Sobrien proper results: 57250503Sobrien 57350503Sobrien Call a sequence of instructions beginning with alignment point X 57450503Sobrien and continuing until the next alignment point `block X'. When `X' 57590087Sobrien is used in an expression, it means the alignment value of the 57650503Sobrien alignment point. 57790087Sobrien 57850503Sobrien Call the distance between the start of the first insn of block X, and 57950503Sobrien the end of the last insn of block X `IX', for the `inner size of X'. 58050503Sobrien This is clearly the sum of the instruction lengths. 58190087Sobrien 58250503Sobrien Likewise with the next alignment-delimited block following X, which we 58350503Sobrien shall call block Y. 58490087Sobrien 58550503Sobrien Call the distance between the start of the first insn of block X, and 58650503Sobrien the start of the first insn of block Y `OX', for the `outer size of X'. 58790087Sobrien 58850503Sobrien The estimated padding is then OX - IX. 58990087Sobrien 59050503Sobrien OX can be safely estimated as 59190087Sobrien 59250503Sobrien if (X >= Y) 59350503Sobrien OX = round_up(IX, Y) 59450503Sobrien else 59550503Sobrien OX = round_up(IX, X) + Y - X 59690087Sobrien 59750503Sobrien Clearly est(IX) >= real(IX), because that only depends on the 59850503Sobrien instruction lengths, and those being overestimated is a given. 59990087Sobrien 60050503Sobrien Clearly round_up(foo, Z) >= round_up(bar, Z) if foo >= bar, so 60150503Sobrien we needn't worry about that when thinking about OX. 60290087Sobrien 60350503Sobrien When X >= Y, the alignment provided by Y adds no uncertainty factor 60450503Sobrien for branch ranges starting before X, so we can just round what we have. 60550503Sobrien But when X < Y, we don't know anything about the, so to speak, 60650503Sobrien `middle bits', so we have to assume the worst when aligning up from an 60750503Sobrien address mod X to one mod Y, which is Y - X. */ 60850503Sobrien 60950503Sobrien#ifndef LABEL_ALIGN 61090087Sobrien#define LABEL_ALIGN(LABEL) align_labels_log 61150503Sobrien#endif 61250503Sobrien 61350503Sobrien#ifndef LABEL_ALIGN_MAX_SKIP 61490087Sobrien#define LABEL_ALIGN_MAX_SKIP align_labels_max_skip 61550503Sobrien#endif 61650503Sobrien 61750503Sobrien#ifndef LOOP_ALIGN 61890087Sobrien#define LOOP_ALIGN(LABEL) align_loops_log 61950503Sobrien#endif 62050503Sobrien 62150503Sobrien#ifndef LOOP_ALIGN_MAX_SKIP 62290087Sobrien#define LOOP_ALIGN_MAX_SKIP align_loops_max_skip 62350503Sobrien#endif 62450503Sobrien 62550503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER 62650503Sobrien#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0 62750503Sobrien#endif 62850503Sobrien 62950503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 63050503Sobrien#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0 63150503Sobrien#endif 63250503Sobrien 63390087Sobrien#ifndef JUMP_ALIGN 63490087Sobrien#define JUMP_ALIGN(LABEL) align_jumps_log 63590087Sobrien#endif 63690087Sobrien 63790087Sobrien#ifndef JUMP_ALIGN_MAX_SKIP 63890087Sobrien#define JUMP_ALIGN_MAX_SKIP align_jumps_max_skip 63990087Sobrien#endif 64090087Sobrien 64150503Sobrien#ifndef ADDR_VEC_ALIGN 64290087Sobrienstatic int 64350503Sobrienfinal_addr_vec_align (addr_vec) 64450503Sobrien rtx addr_vec; 64550503Sobrien{ 64690087Sobrien int align = GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec))); 64750503Sobrien 64850503Sobrien if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT) 64950503Sobrien align = BIGGEST_ALIGNMENT / BITS_PER_UNIT; 65090087Sobrien return exact_log2 (align); 65150503Sobrien 65250503Sobrien} 65390087Sobrien 65450503Sobrien#define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC) 65550503Sobrien#endif 65650503Sobrien 65750503Sobrien#ifndef INSN_LENGTH_ALIGNMENT 65850503Sobrien#define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log 65950503Sobrien#endif 66050503Sobrien 66150503Sobrien#define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)]) 66250503Sobrien 66350503Sobrienstatic int min_labelno, max_labelno; 66450503Sobrien 66550503Sobrien#define LABEL_TO_ALIGNMENT(LABEL) \ 66650503Sobrien (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].alignment) 66750503Sobrien 66850503Sobrien#define LABEL_TO_MAX_SKIP(LABEL) \ 66950503Sobrien (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].max_skip) 67050503Sobrien 67150503Sobrien/* For the benefit of port specific code do this also as a function. */ 67290087Sobrien 67350503Sobrienint 67450503Sobrienlabel_to_alignment (label) 67550503Sobrien rtx label; 67650503Sobrien{ 67750503Sobrien return LABEL_TO_ALIGNMENT (label); 67850503Sobrien} 67950503Sobrien 68050503Sobrien#ifdef HAVE_ATTR_length 68150503Sobrien/* The differences in addresses 68250503Sobrien between a branch and its target might grow or shrink depending on 68350503Sobrien the alignment the start insn of the range (the branch for a forward 68450503Sobrien branch or the label for a backward branch) starts out on; if these 68550503Sobrien differences are used naively, they can even oscillate infinitely. 68650503Sobrien We therefore want to compute a 'worst case' address difference that 68750503Sobrien is independent of the alignment the start insn of the range end 68850503Sobrien up on, and that is at least as large as the actual difference. 68950503Sobrien The function align_fuzz calculates the amount we have to add to the 69050503Sobrien naively computed difference, by traversing the part of the alignment 69150503Sobrien chain of the start insn of the range that is in front of the end insn 69250503Sobrien of the range, and considering for each alignment the maximum amount 69350503Sobrien that it might contribute to a size increase. 69450503Sobrien 69550503Sobrien For casesi tables, we also want to know worst case minimum amounts of 69650503Sobrien address difference, in case a machine description wants to introduce 69750503Sobrien some common offset that is added to all offsets in a table. 69890087Sobrien For this purpose, align_fuzz with a growth argument of 0 computes the 69950503Sobrien appropriate adjustment. */ 70050503Sobrien 70150503Sobrien/* Compute the maximum delta by which the difference of the addresses of 70250503Sobrien START and END might grow / shrink due to a different address for start 70350503Sobrien which changes the size of alignment insns between START and END. 70450503Sobrien KNOWN_ALIGN_LOG is the alignment known for START. 70550503Sobrien GROWTH should be ~0 if the objective is to compute potential code size 70650503Sobrien increase, and 0 if the objective is to compute potential shrink. 70750503Sobrien The return value is undefined for any other value of GROWTH. */ 70890087Sobrien 70990087Sobrienstatic int 71050503Sobrienalign_fuzz (start, end, known_align_log, growth) 71150503Sobrien rtx start, end; 71250503Sobrien int known_align_log; 71350503Sobrien unsigned growth; 71450503Sobrien{ 71550503Sobrien int uid = INSN_UID (start); 71650503Sobrien rtx align_label; 71750503Sobrien int known_align = 1 << known_align_log; 71850503Sobrien int end_shuid = INSN_SHUID (end); 71950503Sobrien int fuzz = 0; 72050503Sobrien 72150503Sobrien for (align_label = uid_align[uid]; align_label; align_label = uid_align[uid]) 72250503Sobrien { 72350503Sobrien int align_addr, new_align; 72450503Sobrien 72550503Sobrien uid = INSN_UID (align_label); 72690087Sobrien align_addr = INSN_ADDRESSES (uid) - insn_lengths[uid]; 72750503Sobrien if (uid_shuid[uid] > end_shuid) 72850503Sobrien break; 72950503Sobrien known_align_log = LABEL_TO_ALIGNMENT (align_label); 73050503Sobrien new_align = 1 << known_align_log; 73150503Sobrien if (new_align < known_align) 73250503Sobrien continue; 73350503Sobrien fuzz += (-align_addr ^ growth) & (new_align - known_align); 73450503Sobrien known_align = new_align; 73550503Sobrien } 73650503Sobrien return fuzz; 73750503Sobrien} 73850503Sobrien 73950503Sobrien/* Compute a worst-case reference address of a branch so that it 74050503Sobrien can be safely used in the presence of aligned labels. Since the 74150503Sobrien size of the branch itself is unknown, the size of the branch is 74250503Sobrien not included in the range. I.e. for a forward branch, the reference 74350503Sobrien address is the end address of the branch as known from the previous 74450503Sobrien branch shortening pass, minus a value to account for possible size 74550503Sobrien increase due to alignment. For a backward branch, it is the start 74650503Sobrien address of the branch as known from the current pass, plus a value 74750503Sobrien to account for possible size increase due to alignment. 74850503Sobrien NB.: Therefore, the maximum offset allowed for backward branches needs 74950503Sobrien to exclude the branch size. */ 75090087Sobrien 75150503Sobrienint 75250503Sobrieninsn_current_reference_address (branch) 75350503Sobrien rtx branch; 75450503Sobrien{ 75590087Sobrien rtx dest, seq; 75690087Sobrien int seq_uid; 75790087Sobrien 75890087Sobrien if (! INSN_ADDRESSES_SET_P ()) 75990087Sobrien return 0; 76090087Sobrien 76190087Sobrien seq = NEXT_INSN (PREV_INSN (branch)); 76290087Sobrien seq_uid = INSN_UID (seq); 76350503Sobrien if (GET_CODE (branch) != JUMP_INSN) 76450503Sobrien /* This can happen for example on the PA; the objective is to know the 76550503Sobrien offset to address something in front of the start of the function. 76650503Sobrien Thus, we can treat it like a backward branch. 76750503Sobrien We assume here that FUNCTION_BOUNDARY / BITS_PER_UNIT is larger than 76850503Sobrien any alignment we'd encounter, so we skip the call to align_fuzz. */ 76950503Sobrien return insn_current_address; 77050503Sobrien dest = JUMP_LABEL (branch); 77190087Sobrien 77290087Sobrien /* BRANCH has no proper alignment chain set, so use SEQ. 77390087Sobrien BRANCH also has no INSN_SHUID. */ 77490087Sobrien if (INSN_SHUID (seq) < INSN_SHUID (dest)) 77550503Sobrien { 77690087Sobrien /* Forward branch. */ 77750503Sobrien return (insn_last_address + insn_lengths[seq_uid] 77850503Sobrien - align_fuzz (seq, dest, length_unit_log, ~0)); 77950503Sobrien } 78050503Sobrien else 78150503Sobrien { 78290087Sobrien /* Backward branch. */ 78350503Sobrien return (insn_current_address 78450503Sobrien + align_fuzz (dest, seq, length_unit_log, ~0)); 78550503Sobrien } 78650503Sobrien} 78750503Sobrien#endif /* HAVE_ATTR_length */ 78850503Sobrien 78990087Sobrienvoid 79090087Sobriencompute_alignments () 79190087Sobrien{ 79290087Sobrien int i; 79390087Sobrien int log, max_skip, max_log; 79490087Sobrien 79590087Sobrien if (label_align) 79690087Sobrien { 79790087Sobrien free (label_align); 79890087Sobrien label_align = 0; 79990087Sobrien } 80090087Sobrien 80190087Sobrien max_labelno = max_label_num (); 80290087Sobrien min_labelno = get_first_label_num (); 80390087Sobrien label_align = (struct label_alignment *) 80490087Sobrien xcalloc (max_labelno - min_labelno + 1, sizeof (struct label_alignment)); 80590087Sobrien 80690087Sobrien /* If not optimizing or optimizing for size, don't assign any alignments. */ 80790087Sobrien if (! optimize || optimize_size) 80890087Sobrien return; 80990087Sobrien 81090087Sobrien for (i = 0; i < n_basic_blocks; i++) 81190087Sobrien { 81290087Sobrien basic_block bb = BASIC_BLOCK (i); 81390087Sobrien rtx label = bb->head; 81490087Sobrien int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0; 81590087Sobrien edge e; 81690087Sobrien 81790087Sobrien if (GET_CODE (label) != CODE_LABEL) 81890087Sobrien continue; 81990087Sobrien max_log = LABEL_ALIGN (label); 82090087Sobrien max_skip = LABEL_ALIGN_MAX_SKIP; 82190087Sobrien 82290087Sobrien for (e = bb->pred; e; e = e->pred_next) 82390087Sobrien { 82490087Sobrien if (e->flags & EDGE_FALLTHRU) 82590087Sobrien has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e); 82690087Sobrien else 82790087Sobrien branch_frequency += EDGE_FREQUENCY (e); 82890087Sobrien } 82990087Sobrien 83090087Sobrien /* There are two purposes to align block with no fallthru incoming edge: 83190087Sobrien 1) to avoid fetch stalls when branch destination is near cache boundary 83290087Sobrien 2) to improve cache efficiency in case the previous block is not executed 83390087Sobrien (so it does not need to be in the cache). 83490087Sobrien 83590087Sobrien We to catch first case, we align frequently executed blocks. 83690087Sobrien To catch the second, we align blocks that are executed more frequently 83790087Sobrien than the predecessor and the predecessor is likely to not be executed 83890087Sobrien when function is called. */ 83990087Sobrien 84090087Sobrien if (!has_fallthru 84190087Sobrien && (branch_frequency > BB_FREQ_MAX / 10 84290087Sobrien || (bb->frequency > BASIC_BLOCK (i - 1)->frequency * 10 84390087Sobrien && (BASIC_BLOCK (i - 1)->frequency 84490087Sobrien <= ENTRY_BLOCK_PTR->frequency / 2)))) 84590087Sobrien { 84690087Sobrien log = JUMP_ALIGN (label); 84790087Sobrien if (max_log < log) 84890087Sobrien { 84990087Sobrien max_log = log; 85090087Sobrien max_skip = JUMP_ALIGN_MAX_SKIP; 85190087Sobrien } 85290087Sobrien } 85390087Sobrien /* In case block is frequent and reached mostly by non-fallthru edge, 85490087Sobrien align it. It is most likely an first block of loop. */ 85590087Sobrien if (has_fallthru 85690087Sobrien && branch_frequency + fallthru_frequency > BB_FREQ_MAX / 10 85790087Sobrien && branch_frequency > fallthru_frequency * 5) 85890087Sobrien { 85990087Sobrien log = LOOP_ALIGN (label); 86090087Sobrien if (max_log < log) 86190087Sobrien { 86290087Sobrien max_log = log; 86390087Sobrien max_skip = LOOP_ALIGN_MAX_SKIP; 86490087Sobrien } 86590087Sobrien } 86690087Sobrien LABEL_TO_ALIGNMENT (label) = max_log; 86790087Sobrien LABEL_TO_MAX_SKIP (label) = max_skip; 86890087Sobrien } 86990087Sobrien} 87090087Sobrien 87118334Speter/* Make a pass over all insns and compute their actual lengths by shortening 87218334Speter any branches of variable length if possible. */ 87318334Speter 87418334Speter/* Give a default value for the lowest address in a function. */ 87518334Speter 87618334Speter#ifndef FIRST_INSN_ADDRESS 87718334Speter#define FIRST_INSN_ADDRESS 0 87818334Speter#endif 87918334Speter 88050503Sobrien/* shorten_branches might be called multiple times: for example, the SH 88150503Sobrien port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG. 88250503Sobrien In order to do this, it needs proper length information, which it obtains 88350503Sobrien by calling shorten_branches. This cannot be collapsed with 88490087Sobrien shorten_branches itself into a single pass unless we also want to integrate 88550503Sobrien reorg.c, since the branch splitting exposes new instructions with delay 88650503Sobrien slots. */ 88750503Sobrien 88818334Spetervoid 88918334Spetershorten_branches (first) 89090087Sobrien rtx first ATTRIBUTE_UNUSED; 89118334Speter{ 89250503Sobrien rtx insn; 89350503Sobrien int max_uid; 89450503Sobrien int i; 89550503Sobrien int max_log; 89650503Sobrien int max_skip; 89718334Speter#ifdef HAVE_ATTR_length 89850503Sobrien#define MAX_CODE_ALIGN 16 89950503Sobrien rtx seq; 90018334Speter int something_changed = 1; 90118334Speter char *varying_length; 90218334Speter rtx body; 90318334Speter int uid; 90450503Sobrien rtx align_tab[MAX_CODE_ALIGN]; 90518334Speter 90650503Sobrien#endif 90718334Speter 90850503Sobrien /* Compute maximum UID and allocate label_align / uid_shuid. */ 90950503Sobrien max_uid = get_max_uid (); 91050503Sobrien 91150503Sobrien uid_shuid = (int *) xmalloc (max_uid * sizeof *uid_shuid); 91250503Sobrien 91390087Sobrien if (max_labelno != max_label_num ()) 91490087Sobrien { 91590087Sobrien int old = max_labelno; 91690087Sobrien int n_labels; 91790087Sobrien int n_old_labels; 91890087Sobrien 91990087Sobrien max_labelno = max_label_num (); 92090087Sobrien 92190087Sobrien n_labels = max_labelno - min_labelno + 1; 92290087Sobrien n_old_labels = old - min_labelno + 1; 92390087Sobrien 92490087Sobrien label_align = (struct label_alignment *) xrealloc 92590087Sobrien (label_align, n_labels * sizeof (struct label_alignment)); 92690087Sobrien 92790087Sobrien /* Range of labels grows monotonically in the function. Abort here 92890087Sobrien means that the initialization of array got lost. */ 92990087Sobrien if (n_old_labels > n_labels) 93090087Sobrien abort (); 93190087Sobrien 93290087Sobrien memset (label_align + n_old_labels, 0, 93390087Sobrien (n_labels - n_old_labels) * sizeof (struct label_alignment)); 93490087Sobrien } 93590087Sobrien 93650503Sobrien /* Initialize label_align and set up uid_shuid to be strictly 93750503Sobrien monotonically rising with insn order. */ 93850503Sobrien /* We use max_log here to keep track of the maximum alignment we want to 93950503Sobrien impose on the next CODE_LABEL (or the current one if we are processing 94050503Sobrien the CODE_LABEL itself). */ 94190087Sobrien 94250503Sobrien max_log = 0; 94350503Sobrien max_skip = 0; 94450503Sobrien 94550503Sobrien for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn)) 94650503Sobrien { 94750503Sobrien int log; 94850503Sobrien 94950503Sobrien INSN_SHUID (insn) = i++; 95090087Sobrien if (INSN_P (insn)) 95150503Sobrien { 95250503Sobrien /* reorg might make the first insn of a loop being run once only, 95350503Sobrien and delete the label in front of it. Then we want to apply 95450503Sobrien the loop alignment to the new label created by reorg, which 95550503Sobrien is separated by the former loop start insn from the 95650503Sobrien NOTE_INSN_LOOP_BEG. */ 95750503Sobrien } 95850503Sobrien else if (GET_CODE (insn) == CODE_LABEL) 95950503Sobrien { 96050503Sobrien rtx next; 96150503Sobrien 96290087Sobrien /* Merge in alignments computed by compute_alignments. */ 96390087Sobrien log = LABEL_TO_ALIGNMENT (insn); 96490087Sobrien if (max_log < log) 96590087Sobrien { 96690087Sobrien max_log = log; 96790087Sobrien max_skip = LABEL_TO_MAX_SKIP (insn); 96890087Sobrien } 96990087Sobrien 97050503Sobrien log = LABEL_ALIGN (insn); 97150503Sobrien if (max_log < log) 97250503Sobrien { 97350503Sobrien max_log = log; 97450503Sobrien max_skip = LABEL_ALIGN_MAX_SKIP; 97550503Sobrien } 97650503Sobrien next = NEXT_INSN (insn); 97750503Sobrien /* ADDR_VECs only take room if read-only data goes into the text 97850503Sobrien section. */ 97950503Sobrien if (JUMP_TABLES_IN_TEXT_SECTION 98050503Sobrien#if !defined(READONLY_DATA_SECTION) 98150503Sobrien || 1 98250503Sobrien#endif 98350503Sobrien ) 98450503Sobrien if (next && GET_CODE (next) == JUMP_INSN) 98550503Sobrien { 98650503Sobrien rtx nextbody = PATTERN (next); 98750503Sobrien if (GET_CODE (nextbody) == ADDR_VEC 98850503Sobrien || GET_CODE (nextbody) == ADDR_DIFF_VEC) 98950503Sobrien { 99050503Sobrien log = ADDR_VEC_ALIGN (next); 99150503Sobrien if (max_log < log) 99250503Sobrien { 99350503Sobrien max_log = log; 99450503Sobrien max_skip = LABEL_ALIGN_MAX_SKIP; 99550503Sobrien } 99650503Sobrien } 99750503Sobrien } 99850503Sobrien LABEL_TO_ALIGNMENT (insn) = max_log; 99950503Sobrien LABEL_TO_MAX_SKIP (insn) = max_skip; 100050503Sobrien max_log = 0; 100150503Sobrien max_skip = 0; 100250503Sobrien } 100350503Sobrien else if (GET_CODE (insn) == BARRIER) 100450503Sobrien { 100550503Sobrien rtx label; 100650503Sobrien 100790087Sobrien for (label = insn; label && ! INSN_P (label); 100850503Sobrien label = NEXT_INSN (label)) 100950503Sobrien if (GET_CODE (label) == CODE_LABEL) 101050503Sobrien { 101150503Sobrien log = LABEL_ALIGN_AFTER_BARRIER (insn); 101250503Sobrien if (max_log < log) 101350503Sobrien { 101450503Sobrien max_log = log; 101550503Sobrien max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP; 101650503Sobrien } 101750503Sobrien break; 101850503Sobrien } 101950503Sobrien } 102050503Sobrien } 102150503Sobrien#ifdef HAVE_ATTR_length 102250503Sobrien 102350503Sobrien /* Allocate the rest of the arrays. */ 102490087Sobrien insn_lengths = (int *) xmalloc (max_uid * sizeof (*insn_lengths)); 102552515Sobrien insn_lengths_max_uid = max_uid; 102650503Sobrien /* Syntax errors can lead to labels being outside of the main insn stream. 102750503Sobrien Initialize insn_addresses, so that we get reproducible results. */ 102890087Sobrien INSN_ADDRESSES_ALLOC (max_uid); 102950503Sobrien 103090087Sobrien varying_length = (char *) xcalloc (max_uid, sizeof (char)); 103150503Sobrien 103250503Sobrien /* Initialize uid_align. We scan instructions 103350503Sobrien from end to start, and keep in align_tab[n] the last seen insn 103450503Sobrien that does an alignment of at least n+1, i.e. the successor 103550503Sobrien in the alignment chain for an insn that does / has a known 103650503Sobrien alignment of n. */ 103790087Sobrien uid_align = (rtx *) xcalloc (max_uid, sizeof *uid_align); 103850503Sobrien 103990087Sobrien for (i = MAX_CODE_ALIGN; --i >= 0;) 104050503Sobrien align_tab[i] = NULL_RTX; 104150503Sobrien seq = get_last_insn (); 104250503Sobrien for (; seq; seq = PREV_INSN (seq)) 104350503Sobrien { 104450503Sobrien int uid = INSN_UID (seq); 104550503Sobrien int log; 104650503Sobrien log = (GET_CODE (seq) == CODE_LABEL ? LABEL_TO_ALIGNMENT (seq) : 0); 104750503Sobrien uid_align[uid] = align_tab[0]; 104850503Sobrien if (log) 104950503Sobrien { 105050503Sobrien /* Found an alignment label. */ 105150503Sobrien uid_align[uid] = align_tab[log]; 105250503Sobrien for (i = log - 1; i >= 0; i--) 105350503Sobrien align_tab[i] = seq; 105450503Sobrien } 105550503Sobrien } 105650503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE 105750503Sobrien if (optimize) 105850503Sobrien { 105950503Sobrien /* Look for ADDR_DIFF_VECs, and initialize their minimum and maximum 106050503Sobrien label fields. */ 106150503Sobrien 106250503Sobrien int min_shuid = INSN_SHUID (get_insns ()) - 1; 106350503Sobrien int max_shuid = INSN_SHUID (get_last_insn ()) + 1; 106450503Sobrien int rel; 106550503Sobrien 106650503Sobrien for (insn = first; insn != 0; insn = NEXT_INSN (insn)) 106750503Sobrien { 106850503Sobrien rtx min_lab = NULL_RTX, max_lab = NULL_RTX, pat; 106950503Sobrien int len, i, min, max, insn_shuid; 107050503Sobrien int min_align; 107150503Sobrien addr_diff_vec_flags flags; 107250503Sobrien 107350503Sobrien if (GET_CODE (insn) != JUMP_INSN 107450503Sobrien || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC) 107550503Sobrien continue; 107650503Sobrien pat = PATTERN (insn); 107750503Sobrien len = XVECLEN (pat, 1); 107850503Sobrien if (len <= 0) 107950503Sobrien abort (); 108050503Sobrien min_align = MAX_CODE_ALIGN; 108150503Sobrien for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--) 108250503Sobrien { 108350503Sobrien rtx lab = XEXP (XVECEXP (pat, 1, i), 0); 108450503Sobrien int shuid = INSN_SHUID (lab); 108550503Sobrien if (shuid < min) 108650503Sobrien { 108750503Sobrien min = shuid; 108850503Sobrien min_lab = lab; 108950503Sobrien } 109050503Sobrien if (shuid > max) 109150503Sobrien { 109250503Sobrien max = shuid; 109350503Sobrien max_lab = lab; 109450503Sobrien } 109550503Sobrien if (min_align > LABEL_TO_ALIGNMENT (lab)) 109650503Sobrien min_align = LABEL_TO_ALIGNMENT (lab); 109750503Sobrien } 109850503Sobrien XEXP (pat, 2) = gen_rtx_LABEL_REF (VOIDmode, min_lab); 109950503Sobrien XEXP (pat, 3) = gen_rtx_LABEL_REF (VOIDmode, max_lab); 110050503Sobrien insn_shuid = INSN_SHUID (insn); 110150503Sobrien rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0)); 110250503Sobrien flags.min_align = min_align; 110350503Sobrien flags.base_after_vec = rel > insn_shuid; 110450503Sobrien flags.min_after_vec = min > insn_shuid; 110550503Sobrien flags.max_after_vec = max > insn_shuid; 110650503Sobrien flags.min_after_base = min > rel; 110750503Sobrien flags.max_after_base = max > rel; 110850503Sobrien ADDR_DIFF_VEC_FLAGS (pat) = flags; 110950503Sobrien } 111050503Sobrien } 111150503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */ 111250503Sobrien 111318334Speter /* Compute initial lengths, addresses, and varying flags for each insn. */ 111418334Speter for (insn_current_address = FIRST_INSN_ADDRESS, insn = first; 111518334Speter insn != 0; 111618334Speter insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn)) 111718334Speter { 111818334Speter uid = INSN_UID (insn); 111950503Sobrien 112050503Sobrien insn_lengths[uid] = 0; 112150503Sobrien 112250503Sobrien if (GET_CODE (insn) == CODE_LABEL) 112350503Sobrien { 112450503Sobrien int log = LABEL_TO_ALIGNMENT (insn); 112550503Sobrien if (log) 112650503Sobrien { 112750503Sobrien int align = 1 << log; 112850503Sobrien int new_address = (insn_current_address + align - 1) & -align; 112950503Sobrien insn_lengths[uid] = new_address - insn_current_address; 113050503Sobrien } 113150503Sobrien } 113250503Sobrien 113390087Sobrien INSN_ADDRESSES (uid) = insn_current_address; 113490087Sobrien 113518334Speter if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER 113618334Speter || GET_CODE (insn) == CODE_LABEL) 113718334Speter continue; 113850503Sobrien if (INSN_DELETED_P (insn)) 113950503Sobrien continue; 114018334Speter 114118334Speter body = PATTERN (insn); 114218334Speter if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) 114318334Speter { 114418334Speter /* This only takes room if read-only data goes into the text 114518334Speter section. */ 114650503Sobrien if (JUMP_TABLES_IN_TEXT_SECTION 114750503Sobrien#if !defined(READONLY_DATA_SECTION) 114850503Sobrien || 1 114918334Speter#endif 115050503Sobrien ) 115150503Sobrien insn_lengths[uid] = (XVECLEN (body, 115250503Sobrien GET_CODE (body) == ADDR_DIFF_VEC) 115350503Sobrien * GET_MODE_SIZE (GET_MODE (body))); 115450503Sobrien /* Alignment is handled by ADDR_VEC_ALIGN. */ 115518334Speter } 115690087Sobrien else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0) 115718334Speter insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn); 115818334Speter else if (GET_CODE (body) == SEQUENCE) 115918334Speter { 116018334Speter int i; 116118334Speter int const_delay_slots; 116218334Speter#ifdef DELAY_SLOTS 116318334Speter const_delay_slots = const_num_delay_slots (XVECEXP (body, 0, 0)); 116418334Speter#else 116518334Speter const_delay_slots = 0; 116618334Speter#endif 116718334Speter /* Inside a delay slot sequence, we do not do any branch shortening 116818334Speter if the shortening could change the number of delay slots 116950503Sobrien of the branch. */ 117018334Speter for (i = 0; i < XVECLEN (body, 0); i++) 117118334Speter { 117218334Speter rtx inner_insn = XVECEXP (body, 0, i); 117318334Speter int inner_uid = INSN_UID (inner_insn); 117418334Speter int inner_length; 117518334Speter 117690087Sobrien if (GET_CODE (body) == ASM_INPUT 117790087Sobrien || asm_noperands (PATTERN (XVECEXP (body, 0, i))) >= 0) 117818334Speter inner_length = (asm_insn_count (PATTERN (inner_insn)) 117918334Speter * insn_default_length (inner_insn)); 118018334Speter else 118118334Speter inner_length = insn_default_length (inner_insn); 118290087Sobrien 118318334Speter insn_lengths[inner_uid] = inner_length; 118418334Speter if (const_delay_slots) 118518334Speter { 118618334Speter if ((varying_length[inner_uid] 118718334Speter = insn_variable_length_p (inner_insn)) != 0) 118818334Speter varying_length[uid] = 1; 118990087Sobrien INSN_ADDRESSES (inner_uid) = (insn_current_address 119090087Sobrien + insn_lengths[uid]); 119118334Speter } 119218334Speter else 119318334Speter varying_length[inner_uid] = 0; 119418334Speter insn_lengths[uid] += inner_length; 119518334Speter } 119618334Speter } 119718334Speter else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER) 119818334Speter { 119918334Speter insn_lengths[uid] = insn_default_length (insn); 120018334Speter varying_length[uid] = insn_variable_length_p (insn); 120118334Speter } 120218334Speter 120318334Speter /* If needed, do any adjustment. */ 120418334Speter#ifdef ADJUST_INSN_LENGTH 120518334Speter ADJUST_INSN_LENGTH (insn, insn_lengths[uid]); 120652515Sobrien if (insn_lengths[uid] < 0) 120790087Sobrien fatal_insn ("negative insn length", insn); 120818334Speter#endif 120918334Speter } 121018334Speter 121118334Speter /* Now loop over all the insns finding varying length insns. For each, 121218334Speter get the current insn length. If it has changed, reflect the change. 121318334Speter When nothing changes for a full pass, we are done. */ 121418334Speter 121518334Speter while (something_changed) 121618334Speter { 121718334Speter something_changed = 0; 121850503Sobrien insn_current_align = MAX_CODE_ALIGN - 1; 121918334Speter for (insn_current_address = FIRST_INSN_ADDRESS, insn = first; 122018334Speter insn != 0; 122118334Speter insn = NEXT_INSN (insn)) 122218334Speter { 122318334Speter int new_length; 122450503Sobrien#ifdef ADJUST_INSN_LENGTH 122518334Speter int tmp_length; 122650503Sobrien#endif 122750503Sobrien int length_align; 122818334Speter 122918334Speter uid = INSN_UID (insn); 123050503Sobrien 123150503Sobrien if (GET_CODE (insn) == CODE_LABEL) 123250503Sobrien { 123350503Sobrien int log = LABEL_TO_ALIGNMENT (insn); 123450503Sobrien if (log > insn_current_align) 123550503Sobrien { 123650503Sobrien int align = 1 << log; 123750503Sobrien int new_address= (insn_current_address + align - 1) & -align; 123850503Sobrien insn_lengths[uid] = new_address - insn_current_address; 123950503Sobrien insn_current_align = log; 124050503Sobrien insn_current_address = new_address; 124150503Sobrien } 124250503Sobrien else 124350503Sobrien insn_lengths[uid] = 0; 124490087Sobrien INSN_ADDRESSES (uid) = insn_current_address; 124550503Sobrien continue; 124650503Sobrien } 124750503Sobrien 124850503Sobrien length_align = INSN_LENGTH_ALIGNMENT (insn); 124950503Sobrien if (length_align < insn_current_align) 125050503Sobrien insn_current_align = length_align; 125150503Sobrien 125290087Sobrien insn_last_address = INSN_ADDRESSES (uid); 125390087Sobrien INSN_ADDRESSES (uid) = insn_current_address; 125450503Sobrien 125550503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE 125650503Sobrien if (optimize && GET_CODE (insn) == JUMP_INSN 125750503Sobrien && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC) 125818334Speter { 125950503Sobrien rtx body = PATTERN (insn); 126050503Sobrien int old_length = insn_lengths[uid]; 126150503Sobrien rtx rel_lab = XEXP (XEXP (body, 0), 0); 126250503Sobrien rtx min_lab = XEXP (XEXP (body, 2), 0); 126350503Sobrien rtx max_lab = XEXP (XEXP (body, 3), 0); 126490087Sobrien int rel_addr = INSN_ADDRESSES (INSN_UID (rel_lab)); 126590087Sobrien int min_addr = INSN_ADDRESSES (INSN_UID (min_lab)); 126690087Sobrien int max_addr = INSN_ADDRESSES (INSN_UID (max_lab)); 126750503Sobrien rtx prev; 126850503Sobrien int rel_align = 0; 126990087Sobrien addr_diff_vec_flags flags; 127050503Sobrien 127190087Sobrien /* Avoid automatic aggregate initialization. */ 127290087Sobrien flags = ADDR_DIFF_VEC_FLAGS (body); 127390087Sobrien 127450503Sobrien /* Try to find a known alignment for rel_lab. */ 127550503Sobrien for (prev = rel_lab; 127650503Sobrien prev 127750503Sobrien && ! insn_lengths[INSN_UID (prev)] 127850503Sobrien && ! (varying_length[INSN_UID (prev)] & 1); 127950503Sobrien prev = PREV_INSN (prev)) 128050503Sobrien if (varying_length[INSN_UID (prev)] & 2) 128150503Sobrien { 128250503Sobrien rel_align = LABEL_TO_ALIGNMENT (prev); 128350503Sobrien break; 128450503Sobrien } 128550503Sobrien 128650503Sobrien /* See the comment on addr_diff_vec_flags in rtl.h for the 128750503Sobrien meaning of the flags values. base: REL_LAB vec: INSN */ 128850503Sobrien /* Anything after INSN has still addresses from the last 128950503Sobrien pass; adjust these so that they reflect our current 129050503Sobrien estimate for this pass. */ 129150503Sobrien if (flags.base_after_vec) 129250503Sobrien rel_addr += insn_current_address - insn_last_address; 129350503Sobrien if (flags.min_after_vec) 129450503Sobrien min_addr += insn_current_address - insn_last_address; 129550503Sobrien if (flags.max_after_vec) 129650503Sobrien max_addr += insn_current_address - insn_last_address; 129750503Sobrien /* We want to know the worst case, i.e. lowest possible value 129850503Sobrien for the offset of MIN_LAB. If MIN_LAB is after REL_LAB, 129950503Sobrien its offset is positive, and we have to be wary of code shrink; 130050503Sobrien otherwise, it is negative, and we have to be vary of code 130150503Sobrien size increase. */ 130250503Sobrien if (flags.min_after_base) 130350503Sobrien { 130450503Sobrien /* If INSN is between REL_LAB and MIN_LAB, the size 130550503Sobrien changes we are about to make can change the alignment 130650503Sobrien within the observed offset, therefore we have to break 130750503Sobrien it up into two parts that are independent. */ 130850503Sobrien if (! flags.base_after_vec && flags.min_after_vec) 130950503Sobrien { 131050503Sobrien min_addr -= align_fuzz (rel_lab, insn, rel_align, 0); 131150503Sobrien min_addr -= align_fuzz (insn, min_lab, 0, 0); 131250503Sobrien } 131350503Sobrien else 131450503Sobrien min_addr -= align_fuzz (rel_lab, min_lab, rel_align, 0); 131550503Sobrien } 131650503Sobrien else 131750503Sobrien { 131850503Sobrien if (flags.base_after_vec && ! flags.min_after_vec) 131950503Sobrien { 132050503Sobrien min_addr -= align_fuzz (min_lab, insn, 0, ~0); 132150503Sobrien min_addr -= align_fuzz (insn, rel_lab, 0, ~0); 132250503Sobrien } 132350503Sobrien else 132450503Sobrien min_addr -= align_fuzz (min_lab, rel_lab, 0, ~0); 132550503Sobrien } 132650503Sobrien /* Likewise, determine the highest lowest possible value 132750503Sobrien for the offset of MAX_LAB. */ 132850503Sobrien if (flags.max_after_base) 132950503Sobrien { 133050503Sobrien if (! flags.base_after_vec && flags.max_after_vec) 133150503Sobrien { 133250503Sobrien max_addr += align_fuzz (rel_lab, insn, rel_align, ~0); 133350503Sobrien max_addr += align_fuzz (insn, max_lab, 0, ~0); 133450503Sobrien } 133550503Sobrien else 133650503Sobrien max_addr += align_fuzz (rel_lab, max_lab, rel_align, ~0); 133750503Sobrien } 133850503Sobrien else 133950503Sobrien { 134050503Sobrien if (flags.base_after_vec && ! flags.max_after_vec) 134150503Sobrien { 134250503Sobrien max_addr += align_fuzz (max_lab, insn, 0, 0); 134350503Sobrien max_addr += align_fuzz (insn, rel_lab, 0, 0); 134450503Sobrien } 134550503Sobrien else 134650503Sobrien max_addr += align_fuzz (max_lab, rel_lab, 0, 0); 134750503Sobrien } 134850503Sobrien PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr, 134950503Sobrien max_addr - rel_addr, 135050503Sobrien body)); 135150503Sobrien if (JUMP_TABLES_IN_TEXT_SECTION 135250503Sobrien#if !defined(READONLY_DATA_SECTION) 135350503Sobrien || 1 135450503Sobrien#endif 135550503Sobrien ) 135650503Sobrien { 135750503Sobrien insn_lengths[uid] 135850503Sobrien = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body))); 135950503Sobrien insn_current_address += insn_lengths[uid]; 136050503Sobrien if (insn_lengths[uid] != old_length) 136150503Sobrien something_changed = 1; 136250503Sobrien } 136350503Sobrien 136450503Sobrien continue; 136550503Sobrien } 136650503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */ 136750503Sobrien 136850503Sobrien if (! (varying_length[uid])) 136950503Sobrien { 137090087Sobrien if (GET_CODE (insn) == INSN 137190087Sobrien && GET_CODE (PATTERN (insn)) == SEQUENCE) 137290087Sobrien { 137390087Sobrien int i; 137490087Sobrien 137590087Sobrien body = PATTERN (insn); 137690087Sobrien for (i = 0; i < XVECLEN (body, 0); i++) 137790087Sobrien { 137890087Sobrien rtx inner_insn = XVECEXP (body, 0, i); 137990087Sobrien int inner_uid = INSN_UID (inner_insn); 138090087Sobrien 138190087Sobrien INSN_ADDRESSES (inner_uid) = insn_current_address; 138290087Sobrien 138390087Sobrien insn_current_address += insn_lengths[inner_uid]; 138490087Sobrien } 138590087Sobrien } 138690087Sobrien else 138790087Sobrien insn_current_address += insn_lengths[uid]; 138890087Sobrien 138918334Speter continue; 139018334Speter } 139190087Sobrien 139218334Speter if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) 139318334Speter { 139418334Speter int i; 139590087Sobrien 139618334Speter body = PATTERN (insn); 139718334Speter new_length = 0; 139818334Speter for (i = 0; i < XVECLEN (body, 0); i++) 139918334Speter { 140018334Speter rtx inner_insn = XVECEXP (body, 0, i); 140118334Speter int inner_uid = INSN_UID (inner_insn); 140218334Speter int inner_length; 140318334Speter 140490087Sobrien INSN_ADDRESSES (inner_uid) = insn_current_address; 140518334Speter 140618334Speter /* insn_current_length returns 0 for insns with a 140718334Speter non-varying length. */ 140818334Speter if (! varying_length[inner_uid]) 140918334Speter inner_length = insn_lengths[inner_uid]; 141018334Speter else 141118334Speter inner_length = insn_current_length (inner_insn); 141218334Speter 141318334Speter if (inner_length != insn_lengths[inner_uid]) 141418334Speter { 141518334Speter insn_lengths[inner_uid] = inner_length; 141618334Speter something_changed = 1; 141718334Speter } 141818334Speter insn_current_address += insn_lengths[inner_uid]; 141918334Speter new_length += inner_length; 142018334Speter } 142118334Speter } 142218334Speter else 142318334Speter { 142418334Speter new_length = insn_current_length (insn); 142518334Speter insn_current_address += new_length; 142618334Speter } 142718334Speter 142818334Speter#ifdef ADJUST_INSN_LENGTH 142918334Speter /* If needed, do any adjustment. */ 143018334Speter tmp_length = new_length; 143118334Speter ADJUST_INSN_LENGTH (insn, new_length); 143218334Speter insn_current_address += (new_length - tmp_length); 143318334Speter#endif 143418334Speter 143518334Speter if (new_length != insn_lengths[uid]) 143618334Speter { 143718334Speter insn_lengths[uid] = new_length; 143818334Speter something_changed = 1; 143918334Speter } 144018334Speter } 144118334Speter /* For a non-optimizing compile, do only a single pass. */ 144218334Speter if (!optimize) 144318334Speter break; 144418334Speter } 144550503Sobrien 144650503Sobrien free (varying_length); 144750503Sobrien 144818334Speter#endif /* HAVE_ATTR_length */ 144918334Speter} 145018334Speter 145118334Speter#ifdef HAVE_ATTR_length 145218334Speter/* Given the body of an INSN known to be generated by an ASM statement, return 145318334Speter the number of machine instructions likely to be generated for this insn. 145418334Speter This is used to compute its length. */ 145518334Speter 145618334Speterstatic int 145718334Speterasm_insn_count (body) 145818334Speter rtx body; 145918334Speter{ 146090087Sobrien const char *template; 146118334Speter int count = 1; 146218334Speter 146318334Speter if (GET_CODE (body) == ASM_INPUT) 146418334Speter template = XSTR (body, 0); 146518334Speter else 146690087Sobrien template = decode_asm_operands (body, NULL, NULL, NULL, NULL); 146718334Speter 146890087Sobrien for (; *template; template++) 146990087Sobrien if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n') 147018334Speter count++; 147118334Speter 147218334Speter return count; 147318334Speter} 147418334Speter#endif 147518334Speter 147618334Speter/* Output assembler code for the start of a function, 147718334Speter and initialize some of the variables in this file 147818334Speter for the new function. The label for the function and associated 147918334Speter assembler pseudo-ops have already been output in `assemble_start_function'. 148018334Speter 148118334Speter FIRST is the first insn of the rtl for the function being compiled. 148218334Speter FILE is the file to write assembler code to. 148318334Speter OPTIMIZE is nonzero if we should eliminate redundant 148418334Speter test and compare insns. */ 148518334Speter 148618334Spetervoid 148718334Speterfinal_start_function (first, file, optimize) 148818334Speter rtx first; 148918334Speter FILE *file; 149090087Sobrien int optimize ATTRIBUTE_UNUSED; 149118334Speter{ 149218334Speter block_depth = 0; 149318334Speter 149418334Speter this_is_asm_operands = 0; 149518334Speter 149618334Speter#ifdef NON_SAVING_SETJMP 149718334Speter /* A function that calls setjmp should save and restore all the 149818334Speter call-saved registers on a system where longjmp clobbers them. */ 149918334Speter if (NON_SAVING_SETJMP && current_function_calls_setjmp) 150018334Speter { 150118334Speter int i; 150218334Speter 150318334Speter for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 150452515Sobrien if (!call_used_regs[i]) 150518334Speter regs_ever_live[i] = 1; 150618334Speter } 150718334Speter#endif 150890087Sobrien 150918334Speter if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED) 151090087Sobrien notice_source_line (first); 151190087Sobrien high_block_linenum = high_function_linenum = last_linenum; 151218334Speter 151390087Sobrien (*debug_hooks->begin_prologue) (last_linenum, last_filename); 151450503Sobrien 151590087Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (IA64_UNWIND_INFO) 151690087Sobrien if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG) 151790087Sobrien dwarf2out_begin_prologue (0, NULL); 151818334Speter#endif 151918334Speter 152018334Speter#ifdef LEAF_REG_REMAP 152152515Sobrien if (current_function_uses_only_leaf_regs) 152218334Speter leaf_renumber_regs (first); 152318334Speter#endif 152418334Speter 152518334Speter /* The Sun386i and perhaps other machines don't work right 152618334Speter if the profiling code comes after the prologue. */ 152718334Speter#ifdef PROFILE_BEFORE_PROLOGUE 152890087Sobrien if (current_function_profile) 152918334Speter profile_function (file); 153018334Speter#endif /* PROFILE_BEFORE_PROLOGUE */ 153118334Speter 153250503Sobrien#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue) 153350503Sobrien if (dwarf2out_do_frame ()) 153450503Sobrien dwarf2out_frame_debug (NULL_RTX); 153550503Sobrien#endif 153650503Sobrien 153790087Sobrien /* If debugging, assign block numbers to all of the blocks in this 153890087Sobrien function. */ 153990087Sobrien if (write_symbols) 154090087Sobrien { 154190087Sobrien remove_unnecessary_notes (); 154290087Sobrien reorder_blocks (); 154390087Sobrien number_blocks (current_function_decl); 154490087Sobrien /* We never actually put out begin/end notes for the top-level 154590087Sobrien block in the function. But, conceptually, that block is 154690087Sobrien always needed. */ 154790087Sobrien TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1; 154890087Sobrien } 154990087Sobrien 155018334Speter /* First output the function prologue: code to set up the stack frame. */ 155190087Sobrien (*targetm.asm_out.function_prologue) (file, get_frame_size ()); 155218334Speter 155390087Sobrien#ifdef VMS_DEBUGGING_INFO 155490087Sobrien /* Output label after the prologue of the function. */ 155590087Sobrien if (write_symbols == VMS_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG) 155690087Sobrien vmsdbgout_after_prologue (); 155718334Speter#endif 155818334Speter 155918334Speter /* If the machine represents the prologue as RTL, the profiling code must 156018334Speter be emitted when NOTE_INSN_PROLOGUE_END is scanned. */ 156118334Speter#ifdef HAVE_prologue 156218334Speter if (! HAVE_prologue) 156318334Speter#endif 156418334Speter profile_after_prologue (file); 156518334Speter} 156618334Speter 156718334Speterstatic void 156818334Speterprofile_after_prologue (file) 156990087Sobrien FILE *file ATTRIBUTE_UNUSED; 157018334Speter{ 157118334Speter#ifndef PROFILE_BEFORE_PROLOGUE 157290087Sobrien if (current_function_profile) 157318334Speter profile_function (file); 157418334Speter#endif /* not PROFILE_BEFORE_PROLOGUE */ 157518334Speter} 157618334Speter 157718334Speterstatic void 157818334Speterprofile_function (file) 157990087Sobrien FILE *file ATTRIBUTE_UNUSED; 158018334Speter{ 158174478Sobrien#ifndef NO_PROFILE_COUNTERS 158250503Sobrien int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE); 158374478Sobrien#endif 158450503Sobrien#if defined(ASM_OUTPUT_REG_PUSH) 158550503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) || defined(STRUCT_VALUE_REGNUM) 158618334Speter int sval = current_function_returns_struct; 158750503Sobrien#endif 158850503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM) 158918334Speter int cxt = current_function_needs_context; 159050503Sobrien#endif 159150503Sobrien#endif /* ASM_OUTPUT_REG_PUSH */ 159218334Speter 159374478Sobrien#ifndef NO_PROFILE_COUNTERS 159418334Speter data_section (); 159518334Speter ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT)); 159696281Sobrien ASM_OUTPUT_INTERNAL_LABEL (file, "LP", current_function_profile_label_no); 159790087Sobrien assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1); 159874478Sobrien#endif 159918334Speter 160050503Sobrien function_section (current_function_decl); 160118334Speter 160250503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 160318334Speter if (sval) 160418334Speter ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_INCOMING_REGNUM); 160518334Speter#else 160650503Sobrien#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 160718334Speter if (sval) 160850503Sobrien { 160950503Sobrien ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_REGNUM); 161050503Sobrien } 161118334Speter#endif 161218334Speter#endif 161318334Speter 161450503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 161518334Speter if (cxt) 161618334Speter ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM); 161718334Speter#else 161850503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 161918334Speter if (cxt) 162050503Sobrien { 162150503Sobrien ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM); 162250503Sobrien } 162318334Speter#endif 162418334Speter#endif 162518334Speter 162696281Sobrien FUNCTION_PROFILER (file, current_function_profile_label_no); 162718334Speter 162850503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 162918334Speter if (cxt) 163018334Speter ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM); 163118334Speter#else 163250503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 163318334Speter if (cxt) 163450503Sobrien { 163550503Sobrien ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM); 163650503Sobrien } 163718334Speter#endif 163818334Speter#endif 163918334Speter 164050503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 164118334Speter if (sval) 164218334Speter ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_INCOMING_REGNUM); 164318334Speter#else 164450503Sobrien#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 164518334Speter if (sval) 164650503Sobrien { 164750503Sobrien ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_REGNUM); 164850503Sobrien } 164918334Speter#endif 165018334Speter#endif 165118334Speter} 165218334Speter 165318334Speter/* Output assembler code for the end of a function. 165418334Speter For clarity, args are same as those of `final_start_function' 165518334Speter even though not all of them are needed. */ 165618334Speter 165718334Spetervoid 165890087Sobrienfinal_end_function () 165918334Speter{ 166090087Sobrien app_disable (); 166118334Speter 166290087Sobrien (*debug_hooks->end_function) (high_function_linenum); 166318334Speter 166418334Speter /* Finally, output the function epilogue: 166518334Speter code to restore the stack frame and return to the caller. */ 166690087Sobrien (*targetm.asm_out.function_epilogue) (asm_out_file, get_frame_size ()); 166718334Speter 166890087Sobrien /* And debug output. */ 166990087Sobrien (*debug_hooks->end_epilogue) (); 167090087Sobrien 167190087Sobrien#if defined (DWARF2_UNWIND_INFO) 167290087Sobrien if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG 167390087Sobrien && dwarf2out_do_frame ()) 167450503Sobrien dwarf2out_end_epilogue (); 167550503Sobrien#endif 167618334Speter} 167718334Speter 167818334Speter/* Output assembler code for some insns: all or part of a function. 167918334Speter For description of args, see `final_start_function', above. 168018334Speter 168118334Speter PRESCAN is 1 if we are not really outputting, 168218334Speter just scanning as if we were outputting. 168318334Speter Prescanning deletes and rearranges insns just like ordinary output. 168418334Speter PRESCAN is -2 if we are outputting after having prescanned. 168518334Speter In this case, don't try to delete or rearrange insns 168618334Speter because that has already been done. 168718334Speter Prescanning is done only on certain machines. */ 168818334Speter 168918334Spetervoid 169018334Speterfinal (first, file, optimize, prescan) 169118334Speter rtx first; 169218334Speter FILE *file; 169318334Speter int optimize; 169418334Speter int prescan; 169518334Speter{ 169690087Sobrien rtx insn; 169718334Speter int max_line = 0; 169850503Sobrien int max_uid = 0; 169918334Speter 170018334Speter last_ignored_compare = 0; 170118334Speter new_block = 1; 170218334Speter 170318334Speter /* Make a map indicating which line numbers appear in this function. 170418334Speter When producing SDB debugging info, delete troublesome line number 170518334Speter notes from inlined functions in other files as well as duplicate 170618334Speter line number notes. */ 170718334Speter#ifdef SDB_DEBUGGING_INFO 170818334Speter if (write_symbols == SDB_DEBUG) 170918334Speter { 171018334Speter rtx last = 0; 171118334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 171218334Speter if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) 171318334Speter { 171418334Speter if ((RTX_INTEGRATED_P (insn) 171518334Speter && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0) 171618334Speter || (last != 0 171718334Speter && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last) 171818334Speter && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last))) 171918334Speter { 172090087Sobrien delete_insn (insn); /* Use delete_note. */ 172118334Speter continue; 172218334Speter } 172318334Speter last = insn; 172418334Speter if (NOTE_LINE_NUMBER (insn) > max_line) 172518334Speter max_line = NOTE_LINE_NUMBER (insn); 172618334Speter } 172718334Speter } 172818334Speter else 172918334Speter#endif 173018334Speter { 173118334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 173218334Speter if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > max_line) 173318334Speter max_line = NOTE_LINE_NUMBER (insn); 173418334Speter } 173518334Speter 173690087Sobrien line_note_exists = (char *) xcalloc (max_line + 1, sizeof (char)); 173718334Speter 173818334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 173950503Sobrien { 174050503Sobrien if (INSN_UID (insn) > max_uid) /* find largest UID */ 174190087Sobrien max_uid = INSN_UID (insn); 174250503Sobrien if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) 174390087Sobrien line_note_exists[NOTE_LINE_NUMBER (insn)] = 1; 174452515Sobrien#ifdef HAVE_cc0 174552515Sobrien /* If CC tracking across branches is enabled, record the insn which 174652515Sobrien jumps to each branch only reached from one place. */ 174752515Sobrien if (optimize && GET_CODE (insn) == JUMP_INSN) 174852515Sobrien { 174952515Sobrien rtx lab = JUMP_LABEL (insn); 175052515Sobrien if (lab && LABEL_NUSES (lab) == 1) 175152515Sobrien { 175252515Sobrien LABEL_REFS (lab) = insn; 175352515Sobrien } 175452515Sobrien } 175552515Sobrien#endif 175650503Sobrien } 175718334Speter 175818334Speter init_recog (); 175918334Speter 176018334Speter CC_STATUS_INIT; 176118334Speter 176218334Speter /* Output the insns. */ 176318334Speter for (insn = NEXT_INSN (first); insn;) 176450503Sobrien { 176550503Sobrien#ifdef HAVE_ATTR_length 176690087Sobrien if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ()) 176790087Sobrien { 176890087Sobrien#ifdef STACK_REGS 176990087Sobrien /* Irritatingly, the reg-stack pass is creating new instructions 177090087Sobrien and because of REG_DEAD note abuse it has to run after 177190087Sobrien shorten_branches. Fake address of -1 then. */ 177290087Sobrien insn_current_address = -1; 177390087Sobrien#else 177490087Sobrien /* This can be triggered by bugs elsewhere in the compiler if 177590087Sobrien new insns are created after init_insn_lengths is called. */ 177690087Sobrien abort (); 177750503Sobrien#endif 177890087Sobrien } 177990087Sobrien else 178090087Sobrien insn_current_address = INSN_ADDRESSES (INSN_UID (insn)); 178190087Sobrien#endif /* HAVE_ATTR_length */ 178290087Sobrien 178350503Sobrien insn = final_scan_insn (insn, file, optimize, prescan, 0); 178450503Sobrien } 178518334Speter 178690087Sobrien free (line_note_exists); 178790087Sobrien line_note_exists = NULL; 178890087Sobrien} 178990087Sobrien 179090087Sobrienconst char * 179190087Sobrienget_insn_template (code, insn) 179290087Sobrien int code; 179390087Sobrien rtx insn; 179490087Sobrien{ 179590087Sobrien const void *output = insn_data[code].output; 179690087Sobrien switch (insn_data[code].output_format) 179790087Sobrien { 179890087Sobrien case INSN_OUTPUT_FORMAT_SINGLE: 179990087Sobrien return (const char *) output; 180090087Sobrien case INSN_OUTPUT_FORMAT_MULTI: 180190087Sobrien return ((const char *const *) output)[which_alternative]; 180290087Sobrien case INSN_OUTPUT_FORMAT_FUNCTION: 180390087Sobrien if (insn == NULL) 180490087Sobrien abort (); 180590087Sobrien return (*(insn_output_fn) output) (recog_data.operand, insn); 180650503Sobrien 180790087Sobrien default: 180890087Sobrien abort (); 180990087Sobrien } 181018334Speter} 181190087Sobrien 181218334Speter/* The final scan for one insn, INSN. 181318334Speter Args are same as in `final', except that INSN 181418334Speter is the insn being scanned. 181518334Speter Value returned is the next insn to be scanned. 181618334Speter 181718334Speter NOPEEPHOLES is the flag to disallow peephole processing (currently 181818334Speter used for within delayed branch sequence output). */ 181918334Speter 182018334Speterrtx 182118334Speterfinal_scan_insn (insn, file, optimize, prescan, nopeepholes) 182218334Speter rtx insn; 182318334Speter FILE *file; 182490087Sobrien int optimize ATTRIBUTE_UNUSED; 182518334Speter int prescan; 182690087Sobrien int nopeepholes ATTRIBUTE_UNUSED; 182718334Speter{ 182850503Sobrien#ifdef HAVE_cc0 182950503Sobrien rtx set; 183050503Sobrien#endif 183150503Sobrien 183218334Speter insn_counter++; 183318334Speter 183418334Speter /* Ignore deleted insns. These can occur when we split insns (due to a 183518334Speter template of "#") while not optimizing. */ 183618334Speter if (INSN_DELETED_P (insn)) 183718334Speter return NEXT_INSN (insn); 183818334Speter 183918334Speter switch (GET_CODE (insn)) 184018334Speter { 184118334Speter case NOTE: 184218334Speter if (prescan > 0) 184318334Speter break; 184418334Speter 184590087Sobrien switch (NOTE_LINE_NUMBER (insn)) 184618334Speter { 184790087Sobrien case NOTE_INSN_DELETED: 184890087Sobrien case NOTE_INSN_LOOP_BEG: 184990087Sobrien case NOTE_INSN_LOOP_END: 185096281Sobrien case NOTE_INSN_LOOP_END_TOP_COND: 185190087Sobrien case NOTE_INSN_LOOP_CONT: 185290087Sobrien case NOTE_INSN_LOOP_VTOP: 185390087Sobrien case NOTE_INSN_FUNCTION_END: 185490087Sobrien case NOTE_INSN_REPEATED_LINE_NUMBER: 185590087Sobrien case NOTE_INSN_RANGE_BEG: 185690087Sobrien case NOTE_INSN_RANGE_END: 185790087Sobrien case NOTE_INSN_LIVE: 185890087Sobrien case NOTE_INSN_EXPECTED_VALUE: 185918334Speter break; 186018334Speter 186190087Sobrien case NOTE_INSN_BASIC_BLOCK: 186290087Sobrien#ifdef IA64_UNWIND_INFO 186390087Sobrien IA64_UNWIND_EMIT (asm_out_file, insn); 186450503Sobrien#endif 186590087Sobrien if (flag_debug_asm) 186690087Sobrien fprintf (asm_out_file, "\t%s basic block %d\n", 186790087Sobrien ASM_COMMENT_START, NOTE_BASIC_BLOCK (insn)->index); 186850503Sobrien break; 186950503Sobrien 187090087Sobrien case NOTE_INSN_EH_REGION_BEG: 187190087Sobrien ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHB", 187290087Sobrien NOTE_EH_HANDLER (insn)); 187390087Sobrien break; 187490087Sobrien 187590087Sobrien case NOTE_INSN_EH_REGION_END: 187690087Sobrien ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHE", 187790087Sobrien NOTE_EH_HANDLER (insn)); 187890087Sobrien break; 187990087Sobrien 188090087Sobrien case NOTE_INSN_PROLOGUE_END: 188190087Sobrien (*targetm.asm_out.function_end_prologue) (file); 188218334Speter profile_after_prologue (file); 188318334Speter break; 188418334Speter 188590087Sobrien case NOTE_INSN_EPILOGUE_BEG: 188690087Sobrien (*targetm.asm_out.function_begin_epilogue) (file); 188718334Speter break; 188818334Speter 188990087Sobrien case NOTE_INSN_FUNCTION_BEG: 189090087Sobrien app_disable (); 189190087Sobrien (*debug_hooks->end_prologue) (last_linenum); 189218334Speter break; 189390087Sobrien 189490087Sobrien case NOTE_INSN_BLOCK_BEG: 189590087Sobrien if (debug_info_level == DINFO_LEVEL_NORMAL 189618334Speter || debug_info_level == DINFO_LEVEL_VERBOSE 189718334Speter || write_symbols == DWARF_DEBUG 189890087Sobrien || write_symbols == DWARF2_DEBUG 189990087Sobrien || write_symbols == VMS_AND_DWARF2_DEBUG 190090087Sobrien || write_symbols == VMS_DEBUG) 190190087Sobrien { 190290087Sobrien int n = BLOCK_NUMBER (NOTE_BLOCK (insn)); 190318334Speter 190490087Sobrien app_disable (); 190590087Sobrien ++block_depth; 190690087Sobrien high_block_linenum = last_linenum; 190790087Sobrien 190890087Sobrien /* Output debugging info about the symbol-block beginning. */ 190990087Sobrien (*debug_hooks->begin_block) (last_linenum, n); 191090087Sobrien 191190087Sobrien /* Mark this block as output. */ 191290087Sobrien TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1; 191318334Speter } 191490087Sobrien break; 191518334Speter 191690087Sobrien case NOTE_INSN_BLOCK_END: 191790087Sobrien if (debug_info_level == DINFO_LEVEL_NORMAL 191890087Sobrien || debug_info_level == DINFO_LEVEL_VERBOSE 191990087Sobrien || write_symbols == DWARF_DEBUG 192090087Sobrien || write_symbols == DWARF2_DEBUG 192190087Sobrien || write_symbols == VMS_AND_DWARF2_DEBUG 192290087Sobrien || write_symbols == VMS_DEBUG) 192390087Sobrien { 192490087Sobrien int n = BLOCK_NUMBER (NOTE_BLOCK (insn)); 192518334Speter 192690087Sobrien app_disable (); 192718334Speter 192890087Sobrien /* End of a symbol-block. */ 192990087Sobrien --block_depth; 193090087Sobrien if (block_depth < 0) 193190087Sobrien abort (); 193218334Speter 193390087Sobrien (*debug_hooks->end_block) (high_block_linenum, n); 193490087Sobrien } 193590087Sobrien break; 193618334Speter 193790087Sobrien case NOTE_INSN_DELETED_LABEL: 193890087Sobrien /* Emit the label. We may have deleted the CODE_LABEL because 193990087Sobrien the label could be proved to be unreachable, though still 194090087Sobrien referenced (in the form of having its address taken. */ 194190087Sobrien ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); 194290087Sobrien break; 194318334Speter 194490087Sobrien case 0: 194590087Sobrien break; 194618334Speter 194790087Sobrien default: 194890087Sobrien if (NOTE_LINE_NUMBER (insn) <= 0) 194990087Sobrien abort (); 195018334Speter 195190087Sobrien /* This note is a line-number. */ 195290087Sobrien { 195390087Sobrien rtx note; 195490087Sobrien int note_after = 0; 195518334Speter 195690087Sobrien /* If there is anything real after this note, output it. 195790087Sobrien If another line note follows, omit this one. */ 195890087Sobrien for (note = NEXT_INSN (insn); note; note = NEXT_INSN (note)) 195990087Sobrien { 196090087Sobrien if (GET_CODE (note) != NOTE && GET_CODE (note) != CODE_LABEL) 196118334Speter break; 196218334Speter 196390087Sobrien /* These types of notes can be significant 196490087Sobrien so make sure the preceding line number stays. */ 196590087Sobrien else if (GET_CODE (note) == NOTE 196690087Sobrien && (NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_BEG 196790087Sobrien || NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_END 196890087Sobrien || NOTE_LINE_NUMBER (note) == NOTE_INSN_FUNCTION_BEG)) 196990087Sobrien break; 197090087Sobrien else if (GET_CODE (note) == NOTE && NOTE_LINE_NUMBER (note) > 0) 197190087Sobrien { 197290087Sobrien /* Another line note follows; we can delete this note 197390087Sobrien if no intervening line numbers have notes elsewhere. */ 197490087Sobrien int num; 197590087Sobrien for (num = NOTE_LINE_NUMBER (insn) + 1; 197690087Sobrien num < NOTE_LINE_NUMBER (note); 197790087Sobrien num++) 197890087Sobrien if (line_note_exists[num]) 197990087Sobrien break; 198090087Sobrien 198190087Sobrien if (num >= NOTE_LINE_NUMBER (note)) 198290087Sobrien note_after = 1; 198390087Sobrien break; 198490087Sobrien } 198590087Sobrien } 198690087Sobrien 198790087Sobrien /* Output this line note if it is the first or the last line 198890087Sobrien note in a row. */ 198990087Sobrien if (!note_after) 199090087Sobrien { 199190087Sobrien notice_source_line (insn); 199290087Sobrien (*debug_hooks->source_line) (last_linenum, last_filename); 199390087Sobrien } 199490087Sobrien } 199590087Sobrien break; 199618334Speter } 199718334Speter break; 199818334Speter 199918334Speter case BARRIER: 200090087Sobrien#if defined (DWARF2_UNWIND_INFO) 200190087Sobrien if (dwarf2out_do_frame ()) 200290087Sobrien dwarf2out_frame_debug (insn); 200318334Speter#endif 200418334Speter break; 200518334Speter 200618334Speter case CODE_LABEL: 200750503Sobrien /* The target port might emit labels in the output function for 200850503Sobrien some insn, e.g. sh.c output_branchy_insn. */ 200950503Sobrien if (CODE_LABEL_NUMBER (insn) <= max_labelno) 201050503Sobrien { 201150503Sobrien int align = LABEL_TO_ALIGNMENT (insn); 201250503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN 201350503Sobrien int max_skip = LABEL_TO_MAX_SKIP (insn); 201450503Sobrien#endif 201550503Sobrien 201650503Sobrien if (align && NEXT_INSN (insn)) 201790087Sobrien { 201850503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN 201990087Sobrien ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip); 202050503Sobrien#else 202190087Sobrien ASM_OUTPUT_ALIGN (file, align); 202250503Sobrien#endif 202390087Sobrien } 202450503Sobrien } 202552515Sobrien#ifdef HAVE_cc0 202618334Speter CC_STATUS_INIT; 202752515Sobrien /* If this label is reached from only one place, set the condition 202852515Sobrien codes from the instruction just before the branch. */ 202952515Sobrien 203052515Sobrien /* Disabled because some insns set cc_status in the C output code 203152515Sobrien and NOTICE_UPDATE_CC alone can set incorrect status. */ 203252515Sobrien if (0 /* optimize && LABEL_NUSES (insn) == 1*/) 203352515Sobrien { 203452515Sobrien rtx jump = LABEL_REFS (insn); 203552515Sobrien rtx barrier = prev_nonnote_insn (insn); 203652515Sobrien rtx prev; 203752515Sobrien /* If the LABEL_REFS field of this label has been set to point 203852515Sobrien at a branch, the predecessor of the branch is a regular 203952515Sobrien insn, and that branch is the only way to reach this label, 204052515Sobrien set the condition codes based on the branch and its 204152515Sobrien predecessor. */ 204252515Sobrien if (barrier && GET_CODE (barrier) == BARRIER 204352515Sobrien && jump && GET_CODE (jump) == JUMP_INSN 204452515Sobrien && (prev = prev_nonnote_insn (jump)) 204552515Sobrien && GET_CODE (prev) == INSN) 204652515Sobrien { 204752515Sobrien NOTICE_UPDATE_CC (PATTERN (prev), prev); 204852515Sobrien NOTICE_UPDATE_CC (PATTERN (jump), jump); 204952515Sobrien } 205052515Sobrien } 205152515Sobrien#endif 205218334Speter if (prescan > 0) 205318334Speter break; 205418334Speter new_block = 1; 205550503Sobrien 205650503Sobrien#ifdef FINAL_PRESCAN_LABEL 205790087Sobrien FINAL_PRESCAN_INSN (insn, NULL, 0); 205850503Sobrien#endif 205950503Sobrien 206090087Sobrien if (LABEL_NAME (insn)) 206190087Sobrien (*debug_hooks->label) (insn); 206290087Sobrien 206318334Speter if (app_on) 206418334Speter { 206550503Sobrien fputs (ASM_APP_OFF, file); 206618334Speter app_on = 0; 206718334Speter } 206818334Speter if (NEXT_INSN (insn) != 0 206918334Speter && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN) 207018334Speter { 207118334Speter rtx nextbody = PATTERN (NEXT_INSN (insn)); 207218334Speter 207318334Speter /* If this label is followed by a jump-table, 207418334Speter make sure we put the label in the read-only section. Also 207518334Speter possibly write the label and jump table together. */ 207618334Speter 207718334Speter if (GET_CODE (nextbody) == ADDR_VEC 207818334Speter || GET_CODE (nextbody) == ADDR_DIFF_VEC) 207918334Speter { 208052515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC) 208152515Sobrien /* In this case, the case vector is being moved by the 208252515Sobrien target, so don't output the label at all. Leave that 208352515Sobrien to the back end macros. */ 208452515Sobrien#else 208550503Sobrien if (! JUMP_TABLES_IN_TEXT_SECTION) 208650503Sobrien { 208790087Sobrien int log_align; 208890087Sobrien 208950503Sobrien readonly_data_section (); 209090087Sobrien 209190087Sobrien#ifdef ADDR_VEC_ALIGN 209290087Sobrien log_align = ADDR_VEC_ALIGN (NEXT_INSN (insn)); 209390087Sobrien#else 209490087Sobrien log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT); 209590087Sobrien#endif 209690087Sobrien ASM_OUTPUT_ALIGN (file, log_align); 209750503Sobrien } 209850503Sobrien else 209950503Sobrien function_section (current_function_decl); 210050503Sobrien 210118334Speter#ifdef ASM_OUTPUT_CASE_LABEL 210218334Speter ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), 210318334Speter NEXT_INSN (insn)); 210418334Speter#else 210590087Sobrien if (LABEL_ALTERNATE_NAME (insn)) 210690087Sobrien ASM_OUTPUT_ALTERNATE_LABEL_NAME (file, insn); 210790087Sobrien else 210890087Sobrien ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); 210918334Speter#endif 211052515Sobrien#endif 211118334Speter break; 211218334Speter } 211318334Speter } 211490087Sobrien if (LABEL_ALTERNATE_NAME (insn)) 211590087Sobrien ASM_OUTPUT_ALTERNATE_LABEL_NAME (file, insn); 211690087Sobrien else 211790087Sobrien ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); 211818334Speter break; 211918334Speter 212018334Speter default: 212118334Speter { 212290087Sobrien rtx body = PATTERN (insn); 212318334Speter int insn_code_number; 212452515Sobrien const char *template; 212518334Speter rtx note; 212618334Speter 212718334Speter /* An INSN, JUMP_INSN or CALL_INSN. 212818334Speter First check for special kinds that recog doesn't recognize. */ 212918334Speter 213018334Speter if (GET_CODE (body) == USE /* These are just declarations */ 213118334Speter || GET_CODE (body) == CLOBBER) 213218334Speter break; 213318334Speter 213418334Speter#ifdef HAVE_cc0 213518334Speter /* If there is a REG_CC_SETTER note on this insn, it means that 213618334Speter the setting of the condition code was done in the delay slot 213718334Speter of the insn that branched here. So recover the cc status 213818334Speter from the insn that set it. */ 213918334Speter 214018334Speter note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX); 214118334Speter if (note) 214218334Speter { 214318334Speter NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0)); 214418334Speter cc_prev_status = cc_status; 214518334Speter } 214618334Speter#endif 214718334Speter 214818334Speter /* Detect insns that are really jump-tables 214918334Speter and output them as such. */ 215018334Speter 215118334Speter if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) 215218334Speter { 215352515Sobrien#if !(defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)) 215490087Sobrien int vlen, idx; 215552515Sobrien#endif 215618334Speter 215718334Speter if (prescan > 0) 215818334Speter break; 215918334Speter 216018334Speter if (app_on) 216118334Speter { 216250503Sobrien fputs (ASM_APP_OFF, file); 216318334Speter app_on = 0; 216418334Speter } 216518334Speter 216652515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC) 216752515Sobrien if (GET_CODE (body) == ADDR_VEC) 216852515Sobrien { 216952515Sobrien#ifdef ASM_OUTPUT_ADDR_VEC 217052515Sobrien ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body); 217152515Sobrien#else 217290087Sobrien abort (); 217352515Sobrien#endif 217452515Sobrien } 217552515Sobrien else 217652515Sobrien { 217752515Sobrien#ifdef ASM_OUTPUT_ADDR_DIFF_VEC 217852515Sobrien ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body); 217952515Sobrien#else 218090087Sobrien abort (); 218152515Sobrien#endif 218252515Sobrien } 218352515Sobrien#else 218418334Speter vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC); 218518334Speter for (idx = 0; idx < vlen; idx++) 218618334Speter { 218718334Speter if (GET_CODE (body) == ADDR_VEC) 218818334Speter { 218918334Speter#ifdef ASM_OUTPUT_ADDR_VEC_ELT 219018334Speter ASM_OUTPUT_ADDR_VEC_ELT 219118334Speter (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0))); 219218334Speter#else 219318334Speter abort (); 219418334Speter#endif 219518334Speter } 219618334Speter else 219718334Speter { 219818334Speter#ifdef ASM_OUTPUT_ADDR_DIFF_ELT 219918334Speter ASM_OUTPUT_ADDR_DIFF_ELT 220018334Speter (file, 220150503Sobrien body, 220218334Speter CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)), 220318334Speter CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0))); 220418334Speter#else 220518334Speter abort (); 220618334Speter#endif 220718334Speter } 220818334Speter } 220918334Speter#ifdef ASM_OUTPUT_CASE_END 221018334Speter ASM_OUTPUT_CASE_END (file, 221118334Speter CODE_LABEL_NUMBER (PREV_INSN (insn)), 221218334Speter insn); 221318334Speter#endif 221452515Sobrien#endif 221518334Speter 221618334Speter function_section (current_function_decl); 221718334Speter 221818334Speter break; 221918334Speter } 222018334Speter 222118334Speter if (GET_CODE (body) == ASM_INPUT) 222218334Speter { 222390087Sobrien const char *string = XSTR (body, 0); 222490087Sobrien 222518334Speter /* There's no telling what that did to the condition codes. */ 222618334Speter CC_STATUS_INIT; 222718334Speter if (prescan > 0) 222818334Speter break; 222990087Sobrien 223090087Sobrien if (string[0]) 223118334Speter { 223290087Sobrien if (! app_on) 223390087Sobrien { 223490087Sobrien fputs (ASM_APP_ON, file); 223590087Sobrien app_on = 1; 223690087Sobrien } 223790087Sobrien fprintf (asm_out_file, "\t%s\n", string); 223818334Speter } 223918334Speter break; 224018334Speter } 224118334Speter 224218334Speter /* Detect `asm' construct with operands. */ 224318334Speter if (asm_noperands (body) >= 0) 224418334Speter { 224550503Sobrien unsigned int noperands = asm_noperands (body); 224618334Speter rtx *ops = (rtx *) alloca (noperands * sizeof (rtx)); 224790087Sobrien const char *string; 224818334Speter 224918334Speter /* There's no telling what that did to the condition codes. */ 225018334Speter CC_STATUS_INIT; 225118334Speter if (prescan > 0) 225218334Speter break; 225318334Speter 225418334Speter /* Get out the operand values. */ 225590087Sobrien string = decode_asm_operands (body, ops, NULL, NULL, NULL); 225618334Speter /* Inhibit aborts on what would otherwise be compiler bugs. */ 225718334Speter insn_noperands = noperands; 225818334Speter this_is_asm_operands = insn; 225918334Speter 226018334Speter /* Output the insn using them. */ 226190087Sobrien if (string[0]) 226290087Sobrien { 226390087Sobrien if (! app_on) 226490087Sobrien { 226590087Sobrien fputs (ASM_APP_ON, file); 226690087Sobrien app_on = 1; 226790087Sobrien } 226890087Sobrien output_asm_insn (string, ops); 226990087Sobrien } 227090087Sobrien 227118334Speter this_is_asm_operands = 0; 227218334Speter break; 227318334Speter } 227418334Speter 227518334Speter if (prescan <= 0 && app_on) 227618334Speter { 227750503Sobrien fputs (ASM_APP_OFF, file); 227818334Speter app_on = 0; 227918334Speter } 228018334Speter 228118334Speter if (GET_CODE (body) == SEQUENCE) 228218334Speter { 228318334Speter /* A delayed-branch sequence */ 228490087Sobrien int i; 228518334Speter rtx next; 228618334Speter 228718334Speter if (prescan > 0) 228818334Speter break; 228918334Speter final_sequence = body; 229018334Speter 229118334Speter /* The first insn in this SEQUENCE might be a JUMP_INSN that will 229218334Speter force the restoration of a comparison that was previously 229318334Speter thought unnecessary. If that happens, cancel this sequence 229418334Speter and cause that insn to be restored. */ 229518334Speter 229618334Speter next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1); 229718334Speter if (next != XVECEXP (body, 0, 1)) 229818334Speter { 229918334Speter final_sequence = 0; 230018334Speter return next; 230118334Speter } 230218334Speter 230318334Speter for (i = 1; i < XVECLEN (body, 0); i++) 230418334Speter { 230518334Speter rtx insn = XVECEXP (body, 0, i); 230618334Speter rtx next = NEXT_INSN (insn); 230718334Speter /* We loop in case any instruction in a delay slot gets 230818334Speter split. */ 230918334Speter do 231018334Speter insn = final_scan_insn (insn, file, 0, prescan, 1); 231118334Speter while (insn != next); 231218334Speter } 231318334Speter#ifdef DBR_OUTPUT_SEQEND 231418334Speter DBR_OUTPUT_SEQEND (file); 231518334Speter#endif 231618334Speter final_sequence = 0; 231718334Speter 231818334Speter /* If the insn requiring the delay slot was a CALL_INSN, the 231918334Speter insns in the delay slot are actually executed before the 232018334Speter called function. Hence we don't preserve any CC-setting 232118334Speter actions in these insns and the CC must be marked as being 232218334Speter clobbered by the function. */ 232318334Speter if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN) 232450503Sobrien { 232550503Sobrien CC_STATUS_INIT; 232650503Sobrien } 232718334Speter break; 232818334Speter } 232918334Speter 233018334Speter /* We have a real machine instruction as rtl. */ 233118334Speter 233218334Speter body = PATTERN (insn); 233318334Speter 233418334Speter#ifdef HAVE_cc0 233590087Sobrien set = single_set (insn); 233650503Sobrien 233718334Speter /* Check for redundant test and compare instructions 233818334Speter (when the condition codes are already set up as desired). 233918334Speter This is done only when optimizing; if not optimizing, 234018334Speter it should be possible for the user to alter a variable 234118334Speter with the debugger in between statements 234218334Speter and the next statement should reexamine the variable 234318334Speter to compute the condition codes. */ 234418334Speter 234550503Sobrien if (optimize) 234618334Speter { 234750503Sobrien#if 0 234890087Sobrien rtx set = single_set (insn); 234950503Sobrien#endif 235050503Sobrien 235150503Sobrien if (set 235250503Sobrien && GET_CODE (SET_DEST (set)) == CC0 235350503Sobrien && insn != last_ignored_compare) 235418334Speter { 235550503Sobrien if (GET_CODE (SET_SRC (set)) == SUBREG) 235690087Sobrien SET_SRC (set) = alter_subreg (&SET_SRC (set)); 235750503Sobrien else if (GET_CODE (SET_SRC (set)) == COMPARE) 235818334Speter { 235950503Sobrien if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG) 236050503Sobrien XEXP (SET_SRC (set), 0) 236190087Sobrien = alter_subreg (&XEXP (SET_SRC (set), 0)); 236250503Sobrien if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG) 236350503Sobrien XEXP (SET_SRC (set), 1) 236490087Sobrien = alter_subreg (&XEXP (SET_SRC (set), 1)); 236518334Speter } 236650503Sobrien if ((cc_status.value1 != 0 236750503Sobrien && rtx_equal_p (SET_SRC (set), cc_status.value1)) 236850503Sobrien || (cc_status.value2 != 0 236950503Sobrien && rtx_equal_p (SET_SRC (set), cc_status.value2))) 237050503Sobrien { 237150503Sobrien /* Don't delete insn if it has an addressing side-effect. */ 237290087Sobrien if (! FIND_REG_INC_NOTE (insn, NULL_RTX) 237350503Sobrien /* or if anything in it is volatile. */ 237450503Sobrien && ! volatile_refs_p (PATTERN (insn))) 237550503Sobrien { 237650503Sobrien /* We don't really delete the insn; just ignore it. */ 237750503Sobrien last_ignored_compare = insn; 237850503Sobrien break; 237950503Sobrien } 238050503Sobrien } 238118334Speter } 238218334Speter } 238318334Speter#endif 238418334Speter 238518334Speter#ifndef STACK_REGS 238618334Speter /* Don't bother outputting obvious no-ops, even without -O. 238718334Speter This optimization is fast and doesn't interfere with debugging. 238818334Speter Don't do this if the insn is in a delay slot, since this 238918334Speter will cause an improper number of delay insns to be written. */ 239018334Speter if (final_sequence == 0 239118334Speter && prescan >= 0 239218334Speter && GET_CODE (insn) == INSN && GET_CODE (body) == SET 239318334Speter && GET_CODE (SET_SRC (body)) == REG 239418334Speter && GET_CODE (SET_DEST (body)) == REG 239518334Speter && REGNO (SET_SRC (body)) == REGNO (SET_DEST (body))) 239618334Speter break; 239718334Speter#endif 239818334Speter 239918334Speter#ifdef HAVE_cc0 240018334Speter /* If this is a conditional branch, maybe modify it 240118334Speter if the cc's are in a nonstandard state 240218334Speter so that it accomplishes the same thing that it would 240318334Speter do straightforwardly if the cc's were set up normally. */ 240418334Speter 240518334Speter if (cc_status.flags != 0 240618334Speter && GET_CODE (insn) == JUMP_INSN 240718334Speter && GET_CODE (body) == SET 240818334Speter && SET_DEST (body) == pc_rtx 240918334Speter && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE 241018334Speter && GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (body), 0))) == '<' 241118334Speter && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx 241218334Speter /* This is done during prescan; it is not done again 241318334Speter in final scan when prescan has been done. */ 241418334Speter && prescan >= 0) 241518334Speter { 241618334Speter /* This function may alter the contents of its argument 241718334Speter and clear some of the cc_status.flags bits. 241818334Speter It may also return 1 meaning condition now always true 241918334Speter or -1 meaning condition now always false 242018334Speter or 2 meaning condition nontrivial but altered. */ 242190087Sobrien int result = alter_cond (XEXP (SET_SRC (body), 0)); 242218334Speter /* If condition now has fixed value, replace the IF_THEN_ELSE 242318334Speter with its then-operand or its else-operand. */ 242418334Speter if (result == 1) 242518334Speter SET_SRC (body) = XEXP (SET_SRC (body), 1); 242618334Speter if (result == -1) 242718334Speter SET_SRC (body) = XEXP (SET_SRC (body), 2); 242818334Speter 242918334Speter /* The jump is now either unconditional or a no-op. 243018334Speter If it has become a no-op, don't try to output it. 243118334Speter (It would not be recognized.) */ 243218334Speter if (SET_SRC (body) == pc_rtx) 243318334Speter { 243490087Sobrien delete_insn (insn); 243518334Speter break; 243618334Speter } 243718334Speter else if (GET_CODE (SET_SRC (body)) == RETURN) 243818334Speter /* Replace (set (pc) (return)) with (return). */ 243918334Speter PATTERN (insn) = body = SET_SRC (body); 244018334Speter 244118334Speter /* Rerecognize the instruction if it has changed. */ 244218334Speter if (result != 0) 244318334Speter INSN_CODE (insn) = -1; 244418334Speter } 244518334Speter 244618334Speter /* Make same adjustments to instructions that examine the 244750503Sobrien condition codes without jumping and instructions that 244850503Sobrien handle conditional moves (if this machine has either one). */ 244918334Speter 245018334Speter if (cc_status.flags != 0 245150503Sobrien && set != 0) 245218334Speter { 245350503Sobrien rtx cond_rtx, then_rtx, else_rtx; 245490087Sobrien 245550503Sobrien if (GET_CODE (insn) != JUMP_INSN 245650503Sobrien && GET_CODE (SET_SRC (set)) == IF_THEN_ELSE) 245718334Speter { 245850503Sobrien cond_rtx = XEXP (SET_SRC (set), 0); 245950503Sobrien then_rtx = XEXP (SET_SRC (set), 1); 246050503Sobrien else_rtx = XEXP (SET_SRC (set), 2); 246150503Sobrien } 246250503Sobrien else 246350503Sobrien { 246450503Sobrien cond_rtx = SET_SRC (set); 246550503Sobrien then_rtx = const_true_rtx; 246650503Sobrien else_rtx = const0_rtx; 246750503Sobrien } 246890087Sobrien 246950503Sobrien switch (GET_CODE (cond_rtx)) 247050503Sobrien { 247118334Speter case GTU: 247218334Speter case GT: 247318334Speter case LTU: 247418334Speter case LT: 247518334Speter case GEU: 247618334Speter case GE: 247718334Speter case LEU: 247818334Speter case LE: 247918334Speter case EQ: 248018334Speter case NE: 248118334Speter { 248290087Sobrien int result; 248350503Sobrien if (XEXP (cond_rtx, 0) != cc0_rtx) 248418334Speter break; 248550503Sobrien result = alter_cond (cond_rtx); 248618334Speter if (result == 1) 248750503Sobrien validate_change (insn, &SET_SRC (set), then_rtx, 0); 248818334Speter else if (result == -1) 248950503Sobrien validate_change (insn, &SET_SRC (set), else_rtx, 0); 249018334Speter else if (result == 2) 249118334Speter INSN_CODE (insn) = -1; 249250503Sobrien if (SET_DEST (set) == SET_SRC (set)) 249390087Sobrien delete_insn (insn); 249418334Speter } 249550503Sobrien break; 249650503Sobrien 249750503Sobrien default: 249850503Sobrien break; 249918334Speter } 250018334Speter } 250150503Sobrien 250218334Speter#endif 250318334Speter 250490087Sobrien#ifdef HAVE_peephole 250518334Speter /* Do machine-specific peephole optimizations if desired. */ 250618334Speter 250718334Speter if (optimize && !flag_no_peephole && !nopeepholes) 250818334Speter { 250918334Speter rtx next = peephole (insn); 251018334Speter /* When peepholing, if there were notes within the peephole, 251118334Speter emit them before the peephole. */ 251218334Speter if (next != 0 && next != NEXT_INSN (insn)) 251318334Speter { 251418334Speter rtx prev = PREV_INSN (insn); 251518334Speter 251618334Speter for (note = NEXT_INSN (insn); note != next; 251718334Speter note = NEXT_INSN (note)) 251818334Speter final_scan_insn (note, file, optimize, prescan, nopeepholes); 251918334Speter 252018334Speter /* In case this is prescan, put the notes 252118334Speter in proper position for later rescan. */ 252218334Speter note = NEXT_INSN (insn); 252318334Speter PREV_INSN (note) = prev; 252418334Speter NEXT_INSN (prev) = note; 252518334Speter NEXT_INSN (PREV_INSN (next)) = insn; 252618334Speter PREV_INSN (insn) = PREV_INSN (next); 252718334Speter NEXT_INSN (insn) = next; 252818334Speter PREV_INSN (next) = insn; 252918334Speter } 253018334Speter 253118334Speter /* PEEPHOLE might have changed this. */ 253218334Speter body = PATTERN (insn); 253318334Speter } 253490087Sobrien#endif 253518334Speter 253618334Speter /* Try to recognize the instruction. 253718334Speter If successful, verify that the operands satisfy the 253818334Speter constraints for the instruction. Crash if they don't, 253918334Speter since `reload' should have changed them so that they do. */ 254018334Speter 254118334Speter insn_code_number = recog_memoized (insn); 254252515Sobrien cleanup_subreg_operands (insn); 254318334Speter 254490087Sobrien /* Dump the insn in the assembly for debugging. */ 254590087Sobrien if (flag_dump_rtl_in_asm) 254690087Sobrien { 254790087Sobrien print_rtx_head = ASM_COMMENT_START; 254890087Sobrien print_rtl_single (asm_out_file, insn); 254990087Sobrien print_rtx_head = ""; 255090087Sobrien } 255190087Sobrien 255290087Sobrien if (! constrain_operands_cached (1)) 255318334Speter fatal_insn_not_found (insn); 255418334Speter 255518334Speter /* Some target machines need to prescan each insn before 255618334Speter it is output. */ 255718334Speter 255818334Speter#ifdef FINAL_PRESCAN_INSN 255990087Sobrien FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands); 256018334Speter#endif 256118334Speter 256290087Sobrien#ifdef HAVE_conditional_execution 256390087Sobrien if (GET_CODE (PATTERN (insn)) == COND_EXEC) 256490087Sobrien current_insn_predicate = COND_EXEC_TEST (PATTERN (insn)); 256590087Sobrien else 256690087Sobrien current_insn_predicate = NULL_RTX; 256790087Sobrien#endif 256890087Sobrien 256918334Speter#ifdef HAVE_cc0 257018334Speter cc_prev_status = cc_status; 257118334Speter 257218334Speter /* Update `cc_status' for this instruction. 257318334Speter The instruction's output routine may change it further. 257418334Speter If the output routine for a jump insn needs to depend 257518334Speter on the cc status, it should look at cc_prev_status. */ 257618334Speter 257718334Speter NOTICE_UPDATE_CC (body, insn); 257818334Speter#endif 257918334Speter 258090087Sobrien current_output_insn = debug_insn = insn; 258118334Speter 258290087Sobrien#if defined (DWARF2_UNWIND_INFO) 258350503Sobrien if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ()) 258450503Sobrien dwarf2out_frame_debug (insn); 258550503Sobrien#endif 258650503Sobrien 258790087Sobrien /* Find the proper template for this insn. */ 258890087Sobrien template = get_insn_template (insn_code_number, insn); 258918334Speter 259090087Sobrien /* If the C code returns 0, it means that it is a jump insn 259190087Sobrien which follows a deleted test insn, and that test insn 259290087Sobrien needs to be reinserted. */ 259318334Speter if (template == 0) 259418334Speter { 259590087Sobrien rtx prev; 259618334Speter 259790087Sobrien if (prev_nonnote_insn (insn) != last_ignored_compare) 259890087Sobrien abort (); 259990087Sobrien new_block = 0; 260090087Sobrien 260190087Sobrien /* We have already processed the notes between the setter and 260290087Sobrien the user. Make sure we don't process them again, this is 260390087Sobrien particularly important if one of the notes is a block 260490087Sobrien scope note or an EH note. */ 260590087Sobrien for (prev = insn; 260690087Sobrien prev != last_ignored_compare; 260790087Sobrien prev = PREV_INSN (prev)) 260818334Speter { 260990087Sobrien if (GET_CODE (prev) == NOTE) 261090087Sobrien delete_insn (prev); /* Use delete_note. */ 261118334Speter } 261290087Sobrien 261390087Sobrien return prev; 261418334Speter } 261518334Speter 261618334Speter /* If the template is the string "#", it means that this insn must 261718334Speter be split. */ 261818334Speter if (template[0] == '#' && template[1] == '\0') 261918334Speter { 262018334Speter rtx new = try_split (body, insn, 0); 262118334Speter 262218334Speter /* If we didn't split the insn, go away. */ 262318334Speter if (new == insn && PATTERN (new) == body) 262490087Sobrien fatal_insn ("could not split insn", insn); 262590087Sobrien 262650503Sobrien#ifdef HAVE_ATTR_length 262750503Sobrien /* This instruction should have been split in shorten_branches, 262850503Sobrien to ensure that we would have valid length info for the 262950503Sobrien splitees. */ 263050503Sobrien abort (); 263150503Sobrien#endif 263250503Sobrien 263318334Speter new_block = 0; 263418334Speter return new; 263518334Speter } 263690087Sobrien 263718334Speter if (prescan > 0) 263818334Speter break; 263918334Speter 264090087Sobrien#ifdef IA64_UNWIND_INFO 264190087Sobrien IA64_UNWIND_EMIT (asm_out_file, insn); 264290087Sobrien#endif 264318334Speter /* Output assembler code from the template. */ 264418334Speter 264590087Sobrien output_asm_insn (template, recog_data.operand); 264618334Speter 264750503Sobrien#if defined (DWARF2_UNWIND_INFO) 264890087Sobrien#if defined (HAVE_prologue) 264950503Sobrien if (GET_CODE (insn) == INSN && dwarf2out_do_frame ()) 265050503Sobrien dwarf2out_frame_debug (insn); 265150503Sobrien#else 265290087Sobrien if (!ACCUMULATE_OUTGOING_ARGS 265390087Sobrien && GET_CODE (insn) == INSN 265490087Sobrien && dwarf2out_do_frame ()) 265550503Sobrien dwarf2out_frame_debug (insn); 265650503Sobrien#endif 265750503Sobrien#endif 265850503Sobrien 265918334Speter#if 0 266018334Speter /* It's not at all clear why we did this and doing so interferes 266118334Speter with tests we'd like to do to use REG_WAS_0 notes, so let's try 266218334Speter with this out. */ 266318334Speter 266418334Speter /* Mark this insn as having been output. */ 266518334Speter INSN_DELETED_P (insn) = 1; 266618334Speter#endif 266718334Speter 266890087Sobrien /* Emit information for vtable gc. */ 266990087Sobrien note = find_reg_note (insn, REG_VTABLE_REF, NULL_RTX); 267090087Sobrien if (note) 267190087Sobrien assemble_vtable_entry (XEXP (XEXP (note, 0), 0), 267290087Sobrien INTVAL (XEXP (XEXP (note, 0), 1))); 267390087Sobrien 267490087Sobrien current_output_insn = debug_insn = 0; 267518334Speter } 267618334Speter } 267718334Speter return NEXT_INSN (insn); 267818334Speter} 267918334Speter 268018334Speter/* Output debugging info to the assembler file FILE 268118334Speter based on the NOTE-insn INSN, assumed to be a line number. */ 268218334Speter 268318334Speterstatic void 268490087Sobriennotice_source_line (insn) 268518334Speter rtx insn; 268618334Speter{ 268790087Sobrien const char *filename = NOTE_SOURCE_FILE (insn); 268818334Speter 268918334Speter last_filename = filename; 269018334Speter last_linenum = NOTE_LINE_NUMBER (insn); 269118334Speter high_block_linenum = MAX (last_linenum, high_block_linenum); 269218334Speter high_function_linenum = MAX (last_linenum, high_function_linenum); 269318334Speter} 269418334Speter 269552515Sobrien/* For each operand in INSN, simplify (subreg (reg)) so that it refers 269652515Sobrien directly to the desired hard register. */ 269790087Sobrien 269852515Sobrienvoid 269952515Sobriencleanup_subreg_operands (insn) 270052515Sobrien rtx insn; 270152515Sobrien{ 270252515Sobrien int i; 270390087Sobrien extract_insn_cached (insn); 270490087Sobrien for (i = 0; i < recog_data.n_operands; i++) 270552515Sobrien { 270690087Sobrien /* The following test cannot use recog_data.operand when tesing 270790087Sobrien for a SUBREG: the underlying object might have been changed 270890087Sobrien already if we are inside a match_operator expression that 270990087Sobrien matches the else clause. Instead we test the underlying 271090087Sobrien expression directly. */ 271190087Sobrien if (GET_CODE (*recog_data.operand_loc[i]) == SUBREG) 271290087Sobrien recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]); 271390087Sobrien else if (GET_CODE (recog_data.operand[i]) == PLUS 271490087Sobrien || GET_CODE (recog_data.operand[i]) == MULT 271590087Sobrien || GET_CODE (recog_data.operand[i]) == MEM) 271690087Sobrien recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i]); 271752515Sobrien } 271852515Sobrien 271990087Sobrien for (i = 0; i < recog_data.n_dups; i++) 272052515Sobrien { 272190087Sobrien if (GET_CODE (*recog_data.dup_loc[i]) == SUBREG) 272290087Sobrien *recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]); 272390087Sobrien else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS 272490087Sobrien || GET_CODE (*recog_data.dup_loc[i]) == MULT 272590087Sobrien || GET_CODE (*recog_data.dup_loc[i]) == MEM) 272690087Sobrien *recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]); 272752515Sobrien } 272852515Sobrien} 272952515Sobrien 273018334Speter/* If X is a SUBREG, replace it with a REG or a MEM, 273118334Speter based on the thing it is a subreg of. */ 273218334Speter 273318334Speterrtx 273490087Sobrienalter_subreg (xp) 273590087Sobrien rtx *xp; 273618334Speter{ 273790087Sobrien rtx x = *xp; 273890087Sobrien rtx y = SUBREG_REG (x); 273950503Sobrien 274090087Sobrien /* simplify_subreg does not remove subreg from volatile references. 274190087Sobrien We are required to. */ 274290087Sobrien if (GET_CODE (y) == MEM) 274390087Sobrien *xp = adjust_address (y, GET_MODE (x), SUBREG_BYTE (x)); 274490087Sobrien else 274518334Speter { 274690087Sobrien rtx new = simplify_subreg (GET_MODE (x), y, GET_MODE (y), 274790087Sobrien SUBREG_BYTE (x)); 274850503Sobrien 274990087Sobrien if (new != 0) 275090087Sobrien *xp = new; 275190087Sobrien /* Simplify_subreg can't handle some REG cases, but we have to. */ 275290087Sobrien else if (GET_CODE (y) == REG) 275390087Sobrien { 275490087Sobrien unsigned int regno = subreg_hard_regno (x, 1); 275590087Sobrien PUT_CODE (x, REG); 275690087Sobrien REGNO (x) = regno; 275790087Sobrien ORIGINAL_REGNO (x) = ORIGINAL_REGNO (y); 275890087Sobrien /* This field has a different meaning for REGs and SUBREGs. Make 275990087Sobrien sure to clear it! */ 276090087Sobrien x->used = 0; 276190087Sobrien } 276290087Sobrien else 276390087Sobrien abort (); 276418334Speter } 276518334Speter 276690087Sobrien return *xp; 276718334Speter} 276818334Speter 276918334Speter/* Do alter_subreg on all the SUBREGs contained in X. */ 277018334Speter 277118334Speterstatic rtx 277290087Sobrienwalk_alter_subreg (xp) 277390087Sobrien rtx *xp; 277418334Speter{ 277590087Sobrien rtx x = *xp; 277618334Speter switch (GET_CODE (x)) 277718334Speter { 277818334Speter case PLUS: 277918334Speter case MULT: 278090087Sobrien XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0)); 278190087Sobrien XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1)); 278218334Speter break; 278318334Speter 278418334Speter case MEM: 278590087Sobrien XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0)); 278618334Speter break; 278718334Speter 278818334Speter case SUBREG: 278990087Sobrien return alter_subreg (xp); 279090087Sobrien 279150503Sobrien default: 279250503Sobrien break; 279318334Speter } 279418334Speter 279590087Sobrien return *xp; 279618334Speter} 279718334Speter 279818334Speter#ifdef HAVE_cc0 279918334Speter 280018334Speter/* Given BODY, the body of a jump instruction, alter the jump condition 280118334Speter as required by the bits that are set in cc_status.flags. 280218334Speter Not all of the bits there can be handled at this level in all cases. 280318334Speter 280418334Speter The value is normally 0. 280518334Speter 1 means that the condition has become always true. 280618334Speter -1 means that the condition has become always false. 280718334Speter 2 means that COND has been altered. */ 280818334Speter 280918334Speterstatic int 281018334Speteralter_cond (cond) 281190087Sobrien rtx cond; 281218334Speter{ 281318334Speter int value = 0; 281418334Speter 281518334Speter if (cc_status.flags & CC_REVERSED) 281618334Speter { 281718334Speter value = 2; 281818334Speter PUT_CODE (cond, swap_condition (GET_CODE (cond))); 281918334Speter } 282018334Speter 282118334Speter if (cc_status.flags & CC_INVERTED) 282218334Speter { 282318334Speter value = 2; 282418334Speter PUT_CODE (cond, reverse_condition (GET_CODE (cond))); 282518334Speter } 282618334Speter 282718334Speter if (cc_status.flags & CC_NOT_POSITIVE) 282818334Speter switch (GET_CODE (cond)) 282918334Speter { 283018334Speter case LE: 283118334Speter case LEU: 283218334Speter case GEU: 283318334Speter /* Jump becomes unconditional. */ 283418334Speter return 1; 283518334Speter 283618334Speter case GT: 283718334Speter case GTU: 283818334Speter case LTU: 283918334Speter /* Jump becomes no-op. */ 284018334Speter return -1; 284118334Speter 284218334Speter case GE: 284318334Speter PUT_CODE (cond, EQ); 284418334Speter value = 2; 284518334Speter break; 284618334Speter 284718334Speter case LT: 284818334Speter PUT_CODE (cond, NE); 284918334Speter value = 2; 285018334Speter break; 285190087Sobrien 285250503Sobrien default: 285350503Sobrien break; 285418334Speter } 285518334Speter 285618334Speter if (cc_status.flags & CC_NOT_NEGATIVE) 285718334Speter switch (GET_CODE (cond)) 285818334Speter { 285918334Speter case GE: 286018334Speter case GEU: 286118334Speter /* Jump becomes unconditional. */ 286218334Speter return 1; 286318334Speter 286418334Speter case LT: 286518334Speter case LTU: 286618334Speter /* Jump becomes no-op. */ 286718334Speter return -1; 286818334Speter 286918334Speter case LE: 287018334Speter case LEU: 287118334Speter PUT_CODE (cond, EQ); 287218334Speter value = 2; 287318334Speter break; 287418334Speter 287518334Speter case GT: 287618334Speter case GTU: 287718334Speter PUT_CODE (cond, NE); 287818334Speter value = 2; 287918334Speter break; 288090087Sobrien 288150503Sobrien default: 288250503Sobrien break; 288318334Speter } 288418334Speter 288518334Speter if (cc_status.flags & CC_NO_OVERFLOW) 288618334Speter switch (GET_CODE (cond)) 288718334Speter { 288818334Speter case GEU: 288918334Speter /* Jump becomes unconditional. */ 289018334Speter return 1; 289118334Speter 289218334Speter case LEU: 289318334Speter PUT_CODE (cond, EQ); 289418334Speter value = 2; 289518334Speter break; 289618334Speter 289718334Speter case GTU: 289818334Speter PUT_CODE (cond, NE); 289918334Speter value = 2; 290018334Speter break; 290118334Speter 290218334Speter case LTU: 290318334Speter /* Jump becomes no-op. */ 290418334Speter return -1; 290590087Sobrien 290650503Sobrien default: 290750503Sobrien break; 290818334Speter } 290918334Speter 291018334Speter if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N)) 291118334Speter switch (GET_CODE (cond)) 291218334Speter { 291350503Sobrien default: 291418334Speter abort (); 291518334Speter 291618334Speter case NE: 291718334Speter PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT); 291818334Speter value = 2; 291918334Speter break; 292018334Speter 292118334Speter case EQ: 292218334Speter PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE); 292318334Speter value = 2; 292418334Speter break; 292518334Speter } 292618334Speter 292718334Speter if (cc_status.flags & CC_NOT_SIGNED) 292818334Speter /* The flags are valid if signed condition operators are converted 292918334Speter to unsigned. */ 293018334Speter switch (GET_CODE (cond)) 293118334Speter { 293218334Speter case LE: 293318334Speter PUT_CODE (cond, LEU); 293418334Speter value = 2; 293518334Speter break; 293618334Speter 293718334Speter case LT: 293818334Speter PUT_CODE (cond, LTU); 293918334Speter value = 2; 294018334Speter break; 294118334Speter 294218334Speter case GT: 294318334Speter PUT_CODE (cond, GTU); 294418334Speter value = 2; 294518334Speter break; 294618334Speter 294718334Speter case GE: 294818334Speter PUT_CODE (cond, GEU); 294918334Speter value = 2; 295018334Speter break; 295150503Sobrien 295250503Sobrien default: 295350503Sobrien break; 295418334Speter } 295518334Speter 295618334Speter return value; 295718334Speter} 295818334Speter#endif 295918334Speter 296018334Speter/* Report inconsistency between the assembler template and the operands. 296118334Speter In an `asm', it's the user's fault; otherwise, the compiler's fault. */ 296218334Speter 296318334Spetervoid 296496281Sobrienoutput_operand_lossage VPARAMS ((const char *msgid, ...)) 296518334Speter{ 296696281Sobrien char *fmt_string; 296796281Sobrien char *new_message; 296896281Sobrien const char *pfx_str; 296996281Sobrien VA_OPEN (ap, msgid); 297096281Sobrien VA_FIXEDARG (ap, const char *, msgid); 297196281Sobrien 297296281Sobrien pfx_str = this_is_asm_operands ? _("invalid `asm': ") : "output_operand: "; 297396281Sobrien asprintf (&fmt_string, "%s%s", pfx_str, _(msgid)); 297496281Sobrien vasprintf (&new_message, fmt_string, ap); 297596281Sobrien 297618334Speter if (this_is_asm_operands) 297796281Sobrien error_for_asm (this_is_asm_operands, "%s", new_message); 297818334Speter else 297996281Sobrien internal_error ("%s", new_message); 298096281Sobrien 298196281Sobrien free (fmt_string); 298296281Sobrien free (new_message); 298396281Sobrien VA_CLOSE (ap); 298418334Speter} 298518334Speter 298618334Speter/* Output of assembler code from a template, and its subroutines. */ 298718334Speter 298890087Sobrien/* Annotate the assembly with a comment describing the pattern and 298990087Sobrien alternative used. */ 299090087Sobrien 299190087Sobrienstatic void 299290087Sobrienoutput_asm_name () 299390087Sobrien{ 299490087Sobrien if (debug_insn) 299590087Sobrien { 299690087Sobrien int num = INSN_CODE (debug_insn); 299790087Sobrien fprintf (asm_out_file, "\t%s %d\t%s", 299890087Sobrien ASM_COMMENT_START, INSN_UID (debug_insn), 299990087Sobrien insn_data[num].name); 300090087Sobrien if (insn_data[num].n_alternatives > 1) 300190087Sobrien fprintf (asm_out_file, "/%d", which_alternative + 1); 300290087Sobrien#ifdef HAVE_ATTR_length 300390087Sobrien fprintf (asm_out_file, "\t[length = %d]", 300490087Sobrien get_attr_length (debug_insn)); 300590087Sobrien#endif 300690087Sobrien /* Clear this so only the first assembler insn 300790087Sobrien of any rtl insn will get the special comment for -dp. */ 300890087Sobrien debug_insn = 0; 300990087Sobrien } 301090087Sobrien} 301190087Sobrien 301290087Sobrien/* If OP is a REG or MEM and we can find a MEM_EXPR corresponding to it 301390087Sobrien or its address, return that expr . Set *PADDRESSP to 1 if the expr 301490087Sobrien corresponds to the address of the object and 0 if to the object. */ 301590087Sobrien 301690087Sobrienstatic tree 301790087Sobrienget_mem_expr_from_op (op, paddressp) 301890087Sobrien rtx op; 301990087Sobrien int *paddressp; 302090087Sobrien{ 302190087Sobrien tree expr; 302290087Sobrien int inner_addressp; 302390087Sobrien 302490087Sobrien *paddressp = 0; 302590087Sobrien 302690087Sobrien if (GET_CODE (op) == REG && ORIGINAL_REGNO (op) >= FIRST_PSEUDO_REGISTER) 302790087Sobrien return REGNO_DECL (ORIGINAL_REGNO (op)); 302890087Sobrien else if (GET_CODE (op) != MEM) 302990087Sobrien return 0; 303090087Sobrien 303190087Sobrien if (MEM_EXPR (op) != 0) 303290087Sobrien return MEM_EXPR (op); 303390087Sobrien 303490087Sobrien /* Otherwise we have an address, so indicate it and look at the address. */ 303590087Sobrien *paddressp = 1; 303690087Sobrien op = XEXP (op, 0); 303790087Sobrien 303890087Sobrien /* First check if we have a decl for the address, then look at the right side 303990087Sobrien if it is a PLUS. Otherwise, strip off arithmetic and keep looking. 304090087Sobrien But don't allow the address to itself be indirect. */ 304190087Sobrien if ((expr = get_mem_expr_from_op (op, &inner_addressp)) && ! inner_addressp) 304290087Sobrien return expr; 304390087Sobrien else if (GET_CODE (op) == PLUS 304490087Sobrien && (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp))) 304590087Sobrien return expr; 304690087Sobrien 304790087Sobrien while (GET_RTX_CLASS (GET_CODE (op)) == '1' 304890087Sobrien || GET_RTX_CLASS (GET_CODE (op)) == '2') 304990087Sobrien op = XEXP (op, 0); 305090087Sobrien 305190087Sobrien expr = get_mem_expr_from_op (op, &inner_addressp); 305290087Sobrien return inner_addressp ? 0 : expr; 305390087Sobrien} 305490087Sobrien 305590087Sobrien/* Output operand names for assembler instructions. OPERANDS is the 305690087Sobrien operand vector, OPORDER is the order to write the operands, and NOPS 305790087Sobrien is the number of operands to write. */ 305890087Sobrien 305990087Sobrienstatic void 306090087Sobrienoutput_asm_operand_names (operands, oporder, nops) 306190087Sobrien rtx *operands; 306290087Sobrien int *oporder; 306390087Sobrien int nops; 306490087Sobrien{ 306590087Sobrien int wrote = 0; 306690087Sobrien int i; 306790087Sobrien 306890087Sobrien for (i = 0; i < nops; i++) 306990087Sobrien { 307090087Sobrien int addressp; 307190087Sobrien tree expr = get_mem_expr_from_op (operands[oporder[i]], &addressp); 307290087Sobrien 307390087Sobrien if (expr) 307490087Sobrien { 307590087Sobrien fprintf (asm_out_file, "%c%s %s", 307690087Sobrien wrote ? ',' : '\t', wrote ? "" : ASM_COMMENT_START, 307790087Sobrien addressp ? "*" : ""); 307890087Sobrien print_mem_expr (asm_out_file, expr); 307990087Sobrien wrote = 1; 308090087Sobrien } 308190087Sobrien } 308290087Sobrien} 308390087Sobrien 308418334Speter/* Output text from TEMPLATE to the assembler output file, 308518334Speter obeying %-directions to substitute operands taken from 308618334Speter the vector OPERANDS. 308718334Speter 308818334Speter %N (for N a digit) means print operand N in usual manner. 308918334Speter %lN means require operand N to be a CODE_LABEL or LABEL_REF 309018334Speter and print the label name with no punctuation. 309118334Speter %cN means require operand N to be a constant 309218334Speter and print the constant expression with no punctuation. 309318334Speter %aN means expect operand N to be a memory address 309418334Speter (not a memory reference!) and print a reference 309518334Speter to that address. 309618334Speter %nN means expect operand N to be a constant 309718334Speter and print a constant expression for minus the value 309818334Speter of the operand, with no other punctuation. */ 309918334Speter 310018334Spetervoid 310118334Speteroutput_asm_insn (template, operands) 310252515Sobrien const char *template; 310318334Speter rtx *operands; 310418334Speter{ 310590087Sobrien const char *p; 310690087Sobrien int c; 310790087Sobrien#ifdef ASSEMBLER_DIALECT 310890087Sobrien int dialect = 0; 310990087Sobrien#endif 311090087Sobrien int oporder[MAX_RECOG_OPERANDS]; 311190087Sobrien char opoutput[MAX_RECOG_OPERANDS]; 311290087Sobrien int ops = 0; 311318334Speter 311418334Speter /* An insn may return a null string template 311518334Speter in a case where no assembler code is needed. */ 311618334Speter if (*template == 0) 311718334Speter return; 311818334Speter 311990087Sobrien memset (opoutput, 0, sizeof opoutput); 312018334Speter p = template; 312118334Speter putc ('\t', asm_out_file); 312218334Speter 312318334Speter#ifdef ASM_OUTPUT_OPCODE 312418334Speter ASM_OUTPUT_OPCODE (asm_out_file, p); 312518334Speter#endif 312618334Speter 312750503Sobrien while ((c = *p++)) 312818334Speter switch (c) 312918334Speter { 313018334Speter case '\n': 313190087Sobrien if (flag_verbose_asm) 313290087Sobrien output_asm_operand_names (operands, oporder, ops); 313390087Sobrien if (flag_print_asm_name) 313490087Sobrien output_asm_name (); 313590087Sobrien 313690087Sobrien ops = 0; 313790087Sobrien memset (opoutput, 0, sizeof opoutput); 313890087Sobrien 313918334Speter putc (c, asm_out_file); 314018334Speter#ifdef ASM_OUTPUT_OPCODE 314118334Speter while ((c = *p) == '\t') 314218334Speter { 314318334Speter putc (c, asm_out_file); 314418334Speter p++; 314518334Speter } 314618334Speter ASM_OUTPUT_OPCODE (asm_out_file, p); 314718334Speter#endif 314818334Speter break; 314918334Speter 315018334Speter#ifdef ASSEMBLER_DIALECT 315118334Speter case '{': 315250503Sobrien { 315390087Sobrien int i; 315490087Sobrien 315590087Sobrien if (dialect) 315690087Sobrien output_operand_lossage ("nested assembly dialect alternatives"); 315790087Sobrien else 315890087Sobrien dialect = 1; 315990087Sobrien 316050503Sobrien /* If we want the first dialect, do nothing. Otherwise, skip 316150503Sobrien DIALECT_NUMBER of strings ending with '|'. */ 316250503Sobrien for (i = 0; i < dialect_number; i++) 316350503Sobrien { 316490087Sobrien while (*p && *p != '}' && *p++ != '|') 316550503Sobrien ; 316690087Sobrien if (*p == '}') 316790087Sobrien break; 316850503Sobrien if (*p == '|') 316950503Sobrien p++; 317050503Sobrien } 317190087Sobrien 317290087Sobrien if (*p == '\0') 317390087Sobrien output_operand_lossage ("unterminated assembly dialect alternative"); 317450503Sobrien } 317518334Speter break; 317618334Speter 317718334Speter case '|': 317890087Sobrien if (dialect) 317990087Sobrien { 318090087Sobrien /* Skip to close brace. */ 318190087Sobrien do 318290087Sobrien { 318390087Sobrien if (*p == '\0') 318490087Sobrien { 318590087Sobrien output_operand_lossage ("unterminated assembly dialect alternative"); 318690087Sobrien break; 318790087Sobrien } 318890087Sobrien } 318990087Sobrien while (*p++ != '}'); 319090087Sobrien dialect = 0; 319190087Sobrien } 319290087Sobrien else 319390087Sobrien putc (c, asm_out_file); 319418334Speter break; 319518334Speter 319618334Speter case '}': 319790087Sobrien if (! dialect) 319890087Sobrien putc (c, asm_out_file); 319990087Sobrien dialect = 0; 320018334Speter break; 320118334Speter#endif 320218334Speter 320318334Speter case '%': 320418334Speter /* %% outputs a single %. */ 320518334Speter if (*p == '%') 320618334Speter { 320718334Speter p++; 320818334Speter putc (c, asm_out_file); 320918334Speter } 321018334Speter /* %= outputs a number which is unique to each insn in the entire 321118334Speter compilation. This is useful for making local labels that are 321218334Speter referred to more than once in a given insn. */ 321318334Speter else if (*p == '=') 321418334Speter { 321518334Speter p++; 321618334Speter fprintf (asm_out_file, "%d", insn_counter); 321718334Speter } 321818334Speter /* % followed by a letter and some digits 321918334Speter outputs an operand in a special way depending on the letter. 322018334Speter Letters `acln' are implemented directly. 322118334Speter Other letters are passed to `output_operand' so that 322218334Speter the PRINT_OPERAND macro can define them. */ 322390087Sobrien else if (ISALPHA (*p)) 322418334Speter { 322518334Speter int letter = *p++; 322618334Speter c = atoi (p); 322718334Speter 322890087Sobrien if (! ISDIGIT (*p)) 322996281Sobrien output_operand_lossage ("operand number missing after %%-letter"); 323090087Sobrien else if (this_is_asm_operands 323190087Sobrien && (c < 0 || (unsigned int) c >= insn_noperands)) 323218334Speter output_operand_lossage ("operand number out of range"); 323318334Speter else if (letter == 'l') 323418334Speter output_asm_label (operands[c]); 323518334Speter else if (letter == 'a') 323618334Speter output_address (operands[c]); 323718334Speter else if (letter == 'c') 323818334Speter { 323918334Speter if (CONSTANT_ADDRESS_P (operands[c])) 324018334Speter output_addr_const (asm_out_file, operands[c]); 324118334Speter else 324218334Speter output_operand (operands[c], 'c'); 324318334Speter } 324418334Speter else if (letter == 'n') 324518334Speter { 324618334Speter if (GET_CODE (operands[c]) == CONST_INT) 324750503Sobrien fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, 324818334Speter - INTVAL (operands[c])); 324918334Speter else 325018334Speter { 325118334Speter putc ('-', asm_out_file); 325218334Speter output_addr_const (asm_out_file, operands[c]); 325318334Speter } 325418334Speter } 325518334Speter else 325618334Speter output_operand (operands[c], letter); 325790087Sobrien 325890087Sobrien if (!opoutput[c]) 325990087Sobrien oporder[ops++] = c; 326090087Sobrien opoutput[c] = 1; 326190087Sobrien 326290087Sobrien while (ISDIGIT (c = *p)) 326390087Sobrien p++; 326418334Speter } 326518334Speter /* % followed by a digit outputs an operand the default way. */ 326690087Sobrien else if (ISDIGIT (*p)) 326718334Speter { 326818334Speter c = atoi (p); 326990087Sobrien if (this_is_asm_operands 327090087Sobrien && (c < 0 || (unsigned int) c >= insn_noperands)) 327118334Speter output_operand_lossage ("operand number out of range"); 327218334Speter else 327318334Speter output_operand (operands[c], 0); 327490087Sobrien 327590087Sobrien if (!opoutput[c]) 327690087Sobrien oporder[ops++] = c; 327790087Sobrien opoutput[c] = 1; 327890087Sobrien 327990087Sobrien while (ISDIGIT (c = *p)) 328090087Sobrien p++; 328118334Speter } 328218334Speter /* % followed by punctuation: output something for that 328318334Speter punctuation character alone, with no operand. 328418334Speter The PRINT_OPERAND macro decides what is actually done. */ 328518334Speter#ifdef PRINT_OPERAND_PUNCT_VALID_P 328690087Sobrien else if (PRINT_OPERAND_PUNCT_VALID_P ((unsigned char) *p)) 328718334Speter output_operand (NULL_RTX, *p++); 328818334Speter#endif 328918334Speter else 329018334Speter output_operand_lossage ("invalid %%-code"); 329118334Speter break; 329218334Speter 329318334Speter default: 329418334Speter putc (c, asm_out_file); 329518334Speter } 329618334Speter 329790087Sobrien /* Write out the variable names for operands, if we know them. */ 329890087Sobrien if (flag_verbose_asm) 329990087Sobrien output_asm_operand_names (operands, oporder, ops); 330090087Sobrien if (flag_print_asm_name) 330190087Sobrien output_asm_name (); 330218334Speter 330318334Speter putc ('\n', asm_out_file); 330418334Speter} 330518334Speter 330618334Speter/* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol. */ 330718334Speter 330818334Spetervoid 330918334Speteroutput_asm_label (x) 331018334Speter rtx x; 331118334Speter{ 331218334Speter char buf[256]; 331318334Speter 331418334Speter if (GET_CODE (x) == LABEL_REF) 331590087Sobrien x = XEXP (x, 0); 331690087Sobrien if (GET_CODE (x) == CODE_LABEL 331790087Sobrien || (GET_CODE (x) == NOTE 331890087Sobrien && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL)) 331918334Speter ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); 332018334Speter else 332196281Sobrien output_operand_lossage ("`%%l' operand isn't a label"); 332218334Speter 332318334Speter assemble_name (asm_out_file, buf); 332418334Speter} 332518334Speter 332618334Speter/* Print operand X using machine-dependent assembler syntax. 332718334Speter The macro PRINT_OPERAND is defined just to control this function. 332818334Speter CODE is a non-digit that preceded the operand-number in the % spec, 332918334Speter such as 'z' if the spec was `%z3'. CODE is 0 if there was no char 333018334Speter between the % and the digits. 333118334Speter When CODE is a non-letter, X is 0. 333218334Speter 333318334Speter The meanings of the letters are machine-dependent and controlled 333418334Speter by PRINT_OPERAND. */ 333518334Speter 333618334Speterstatic void 333718334Speteroutput_operand (x, code) 333818334Speter rtx x; 333990087Sobrien int code ATTRIBUTE_UNUSED; 334018334Speter{ 334118334Speter if (x && GET_CODE (x) == SUBREG) 334290087Sobrien x = alter_subreg (&x); 334318334Speter 334418334Speter /* If X is a pseudo-register, abort now rather than writing trash to the 334518334Speter assembler file. */ 334618334Speter 334718334Speter if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER) 334818334Speter abort (); 334918334Speter 335018334Speter PRINT_OPERAND (asm_out_file, x, code); 335118334Speter} 335218334Speter 335318334Speter/* Print a memory reference operand for address X 335418334Speter using machine-dependent assembler syntax. 335518334Speter The macro PRINT_OPERAND_ADDRESS exists just to control this function. */ 335618334Speter 335718334Spetervoid 335818334Speteroutput_address (x) 335918334Speter rtx x; 336018334Speter{ 336190087Sobrien walk_alter_subreg (&x); 336218334Speter PRINT_OPERAND_ADDRESS (asm_out_file, x); 336318334Speter} 336418334Speter 336518334Speter/* Print an integer constant expression in assembler syntax. 336618334Speter Addition and subtraction are the only arithmetic 336718334Speter that may appear in these expressions. */ 336818334Speter 336918334Spetervoid 337018334Speteroutput_addr_const (file, x) 337118334Speter FILE *file; 337218334Speter rtx x; 337318334Speter{ 337418334Speter char buf[256]; 337518334Speter 337618334Speter restart: 337718334Speter switch (GET_CODE (x)) 337818334Speter { 337918334Speter case PC: 338090087Sobrien putc ('.', file); 338118334Speter break; 338218334Speter 338318334Speter case SYMBOL_REF: 338490087Sobrien#ifdef ASM_OUTPUT_SYMBOL_REF 338590087Sobrien ASM_OUTPUT_SYMBOL_REF (file, x); 338690087Sobrien#else 338718334Speter assemble_name (file, XSTR (x, 0)); 338890087Sobrien#endif 338918334Speter break; 339018334Speter 339118334Speter case LABEL_REF: 339290087Sobrien x = XEXP (x, 0); 339390087Sobrien /* Fall through. */ 339418334Speter case CODE_LABEL: 339518334Speter ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); 339690087Sobrien#ifdef ASM_OUTPUT_LABEL_REF 339790087Sobrien ASM_OUTPUT_LABEL_REF (file, buf); 339890087Sobrien#else 339918334Speter assemble_name (file, buf); 340090087Sobrien#endif 340118334Speter break; 340218334Speter 340318334Speter case CONST_INT: 340450503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); 340518334Speter break; 340618334Speter 340718334Speter case CONST: 340818334Speter /* This used to output parentheses around the expression, 340918334Speter but that does not work on the 386 (either ATT or BSD assembler). */ 341018334Speter output_addr_const (file, XEXP (x, 0)); 341118334Speter break; 341218334Speter 341318334Speter case CONST_DOUBLE: 341418334Speter if (GET_MODE (x) == VOIDmode) 341518334Speter { 341618334Speter /* We can use %d if the number is one word and positive. */ 341718334Speter if (CONST_DOUBLE_HIGH (x)) 341850503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX, 341918334Speter CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x)); 342090087Sobrien else if (CONST_DOUBLE_LOW (x) < 0) 342150503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x)); 342218334Speter else 342350503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x)); 342418334Speter } 342518334Speter else 342618334Speter /* We can't handle floating point constants; 342718334Speter PRINT_OPERAND must handle them. */ 342818334Speter output_operand_lossage ("floating constant misused"); 342918334Speter break; 343018334Speter 343118334Speter case PLUS: 343218334Speter /* Some assemblers need integer constants to appear last (eg masm). */ 343318334Speter if (GET_CODE (XEXP (x, 0)) == CONST_INT) 343418334Speter { 343518334Speter output_addr_const (file, XEXP (x, 1)); 343618334Speter if (INTVAL (XEXP (x, 0)) >= 0) 343718334Speter fprintf (file, "+"); 343818334Speter output_addr_const (file, XEXP (x, 0)); 343918334Speter } 344018334Speter else 344118334Speter { 344218334Speter output_addr_const (file, XEXP (x, 0)); 344390087Sobrien if (GET_CODE (XEXP (x, 1)) != CONST_INT 344490087Sobrien || INTVAL (XEXP (x, 1)) >= 0) 344518334Speter fprintf (file, "+"); 344618334Speter output_addr_const (file, XEXP (x, 1)); 344718334Speter } 344818334Speter break; 344918334Speter 345018334Speter case MINUS: 345118334Speter /* Avoid outputting things like x-x or x+5-x, 345218334Speter since some assemblers can't handle that. */ 345318334Speter x = simplify_subtraction (x); 345418334Speter if (GET_CODE (x) != MINUS) 345518334Speter goto restart; 345618334Speter 345718334Speter output_addr_const (file, XEXP (x, 0)); 345818334Speter fprintf (file, "-"); 345990087Sobrien if ((GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0) 346090087Sobrien || GET_CODE (XEXP (x, 1)) == PC 346190087Sobrien || GET_CODE (XEXP (x, 1)) == SYMBOL_REF) 346290087Sobrien output_addr_const (file, XEXP (x, 1)); 346390087Sobrien else 346418334Speter { 346590087Sobrien fputs (targetm.asm_out.open_paren, file); 346618334Speter output_addr_const (file, XEXP (x, 1)); 346790087Sobrien fputs (targetm.asm_out.close_paren, file); 346818334Speter } 346918334Speter break; 347018334Speter 347118334Speter case ZERO_EXTEND: 347218334Speter case SIGN_EXTEND: 347396281Sobrien case SUBREG: 347418334Speter output_addr_const (file, XEXP (x, 0)); 347518334Speter break; 347618334Speter 347718334Speter default: 347890087Sobrien#ifdef OUTPUT_ADDR_CONST_EXTRA 347990087Sobrien OUTPUT_ADDR_CONST_EXTRA (file, x, fail); 348090087Sobrien break; 348190087Sobrien 348290087Sobrien fail: 348390087Sobrien#endif 348418334Speter output_operand_lossage ("invalid expression as operand"); 348518334Speter } 348618334Speter} 348718334Speter 348818334Speter/* A poor man's fprintf, with the added features of %I, %R, %L, and %U. 348918334Speter %R prints the value of REGISTER_PREFIX. 349018334Speter %L prints the value of LOCAL_LABEL_PREFIX. 349118334Speter %U prints the value of USER_LABEL_PREFIX. 349218334Speter %I prints the value of IMMEDIATE_PREFIX. 349318334Speter %O runs ASM_OUTPUT_OPCODE to transform what follows in the string. 349418334Speter Also supported are %d, %x, %s, %e, %f, %g and %%. 349518334Speter 349618334Speter We handle alternate assembler dialects here, just like output_asm_insn. */ 349718334Speter 349818334Spetervoid 349990087Sobrienasm_fprintf VPARAMS ((FILE *file, const char *p, ...)) 350018334Speter{ 350118334Speter char buf[10]; 350218334Speter char *q, c; 350318334Speter 350490087Sobrien VA_OPEN (argptr, p); 350590087Sobrien VA_FIXEDARG (argptr, FILE *, file); 350690087Sobrien VA_FIXEDARG (argptr, const char *, p); 350718334Speter 350818334Speter buf[0] = '%'; 350918334Speter 351050503Sobrien while ((c = *p++)) 351118334Speter switch (c) 351218334Speter { 351318334Speter#ifdef ASSEMBLER_DIALECT 351418334Speter case '{': 351550503Sobrien { 351650503Sobrien int i; 351718334Speter 351850503Sobrien /* If we want the first dialect, do nothing. Otherwise, skip 351950503Sobrien DIALECT_NUMBER of strings ending with '|'. */ 352050503Sobrien for (i = 0; i < dialect_number; i++) 352150503Sobrien { 352250503Sobrien while (*p && *p++ != '|') 352350503Sobrien ; 352450503Sobrien 352550503Sobrien if (*p == '|') 352650503Sobrien p++; 352790087Sobrien } 352850503Sobrien } 352918334Speter break; 353018334Speter 353118334Speter case '|': 353218334Speter /* Skip to close brace. */ 353318334Speter while (*p && *p++ != '}') 353418334Speter ; 353518334Speter break; 353618334Speter 353718334Speter case '}': 353818334Speter break; 353918334Speter#endif 354018334Speter 354118334Speter case '%': 354218334Speter c = *p++; 354318334Speter q = &buf[1]; 354490087Sobrien while (ISDIGIT (c) || c == '.') 354518334Speter { 354618334Speter *q++ = c; 354718334Speter c = *p++; 354818334Speter } 354918334Speter switch (c) 355018334Speter { 355118334Speter case '%': 355218334Speter fprintf (file, "%%"); 355318334Speter break; 355418334Speter 355518334Speter case 'd': case 'i': case 'u': 355618334Speter case 'x': case 'p': case 'X': 355718334Speter case 'o': 355818334Speter *q++ = c; 355918334Speter *q = 0; 356018334Speter fprintf (file, buf, va_arg (argptr, int)); 356118334Speter break; 356218334Speter 356318334Speter case 'w': 356418334Speter /* This is a prefix to the 'd', 'i', 'u', 'x', 'p', and 'X' cases, 356518334Speter but we do not check for those cases. It means that the value 356618334Speter is a HOST_WIDE_INT, which may be either `int' or `long'. */ 356718334Speter 356850503Sobrien#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT 356950503Sobrien#else 357050503Sobrien#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG 357118334Speter *q++ = 'l'; 357250503Sobrien#else 357350503Sobrien *q++ = 'l'; 357450503Sobrien *q++ = 'l'; 357518334Speter#endif 357650503Sobrien#endif 357718334Speter 357818334Speter *q++ = *p++; 357918334Speter *q = 0; 358018334Speter fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT)); 358118334Speter break; 358218334Speter 358318334Speter case 'l': 358418334Speter *q++ = c; 358518334Speter *q++ = *p++; 358618334Speter *q = 0; 358718334Speter fprintf (file, buf, va_arg (argptr, long)); 358818334Speter break; 358918334Speter 359018334Speter case 'e': 359118334Speter case 'f': 359218334Speter case 'g': 359318334Speter *q++ = c; 359418334Speter *q = 0; 359518334Speter fprintf (file, buf, va_arg (argptr, double)); 359618334Speter break; 359718334Speter 359818334Speter case 's': 359918334Speter *q++ = c; 360018334Speter *q = 0; 360118334Speter fprintf (file, buf, va_arg (argptr, char *)); 360218334Speter break; 360318334Speter 360418334Speter case 'O': 360518334Speter#ifdef ASM_OUTPUT_OPCODE 360618334Speter ASM_OUTPUT_OPCODE (asm_out_file, p); 360718334Speter#endif 360818334Speter break; 360918334Speter 361018334Speter case 'R': 361118334Speter#ifdef REGISTER_PREFIX 361218334Speter fprintf (file, "%s", REGISTER_PREFIX); 361318334Speter#endif 361418334Speter break; 361518334Speter 361618334Speter case 'I': 361718334Speter#ifdef IMMEDIATE_PREFIX 361818334Speter fprintf (file, "%s", IMMEDIATE_PREFIX); 361918334Speter#endif 362018334Speter break; 362118334Speter 362218334Speter case 'L': 362318334Speter#ifdef LOCAL_LABEL_PREFIX 362418334Speter fprintf (file, "%s", LOCAL_LABEL_PREFIX); 362518334Speter#endif 362618334Speter break; 362718334Speter 362818334Speter case 'U': 362952515Sobrien fputs (user_label_prefix, file); 363018334Speter break; 363118334Speter 363290087Sobrien#ifdef ASM_FPRINTF_EXTENSIONS 363390087Sobrien /* Upper case letters are reserved for general use by asm_fprintf 363490087Sobrien and so are not available to target specific code. In order to 363590087Sobrien prevent the ASM_FPRINTF_EXTENSIONS macro from using them then, 363690087Sobrien they are defined here. As they get turned into real extensions 363790087Sobrien to asm_fprintf they should be removed from this list. */ 363890087Sobrien case 'A': case 'B': case 'C': case 'D': case 'E': 363990087Sobrien case 'F': case 'G': case 'H': case 'J': case 'K': 364090087Sobrien case 'M': case 'N': case 'P': case 'Q': case 'S': 364190087Sobrien case 'T': case 'V': case 'W': case 'Y': case 'Z': 364290087Sobrien break; 364390087Sobrien 364490087Sobrien ASM_FPRINTF_EXTENSIONS (file, argptr, p) 364590087Sobrien#endif 364618334Speter default: 364718334Speter abort (); 364818334Speter } 364918334Speter break; 365018334Speter 365118334Speter default: 365218334Speter fputc (c, file); 365318334Speter } 365490087Sobrien VA_CLOSE (argptr); 365518334Speter} 365618334Speter 365718334Speter/* Split up a CONST_DOUBLE or integer constant rtx 365818334Speter into two rtx's for single words, 365918334Speter storing in *FIRST the word that comes first in memory in the target 366018334Speter and in *SECOND the other. */ 366118334Speter 366218334Spetervoid 366318334Spetersplit_double (value, first, second) 366418334Speter rtx value; 366518334Speter rtx *first, *second; 366618334Speter{ 366718334Speter if (GET_CODE (value) == CONST_INT) 366818334Speter { 366918334Speter if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD)) 367018334Speter { 367118334Speter /* In this case the CONST_INT holds both target words. 367250503Sobrien Extract the bits from it into two word-sized pieces. 367350503Sobrien Sign extend each half to HOST_WIDE_INT. */ 367490087Sobrien unsigned HOST_WIDE_INT low, high; 367590087Sobrien unsigned HOST_WIDE_INT mask, sign_bit, sign_extend; 367618334Speter 367790087Sobrien /* Set sign_bit to the most significant bit of a word. */ 367890087Sobrien sign_bit = 1; 367990087Sobrien sign_bit <<= BITS_PER_WORD - 1; 368090087Sobrien 368190087Sobrien /* Set mask so that all bits of the word are set. We could 368290087Sobrien have used 1 << BITS_PER_WORD instead of basing the 368390087Sobrien calculation on sign_bit. However, on machines where 368490087Sobrien HOST_BITS_PER_WIDE_INT == BITS_PER_WORD, it could cause a 368590087Sobrien compiler warning, even though the code would never be 368690087Sobrien executed. */ 368790087Sobrien mask = sign_bit << 1; 368890087Sobrien mask--; 368990087Sobrien 369090087Sobrien /* Set sign_extend as any remaining bits. */ 369190087Sobrien sign_extend = ~mask; 369290087Sobrien 369390087Sobrien /* Pick the lower word and sign-extend it. */ 369490087Sobrien low = INTVAL (value); 369590087Sobrien low &= mask; 369690087Sobrien if (low & sign_bit) 369790087Sobrien low |= sign_extend; 369890087Sobrien 369990087Sobrien /* Pick the higher word, shifted to the least significant 370090087Sobrien bits, and sign-extend it. */ 370190087Sobrien high = INTVAL (value); 370290087Sobrien high >>= BITS_PER_WORD - 1; 370390087Sobrien high >>= 1; 370490087Sobrien high &= mask; 370590087Sobrien if (high & sign_bit) 370690087Sobrien high |= sign_extend; 370790087Sobrien 370890087Sobrien /* Store the words in the target machine order. */ 370918334Speter if (WORDS_BIG_ENDIAN) 371018334Speter { 371190087Sobrien *first = GEN_INT (high); 371290087Sobrien *second = GEN_INT (low); 371318334Speter } 371418334Speter else 371518334Speter { 371690087Sobrien *first = GEN_INT (low); 371790087Sobrien *second = GEN_INT (high); 371818334Speter } 371918334Speter } 372018334Speter else 372118334Speter { 372218334Speter /* The rule for using CONST_INT for a wider mode 372318334Speter is that we regard the value as signed. 372418334Speter So sign-extend it. */ 372518334Speter rtx high = (INTVAL (value) < 0 ? constm1_rtx : const0_rtx); 372618334Speter if (WORDS_BIG_ENDIAN) 372718334Speter { 372818334Speter *first = high; 372918334Speter *second = value; 373018334Speter } 373118334Speter else 373218334Speter { 373318334Speter *first = value; 373418334Speter *second = high; 373518334Speter } 373618334Speter } 373718334Speter } 373818334Speter else if (GET_CODE (value) != CONST_DOUBLE) 373918334Speter { 374018334Speter if (WORDS_BIG_ENDIAN) 374118334Speter { 374218334Speter *first = const0_rtx; 374318334Speter *second = value; 374418334Speter } 374518334Speter else 374618334Speter { 374718334Speter *first = value; 374818334Speter *second = const0_rtx; 374918334Speter } 375018334Speter } 375118334Speter else if (GET_MODE (value) == VOIDmode 375218334Speter /* This is the old way we did CONST_DOUBLE integers. */ 375318334Speter || GET_MODE_CLASS (GET_MODE (value)) == MODE_INT) 375418334Speter { 375518334Speter /* In an integer, the words are defined as most and least significant. 375618334Speter So order them by the target's convention. */ 375718334Speter if (WORDS_BIG_ENDIAN) 375818334Speter { 375918334Speter *first = GEN_INT (CONST_DOUBLE_HIGH (value)); 376018334Speter *second = GEN_INT (CONST_DOUBLE_LOW (value)); 376118334Speter } 376218334Speter else 376318334Speter { 376418334Speter *first = GEN_INT (CONST_DOUBLE_LOW (value)); 376518334Speter *second = GEN_INT (CONST_DOUBLE_HIGH (value)); 376618334Speter } 376718334Speter } 376818334Speter else 376918334Speter { 377018334Speter#ifdef REAL_ARITHMETIC 377190087Sobrien REAL_VALUE_TYPE r; 377290087Sobrien long l[2]; 377318334Speter REAL_VALUE_FROM_CONST_DOUBLE (r, value); 377418334Speter 377518334Speter /* Note, this converts the REAL_VALUE_TYPE to the target's 377618334Speter format, splits up the floating point double and outputs 377718334Speter exactly 32 bits of it into each of l[0] and l[1] -- 377850503Sobrien not necessarily BITS_PER_WORD bits. */ 377918334Speter REAL_VALUE_TO_TARGET_DOUBLE (r, l); 378018334Speter 378152515Sobrien /* If 32 bits is an entire word for the target, but not for the host, 378252515Sobrien then sign-extend on the host so that the number will look the same 378352515Sobrien way on the host that it would on the target. See for instance 378452515Sobrien simplify_unary_operation. The #if is needed to avoid compiler 378552515Sobrien warnings. */ 378652515Sobrien 378752515Sobrien#if HOST_BITS_PER_LONG > 32 378852515Sobrien if (BITS_PER_WORD < HOST_BITS_PER_LONG && BITS_PER_WORD == 32) 378952515Sobrien { 379052515Sobrien if (l[0] & ((long) 1 << 31)) 379152515Sobrien l[0] |= ((long) (-1) << 32); 379252515Sobrien if (l[1] & ((long) 1 << 31)) 379352515Sobrien l[1] |= ((long) (-1) << 32); 379452515Sobrien } 379552515Sobrien#endif 379652515Sobrien 379718334Speter *first = GEN_INT ((HOST_WIDE_INT) l[0]); 379818334Speter *second = GEN_INT ((HOST_WIDE_INT) l[1]); 379918334Speter#else 380018334Speter if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT 380118334Speter || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD) 380218334Speter && ! flag_pretend_float) 380390087Sobrien abort (); 380418334Speter 380518334Speter if ( 380618334Speter#ifdef HOST_WORDS_BIG_ENDIAN 380718334Speter WORDS_BIG_ENDIAN 380818334Speter#else 380918334Speter ! WORDS_BIG_ENDIAN 381018334Speter#endif 381118334Speter ) 381218334Speter { 381318334Speter /* Host and target agree => no need to swap. */ 381418334Speter *first = GEN_INT (CONST_DOUBLE_LOW (value)); 381518334Speter *second = GEN_INT (CONST_DOUBLE_HIGH (value)); 381618334Speter } 381718334Speter else 381818334Speter { 381918334Speter *second = GEN_INT (CONST_DOUBLE_LOW (value)); 382018334Speter *first = GEN_INT (CONST_DOUBLE_HIGH (value)); 382118334Speter } 382218334Speter#endif /* no REAL_ARITHMETIC */ 382318334Speter } 382418334Speter} 382518334Speter 382618334Speter/* Return nonzero if this function has no function calls. */ 382718334Speter 382818334Speterint 382918334Speterleaf_function_p () 383018334Speter{ 383118334Speter rtx insn; 383290087Sobrien rtx link; 383318334Speter 383490087Sobrien if (current_function_profile || profile_arc_flag) 383518334Speter return 0; 383618334Speter 383718334Speter for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 383818334Speter { 383990087Sobrien if (GET_CODE (insn) == CALL_INSN 384090087Sobrien && ! SIBLING_CALL_P (insn)) 384118334Speter return 0; 384218334Speter if (GET_CODE (insn) == INSN 384318334Speter && GET_CODE (PATTERN (insn)) == SEQUENCE 384490087Sobrien && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN 384590087Sobrien && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0))) 384618334Speter return 0; 384718334Speter } 384890087Sobrien for (link = current_function_epilogue_delay_list; 384990087Sobrien link; 385090087Sobrien link = XEXP (link, 1)) 385118334Speter { 385290087Sobrien insn = XEXP (link, 0); 385390087Sobrien 385490087Sobrien if (GET_CODE (insn) == CALL_INSN 385590087Sobrien && ! SIBLING_CALL_P (insn)) 385618334Speter return 0; 385790087Sobrien if (GET_CODE (insn) == INSN 385890087Sobrien && GET_CODE (PATTERN (insn)) == SEQUENCE 385990087Sobrien && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN 386090087Sobrien && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0))) 386118334Speter return 0; 386218334Speter } 386318334Speter 386418334Speter return 1; 386518334Speter} 386618334Speter 386790087Sobrien/* Return 1 if branch is an forward branch. 386890087Sobrien Uses insn_shuid array, so it works only in the final pass. May be used by 386990087Sobrien output templates to customary add branch prediction hints. 387090087Sobrien */ 387190087Sobrienint 387290087Sobrienfinal_forward_branch_p (insn) 387390087Sobrien rtx insn; 387490087Sobrien{ 387590087Sobrien int insn_id, label_id; 387690087Sobrien if (!uid_shuid) 387790087Sobrien abort (); 387890087Sobrien insn_id = INSN_SHUID (insn); 387990087Sobrien label_id = INSN_SHUID (JUMP_LABEL (insn)); 388090087Sobrien /* We've hit some insns that does not have id information available. */ 388190087Sobrien if (!insn_id || !label_id) 388290087Sobrien abort (); 388390087Sobrien return insn_id < label_id; 388490087Sobrien} 388590087Sobrien 388618334Speter/* On some machines, a function with no call insns 388718334Speter can run faster if it doesn't create its own register window. 388818334Speter When output, the leaf function should use only the "output" 388918334Speter registers. Ordinarily, the function would be compiled to use 389018334Speter the "input" registers to find its arguments; it is a candidate 389118334Speter for leaf treatment if it uses only the "input" registers. 389218334Speter Leaf function treatment means renumbering so the function 389318334Speter uses the "output" registers instead. */ 389418334Speter 389518334Speter#ifdef LEAF_REGISTERS 389618334Speter 389718334Speter/* Return 1 if this function uses only the registers that can be 389818334Speter safely renumbered. */ 389918334Speter 390018334Speterint 390118334Speteronly_leaf_regs_used () 390218334Speter{ 390318334Speter int i; 390490087Sobrien char *permitted_reg_in_leaf_functions = LEAF_REGISTERS; 390518334Speter 390618334Speter for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 390750503Sobrien if ((regs_ever_live[i] || global_regs[i]) 390850503Sobrien && ! permitted_reg_in_leaf_functions[i]) 390950503Sobrien return 0; 391050503Sobrien 391150503Sobrien if (current_function_uses_pic_offset_table 391250503Sobrien && pic_offset_table_rtx != 0 391350503Sobrien && GET_CODE (pic_offset_table_rtx) == REG 391450503Sobrien && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)]) 391550503Sobrien return 0; 391650503Sobrien 391718334Speter return 1; 391818334Speter} 391918334Speter 392018334Speter/* Scan all instructions and renumber all registers into those 392118334Speter available in leaf functions. */ 392218334Speter 392318334Speterstatic void 392418334Speterleaf_renumber_regs (first) 392518334Speter rtx first; 392618334Speter{ 392718334Speter rtx insn; 392818334Speter 392918334Speter /* Renumber only the actual patterns. 393018334Speter The reg-notes can contain frame pointer refs, 393118334Speter and renumbering them could crash, and should not be needed. */ 393218334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 393390087Sobrien if (INSN_P (insn)) 393418334Speter leaf_renumber_regs_insn (PATTERN (insn)); 393590087Sobrien for (insn = current_function_epilogue_delay_list; 393690087Sobrien insn; 393790087Sobrien insn = XEXP (insn, 1)) 393890087Sobrien if (INSN_P (XEXP (insn, 0))) 393918334Speter leaf_renumber_regs_insn (PATTERN (XEXP (insn, 0))); 394018334Speter} 394118334Speter 394218334Speter/* Scan IN_RTX and its subexpressions, and renumber all regs into those 394318334Speter available in leaf functions. */ 394418334Speter 394518334Spetervoid 394618334Speterleaf_renumber_regs_insn (in_rtx) 394790087Sobrien rtx in_rtx; 394818334Speter{ 394990087Sobrien int i, j; 395090087Sobrien const char *format_ptr; 395118334Speter 395218334Speter if (in_rtx == 0) 395318334Speter return; 395418334Speter 395518334Speter /* Renumber all input-registers into output-registers. 395618334Speter renumbered_regs would be 1 for an output-register; 395718334Speter they */ 395818334Speter 395918334Speter if (GET_CODE (in_rtx) == REG) 396018334Speter { 396118334Speter int newreg; 396218334Speter 396318334Speter /* Don't renumber the same reg twice. */ 396418334Speter if (in_rtx->used) 396518334Speter return; 396618334Speter 396718334Speter newreg = REGNO (in_rtx); 396818334Speter /* Don't try to renumber pseudo regs. It is possible for a pseudo reg 396918334Speter to reach here as part of a REG_NOTE. */ 397018334Speter if (newreg >= FIRST_PSEUDO_REGISTER) 397118334Speter { 397218334Speter in_rtx->used = 1; 397318334Speter return; 397418334Speter } 397518334Speter newreg = LEAF_REG_REMAP (newreg); 397618334Speter if (newreg < 0) 397718334Speter abort (); 397818334Speter regs_ever_live[REGNO (in_rtx)] = 0; 397918334Speter regs_ever_live[newreg] = 1; 398018334Speter REGNO (in_rtx) = newreg; 398118334Speter in_rtx->used = 1; 398218334Speter } 398318334Speter 398490087Sobrien if (INSN_P (in_rtx)) 398518334Speter { 398618334Speter /* Inside a SEQUENCE, we find insns. 398718334Speter Renumber just the patterns of these insns, 398818334Speter just as we do for the top-level insns. */ 398918334Speter leaf_renumber_regs_insn (PATTERN (in_rtx)); 399018334Speter return; 399118334Speter } 399218334Speter 399318334Speter format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx)); 399418334Speter 399518334Speter for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++) 399618334Speter switch (*format_ptr++) 399718334Speter { 399818334Speter case 'e': 399918334Speter leaf_renumber_regs_insn (XEXP (in_rtx, i)); 400018334Speter break; 400118334Speter 400218334Speter case 'E': 400318334Speter if (NULL != XVEC (in_rtx, i)) 400418334Speter { 400518334Speter for (j = 0; j < XVECLEN (in_rtx, i); j++) 400618334Speter leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j)); 400718334Speter } 400818334Speter break; 400918334Speter 401018334Speter case 'S': 401118334Speter case 's': 401218334Speter case '0': 401318334Speter case 'i': 401418334Speter case 'w': 401518334Speter case 'n': 401618334Speter case 'u': 401718334Speter break; 401818334Speter 401918334Speter default: 402018334Speter abort (); 402118334Speter } 402218334Speter} 402318334Speter#endif 4024