118334Speter/* Convert RTL to assembler code and output it, for GNU compiler. 290087Sobrien Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 3169699Skan 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 4169699Skan Free Software Foundation, Inc. 518334Speter 690087SobrienThis file is part of GCC. 718334Speter 890087SobrienGCC is free software; you can redistribute it and/or modify it under 990087Sobrienthe terms of the GNU General Public License as published by the Free 1090087SobrienSoftware Foundation; either version 2, or (at your option) any later 1190087Sobrienversion. 1218334Speter 1390087SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1490087SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1590087SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1690087Sobrienfor more details. 1718334Speter 1818334SpeterYou should have received a copy of the GNU General Public License 1990087Sobrienalong with GCC; see the file COPYING. If not, write to the Free 20169699SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 21169699Skan02110-1301, USA. */ 2218334Speter 2318334Speter/* This is the final pass of the compiler. 2418334Speter It looks at the rtl code for a function and outputs assembler code. 2518334Speter 2618334Speter Call `final_start_function' to output the assembler code for function entry, 2718334Speter `final' to output assembler code for some RTL code, 2818334Speter `final_end_function' to output assembler code for function exit. 2918334Speter If a function is compiled in several pieces, each piece is 3018334Speter output separately with `final'. 3118334Speter 3218334Speter Some optimizations are also done at this level. 3318334Speter Move instructions that were made unnecessary by good register allocation 3418334Speter are detected and omitted from the output. (Though most of these 3518334Speter are removed by the last jump pass.) 3618334Speter 3718334Speter Instructions to set the condition codes are omitted when it can be 3818334Speter seen that the condition codes already had the desired values. 3918334Speter 4018334Speter In some cases it is sufficient if the inherited condition codes 4118334Speter have related values, but this may require the following insn 4218334Speter (the one that tests the condition codes) to be modified. 4318334Speter 4418334Speter The code for the function prologue and epilogue are generated 4590087Sobrien directly in assembler by the target functions function_prologue and 4690087Sobrien function_epilogue. Those instructions never exist as rtl. */ 4718334Speter 4818334Speter#include "config.h" 4950503Sobrien#include "system.h" 50132727Skan#include "coretypes.h" 51132727Skan#include "tm.h" 5218334Speter 5318334Speter#include "tree.h" 5418334Speter#include "rtl.h" 5590087Sobrien#include "tm_p.h" 5618334Speter#include "regs.h" 5718334Speter#include "insn-config.h" 5818334Speter#include "insn-attr.h" 5918334Speter#include "recog.h" 6018334Speter#include "conditions.h" 6118334Speter#include "flags.h" 6218334Speter#include "real.h" 6318334Speter#include "hard-reg-set.h" 6418334Speter#include "output.h" 6550503Sobrien#include "except.h" 6690087Sobrien#include "function.h" 6750503Sobrien#include "toplev.h" 6850503Sobrien#include "reload.h" 6952515Sobrien#include "intl.h" 7090087Sobrien#include "basic-block.h" 7190087Sobrien#include "target.h" 7290087Sobrien#include "debug.h" 7390087Sobrien#include "expr.h" 74117404Skan#include "cfglayout.h" 75169699Skan#include "tree-pass.h" 76169699Skan#include "timevar.h" 77169699Skan#include "cgraph.h" 78169699Skan#include "coverage.h" 7918334Speter 8018334Speter#ifdef XCOFF_DEBUGGING_INFO 8190087Sobrien#include "xcoffout.h" /* Needed for external data 8290087Sobrien declarations for e.g. AIX 4.x. */ 8318334Speter#endif 8418334Speter 8550503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO) 8650503Sobrien#include "dwarf2out.h" 8750503Sobrien#endif 8850503Sobrien 89132727Skan#ifdef DBX_DEBUGGING_INFO 90132727Skan#include "dbxout.h" 91132727Skan#endif 92132727Skan 93169699Skan#ifdef SDB_DEBUGGING_INFO 94169699Skan#include "sdbout.h" 95169699Skan#endif 96169699Skan 9718334Speter/* If we aren't using cc0, CC_STATUS_INIT shouldn't exist. So define a 9818334Speter null default for it to save conditionalization later. */ 9918334Speter#ifndef CC_STATUS_INIT 10018334Speter#define CC_STATUS_INIT 10118334Speter#endif 10218334Speter 10318334Speter/* How to start an assembler comment. */ 10418334Speter#ifndef ASM_COMMENT_START 10518334Speter#define ASM_COMMENT_START ";#" 10618334Speter#endif 10718334Speter 10818334Speter/* Is the given character a logical line separator for the assembler? */ 10918334Speter#ifndef IS_ASM_LOGICAL_LINE_SEPARATOR 11018334Speter#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';') 11118334Speter#endif 11218334Speter 11350503Sobrien#ifndef JUMP_TABLES_IN_TEXT_SECTION 11450503Sobrien#define JUMP_TABLES_IN_TEXT_SECTION 0 11550503Sobrien#endif 11650503Sobrien 117132727Skan/* Bitflags used by final_scan_insn. */ 118132727Skan#define SEEN_BB 1 119132727Skan#define SEEN_NOTE 2 120132727Skan#define SEEN_EMITTED 4 121132727Skan 12218334Speter/* Last insn processed by final_scan_insn. */ 12390087Sobrienstatic rtx debug_insn; 12490087Sobrienrtx current_output_insn; 12518334Speter 12618334Speter/* Line number of last NOTE. */ 12718334Speterstatic int last_linenum; 12818334Speter 12918334Speter/* Highest line number in current block. */ 13018334Speterstatic int high_block_linenum; 13118334Speter 13218334Speter/* Likewise for function. */ 13318334Speterstatic int high_function_linenum; 13418334Speter 13518334Speter/* Filename of last NOTE. */ 13690087Sobrienstatic const char *last_filename; 13718334Speter 138169699Skan/* Whether to force emission of a line note before the next insn. */ 139169699Skanstatic bool force_source_line = false; 14050503Sobrien 141169699Skanextern const int length_unit_log; /* This is defined in insn-attrtab.c. */ 142169699Skan 14318334Speter/* Nonzero while outputting an `asm' with operands. 144169699Skan This means that inconsistencies are the user's fault, so don't die. 14518334Speter The precise value is the insn being output, to pass to error_for_asm. */ 146117404Skanrtx this_is_asm_operands; 14718334Speter 14818334Speter/* Number of operands of this insn, for an `asm' with operands. */ 14950503Sobrienstatic unsigned int insn_noperands; 15018334Speter 15118334Speter/* Compare optimization flag. */ 15218334Speter 15318334Speterstatic rtx last_ignored_compare = 0; 15418334Speter 15518334Speter/* Assign a unique number to each insn that is output. 15618334Speter This can be used to generate unique local labels. */ 15718334Speter 15818334Speterstatic int insn_counter = 0; 15918334Speter 16018334Speter#ifdef HAVE_cc0 16118334Speter/* This variable contains machine-dependent flags (defined in tm.h) 16218334Speter set and examined by output routines 16318334Speter that describe how to interpret the condition codes properly. */ 16418334Speter 16518334SpeterCC_STATUS cc_status; 16618334Speter 16718334Speter/* During output of an insn, this contains a copy of cc_status 16818334Speter from before the insn. */ 16918334Speter 17018334SpeterCC_STATUS cc_prev_status; 17118334Speter#endif 17218334Speter 17318334Speter/* Indexed by hardware reg number, is 1 if that register is ever 17418334Speter used in the current function. 17518334Speter 17618334Speter In life_analysis, or in stupid_life_analysis, this is set 17718334Speter up to record the hard regs used explicitly. Reload adds 17818334Speter in the hard regs used for holding pseudo regs. Final uses 17918334Speter it to generate the code in the function prologue and epilogue 18018334Speter to save and restore registers as needed. */ 18118334Speter 18218334Speterchar regs_ever_live[FIRST_PSEUDO_REGISTER]; 18318334Speter 184132727Skan/* Like regs_ever_live, but 1 if a reg is set or clobbered from an asm. 185132727Skan Unlike regs_ever_live, elements of this array corresponding to 186132727Skan eliminable regs like the frame pointer are set if an asm sets them. */ 187132727Skan 188132727Skanchar regs_asm_clobbered[FIRST_PSEUDO_REGISTER]; 189132727Skan 19018334Speter/* Nonzero means current function must be given a frame pointer. 191132727Skan Initialized in function.c to 0. Set only in reload1.c as per 192132727Skan the needs of the function. */ 19318334Speter 19418334Speterint frame_pointer_needed; 19518334Speter 19690087Sobrien/* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen. */ 19718334Speter 19818334Speterstatic int block_depth; 19918334Speter 20018334Speter/* Nonzero if have enabled APP processing of our assembler output. */ 20118334Speter 20218334Speterstatic int app_on; 20318334Speter 20418334Speter/* If we are outputting an insn sequence, this contains the sequence rtx. 20518334Speter Zero otherwise. */ 20618334Speter 20718334Speterrtx final_sequence; 20818334Speter 20918334Speter#ifdef ASSEMBLER_DIALECT 21018334Speter 21118334Speter/* Number of the assembler dialect to use, starting at 0. */ 21218334Speterstatic int dialect_number; 21318334Speter#endif 21418334Speter 21590087Sobrien#ifdef HAVE_conditional_execution 21690087Sobrien/* Nonnull if the insn currently being emitted was a COND_EXEC pattern. */ 21790087Sobrienrtx current_insn_predicate; 21890087Sobrien#endif 21918334Speter 22050503Sobrien#ifdef HAVE_ATTR_length 221132727Skanstatic int asm_insn_count (rtx); 22250503Sobrien#endif 223132727Skanstatic void profile_function (FILE *); 224132727Skanstatic void profile_after_prologue (FILE *); 225132727Skanstatic bool notice_source_line (rtx); 226132727Skanstatic rtx walk_alter_subreg (rtx *); 227132727Skanstatic void output_asm_name (void); 228132727Skanstatic void output_alternate_entry_point (FILE *, rtx); 229132727Skanstatic tree get_mem_expr_from_op (rtx, int *); 230132727Skanstatic void output_asm_operand_names (rtx *, int *, int); 231132727Skanstatic void output_operand (rtx, int); 23250503Sobrien#ifdef LEAF_REGISTERS 233132727Skanstatic void leaf_renumber_regs (rtx); 23450503Sobrien#endif 23550503Sobrien#ifdef HAVE_cc0 236132727Skanstatic int alter_cond (rtx); 23750503Sobrien#endif 23890087Sobrien#ifndef ADDR_VEC_ALIGN 239132727Skanstatic int final_addr_vec_align (rtx); 24090087Sobrien#endif 24190087Sobrien#ifdef HAVE_ATTR_length 242132727Skanstatic int align_fuzz (rtx, rtx, int, unsigned); 24390087Sobrien#endif 24418334Speter 24518334Speter/* Initialize data in final at the beginning of a compilation. */ 24618334Speter 24718334Spetervoid 248132727Skaninit_final (const char *filename ATTRIBUTE_UNUSED) 24918334Speter{ 25018334Speter app_on = 0; 25118334Speter final_sequence = 0; 25218334Speter 25318334Speter#ifdef ASSEMBLER_DIALECT 25418334Speter dialect_number = ASSEMBLER_DIALECT; 25518334Speter#endif 25618334Speter} 25718334Speter 25890087Sobrien/* Default target function prologue and epilogue assembler output. 25918334Speter 26090087Sobrien If not overridden for epilogue code, then the function body itself 26190087Sobrien contains return instructions wherever needed. */ 26290087Sobrienvoid 263132727Skandefault_function_pro_epilogue (FILE *file ATTRIBUTE_UNUSED, 264132727Skan HOST_WIDE_INT size ATTRIBUTE_UNUSED) 26590087Sobrien{ 26690087Sobrien} 26718334Speter 26890087Sobrien/* Default target hook that outputs nothing to a stream. */ 26990087Sobrienvoid 270132727Skanno_asm_to_stream (FILE *file ATTRIBUTE_UNUSED) 27190087Sobrien{ 27218334Speter} 27318334Speter 27418334Speter/* Enable APP processing of subsequent output. 27518334Speter Used before the output from an `asm' statement. */ 27618334Speter 27718334Spetervoid 278132727Skanapp_enable (void) 27918334Speter{ 28018334Speter if (! app_on) 28118334Speter { 28250503Sobrien fputs (ASM_APP_ON, asm_out_file); 28318334Speter app_on = 1; 28418334Speter } 28518334Speter} 28618334Speter 28718334Speter/* Disable APP processing of subsequent output. 28818334Speter Called from varasm.c before most kinds of output. */ 28918334Speter 29018334Spetervoid 291132727Skanapp_disable (void) 29218334Speter{ 29318334Speter if (app_on) 29418334Speter { 29550503Sobrien fputs (ASM_APP_OFF, asm_out_file); 29618334Speter app_on = 0; 29718334Speter } 29818334Speter} 29918334Speter 30090087Sobrien/* Return the number of slots filled in the current 30118334Speter delayed branch sequence (we don't count the insn needing the 30218334Speter delay slot). Zero if not in a delayed branch sequence. */ 30318334Speter 30418334Speter#ifdef DELAY_SLOTS 30518334Speterint 306132727Skandbr_sequence_length (void) 30718334Speter{ 30818334Speter if (final_sequence != 0) 30918334Speter return XVECLEN (final_sequence, 0) - 1; 31018334Speter else 31118334Speter return 0; 31218334Speter} 31318334Speter#endif 31418334Speter 31518334Speter/* The next two pages contain routines used to compute the length of an insn 31618334Speter and to shorten branches. */ 31718334Speter 31818334Speter/* Arrays for insn lengths, and addresses. The latter is referenced by 31918334Speter `insn_current_length'. */ 32018334Speter 32190087Sobrienstatic int *insn_lengths; 32218334Speter 32390087Sobrienvarray_type insn_addresses_; 32490087Sobrien 32552515Sobrien/* Max uid for which the above arrays are valid. */ 32652515Sobrienstatic int insn_lengths_max_uid; 32752515Sobrien 32818334Speter/* Address of insn being processed. Used by `insn_current_length'. */ 32918334Speterint insn_current_address; 33018334Speter 33150503Sobrien/* Address of insn being processed in previous iteration. */ 33250503Sobrienint insn_last_address; 33350503Sobrien 33490087Sobrien/* known invariant alignment of insn being processed. */ 33550503Sobrienint insn_current_align; 33650503Sobrien 33750503Sobrien/* After shorten_branches, for any insn, uid_align[INSN_UID (insn)] 33850503Sobrien gives the next following alignment insn that increases the known 33950503Sobrien alignment, or NULL_RTX if there is no such insn. 34050503Sobrien For any alignment obtained this way, we can again index uid_align with 34150503Sobrien its uid to obtain the next following align that in turn increases the 34250503Sobrien alignment, till we reach NULL_RTX; the sequence obtained this way 34350503Sobrien for each insn we'll call the alignment chain of this insn in the following 34450503Sobrien comments. */ 34550503Sobrien 346260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 347260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 34850503Sobrienstatic rtx *uid_align; 34950503Sobrienstatic int *uid_shuid; 350260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 35150503Sobrien 352260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 353260919Spfg 35418334Speter/* Indicate that branch shortening hasn't yet been done. */ 35518334Speter 35618334Spetervoid 357132727Skaninit_insn_lengths (void) 35818334Speter{ 35950503Sobrien if (uid_shuid) 36050503Sobrien { 36150503Sobrien free (uid_shuid); 36250503Sobrien uid_shuid = 0; 36350503Sobrien } 36450503Sobrien if (insn_lengths) 36550503Sobrien { 36650503Sobrien free (insn_lengths); 36750503Sobrien insn_lengths = 0; 36852515Sobrien insn_lengths_max_uid = 0; 36950503Sobrien } 37090087Sobrien#ifdef HAVE_ATTR_length 37190087Sobrien INSN_ADDRESSES_FREE (); 37290087Sobrien#endif 37350503Sobrien if (uid_align) 37450503Sobrien { 37550503Sobrien free (uid_align); 37650503Sobrien uid_align = 0; 37750503Sobrien } 37818334Speter} 37918334Speter 38018334Speter/* Obtain the current length of an insn. If branch shortening has been done, 381169699Skan get its actual length. Otherwise, use FALLBACK_FN to calculate the 382169699Skan length. */ 383169699Skanstatic inline int 384169699Skanget_attr_length_1 (rtx insn ATTRIBUTE_UNUSED, 385169699Skan int (*fallback_fn) (rtx) ATTRIBUTE_UNUSED) 38618334Speter{ 38718334Speter#ifdef HAVE_ATTR_length 38818334Speter rtx body; 38918334Speter int i; 39018334Speter int length = 0; 39118334Speter 39252515Sobrien if (insn_lengths_max_uid > INSN_UID (insn)) 39318334Speter return insn_lengths[INSN_UID (insn)]; 39418334Speter else 39518334Speter switch (GET_CODE (insn)) 39618334Speter { 39718334Speter case NOTE: 39818334Speter case BARRIER: 39918334Speter case CODE_LABEL: 40018334Speter return 0; 40118334Speter 40218334Speter case CALL_INSN: 403169699Skan length = fallback_fn (insn); 40418334Speter break; 40518334Speter 40618334Speter case JUMP_INSN: 40718334Speter body = PATTERN (insn); 408117404Skan if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) 40918334Speter { 41050503Sobrien /* Alignment is machine-dependent and should be handled by 41150503Sobrien ADDR_VEC_ALIGN. */ 41218334Speter } 41318334Speter else 414169699Skan length = fallback_fn (insn); 41518334Speter break; 41618334Speter 41718334Speter case INSN: 41818334Speter body = PATTERN (insn); 41918334Speter if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER) 42018334Speter return 0; 42118334Speter 42218334Speter else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0) 423169699Skan length = asm_insn_count (body) * fallback_fn (insn); 42418334Speter else if (GET_CODE (body) == SEQUENCE) 42518334Speter for (i = 0; i < XVECLEN (body, 0); i++) 42618334Speter length += get_attr_length (XVECEXP (body, 0, i)); 42718334Speter else 428169699Skan length = fallback_fn (insn); 42950503Sobrien break; 43050503Sobrien 43150503Sobrien default: 43250503Sobrien break; 43318334Speter } 43418334Speter 43518334Speter#ifdef ADJUST_INSN_LENGTH 43618334Speter ADJUST_INSN_LENGTH (insn, length); 43718334Speter#endif 43818334Speter return length; 43918334Speter#else /* not HAVE_ATTR_length */ 44018334Speter return 0; 441169699Skan#define insn_default_length 0 442169699Skan#define insn_min_length 0 44318334Speter#endif /* not HAVE_ATTR_length */ 44418334Speter} 445169699Skan 446169699Skan/* Obtain the current length of an insn. If branch shortening has been done, 447169699Skan get its actual length. Otherwise, get its maximum length. */ 448169699Skanint 449169699Skanget_attr_length (rtx insn) 450169699Skan{ 451169699Skan return get_attr_length_1 (insn, insn_default_length); 452169699Skan} 453169699Skan 454169699Skan/* Obtain the current length of an insn. If branch shortening has been done, 455169699Skan get its actual length. Otherwise, get its minimum length. */ 456169699Skanint 457169699Skanget_attr_min_length (rtx insn) 458169699Skan{ 459169699Skan return get_attr_length_1 (insn, insn_min_length); 460169699Skan} 46118334Speter 46250503Sobrien/* Code to handle alignment inside shorten_branches. */ 46350503Sobrien 46450503Sobrien/* Here is an explanation how the algorithm in align_fuzz can give 46550503Sobrien proper results: 46650503Sobrien 46750503Sobrien Call a sequence of instructions beginning with alignment point X 46850503Sobrien and continuing until the next alignment point `block X'. When `X' 46990087Sobrien is used in an expression, it means the alignment value of the 47050503Sobrien alignment point. 47190087Sobrien 47250503Sobrien Call the distance between the start of the first insn of block X, and 47350503Sobrien the end of the last insn of block X `IX', for the `inner size of X'. 47450503Sobrien This is clearly the sum of the instruction lengths. 47590087Sobrien 47650503Sobrien Likewise with the next alignment-delimited block following X, which we 47750503Sobrien shall call block Y. 47890087Sobrien 47950503Sobrien Call the distance between the start of the first insn of block X, and 48050503Sobrien the start of the first insn of block Y `OX', for the `outer size of X'. 48190087Sobrien 48250503Sobrien The estimated padding is then OX - IX. 48390087Sobrien 48450503Sobrien OX can be safely estimated as 48590087Sobrien 48650503Sobrien if (X >= Y) 48750503Sobrien OX = round_up(IX, Y) 48850503Sobrien else 48950503Sobrien OX = round_up(IX, X) + Y - X 49090087Sobrien 49150503Sobrien Clearly est(IX) >= real(IX), because that only depends on the 49250503Sobrien instruction lengths, and those being overestimated is a given. 49390087Sobrien 49450503Sobrien Clearly round_up(foo, Z) >= round_up(bar, Z) if foo >= bar, so 49550503Sobrien we needn't worry about that when thinking about OX. 49690087Sobrien 49750503Sobrien When X >= Y, the alignment provided by Y adds no uncertainty factor 49850503Sobrien for branch ranges starting before X, so we can just round what we have. 49950503Sobrien But when X < Y, we don't know anything about the, so to speak, 50050503Sobrien `middle bits', so we have to assume the worst when aligning up from an 50150503Sobrien address mod X to one mod Y, which is Y - X. */ 50250503Sobrien 50350503Sobrien#ifndef LABEL_ALIGN 50490087Sobrien#define LABEL_ALIGN(LABEL) align_labels_log 50550503Sobrien#endif 50650503Sobrien 50750503Sobrien#ifndef LABEL_ALIGN_MAX_SKIP 50890087Sobrien#define LABEL_ALIGN_MAX_SKIP align_labels_max_skip 50950503Sobrien#endif 51050503Sobrien 51150503Sobrien#ifndef LOOP_ALIGN 51290087Sobrien#define LOOP_ALIGN(LABEL) align_loops_log 51350503Sobrien#endif 51450503Sobrien 51550503Sobrien#ifndef LOOP_ALIGN_MAX_SKIP 51690087Sobrien#define LOOP_ALIGN_MAX_SKIP align_loops_max_skip 51750503Sobrien#endif 51850503Sobrien 51950503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER 52050503Sobrien#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0 52150503Sobrien#endif 52250503Sobrien 52350503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 52450503Sobrien#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0 52550503Sobrien#endif 52650503Sobrien 52790087Sobrien#ifndef JUMP_ALIGN 52890087Sobrien#define JUMP_ALIGN(LABEL) align_jumps_log 52990087Sobrien#endif 53090087Sobrien 53190087Sobrien#ifndef JUMP_ALIGN_MAX_SKIP 53290087Sobrien#define JUMP_ALIGN_MAX_SKIP align_jumps_max_skip 53390087Sobrien#endif 53490087Sobrien 53550503Sobrien#ifndef ADDR_VEC_ALIGN 53690087Sobrienstatic int 537132727Skanfinal_addr_vec_align (rtx addr_vec) 53850503Sobrien{ 53990087Sobrien int align = GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec))); 54050503Sobrien 54150503Sobrien if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT) 54250503Sobrien align = BIGGEST_ALIGNMENT / BITS_PER_UNIT; 54390087Sobrien return exact_log2 (align); 54450503Sobrien 54550503Sobrien} 54690087Sobrien 54750503Sobrien#define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC) 54850503Sobrien#endif 54950503Sobrien 55050503Sobrien#ifndef INSN_LENGTH_ALIGNMENT 55150503Sobrien#define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log 55250503Sobrien#endif 55350503Sobrien 55450503Sobrien#define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)]) 55550503Sobrien 556260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 557260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 55850503Sobrien/* For the benefit of port specific code do this also as a function. */ 55990087Sobrien 56050503Sobrienint 561132727Skanlabel_to_alignment (rtx label) 56250503Sobrien{ 563260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 564260919Spfg return LABEL_ALIGN_LOG (label); 565260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 56650503Sobrien} 56750503Sobrien 56850503Sobrien#ifdef HAVE_ATTR_length 56950503Sobrien/* The differences in addresses 57050503Sobrien between a branch and its target might grow or shrink depending on 57150503Sobrien the alignment the start insn of the range (the branch for a forward 57250503Sobrien branch or the label for a backward branch) starts out on; if these 57350503Sobrien differences are used naively, they can even oscillate infinitely. 57450503Sobrien We therefore want to compute a 'worst case' address difference that 57550503Sobrien is independent of the alignment the start insn of the range end 57650503Sobrien up on, and that is at least as large as the actual difference. 57750503Sobrien The function align_fuzz calculates the amount we have to add to the 57850503Sobrien naively computed difference, by traversing the part of the alignment 57950503Sobrien chain of the start insn of the range that is in front of the end insn 58050503Sobrien of the range, and considering for each alignment the maximum amount 58150503Sobrien that it might contribute to a size increase. 58250503Sobrien 58350503Sobrien For casesi tables, we also want to know worst case minimum amounts of 58450503Sobrien address difference, in case a machine description wants to introduce 58550503Sobrien some common offset that is added to all offsets in a table. 58690087Sobrien For this purpose, align_fuzz with a growth argument of 0 computes the 58750503Sobrien appropriate adjustment. */ 58850503Sobrien 58950503Sobrien/* Compute the maximum delta by which the difference of the addresses of 59050503Sobrien START and END might grow / shrink due to a different address for start 59150503Sobrien which changes the size of alignment insns between START and END. 59250503Sobrien KNOWN_ALIGN_LOG is the alignment known for START. 59350503Sobrien GROWTH should be ~0 if the objective is to compute potential code size 59450503Sobrien increase, and 0 if the objective is to compute potential shrink. 59550503Sobrien The return value is undefined for any other value of GROWTH. */ 59690087Sobrien 59790087Sobrienstatic int 598132727Skanalign_fuzz (rtx start, rtx end, int known_align_log, unsigned int growth) 59950503Sobrien{ 60050503Sobrien int uid = INSN_UID (start); 60150503Sobrien rtx align_label; 60250503Sobrien int known_align = 1 << known_align_log; 60350503Sobrien int end_shuid = INSN_SHUID (end); 60450503Sobrien int fuzz = 0; 60550503Sobrien 60650503Sobrien for (align_label = uid_align[uid]; align_label; align_label = uid_align[uid]) 60750503Sobrien { 60850503Sobrien int align_addr, new_align; 60950503Sobrien 61050503Sobrien uid = INSN_UID (align_label); 61190087Sobrien align_addr = INSN_ADDRESSES (uid) - insn_lengths[uid]; 61250503Sobrien if (uid_shuid[uid] > end_shuid) 61350503Sobrien break; 614260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 615260919Spfg known_align_log = LABEL_ALIGN_LOG (align_label); 616260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 61750503Sobrien new_align = 1 << known_align_log; 61850503Sobrien if (new_align < known_align) 61950503Sobrien continue; 62050503Sobrien fuzz += (-align_addr ^ growth) & (new_align - known_align); 62150503Sobrien known_align = new_align; 62250503Sobrien } 62350503Sobrien return fuzz; 62450503Sobrien} 62550503Sobrien 62650503Sobrien/* Compute a worst-case reference address of a branch so that it 62750503Sobrien can be safely used in the presence of aligned labels. Since the 62850503Sobrien size of the branch itself is unknown, the size of the branch is 62950503Sobrien not included in the range. I.e. for a forward branch, the reference 63050503Sobrien address is the end address of the branch as known from the previous 63150503Sobrien branch shortening pass, minus a value to account for possible size 63250503Sobrien increase due to alignment. For a backward branch, it is the start 63350503Sobrien address of the branch as known from the current pass, plus a value 63450503Sobrien to account for possible size increase due to alignment. 63550503Sobrien NB.: Therefore, the maximum offset allowed for backward branches needs 63650503Sobrien to exclude the branch size. */ 63790087Sobrien 63850503Sobrienint 639132727Skaninsn_current_reference_address (rtx branch) 64050503Sobrien{ 64190087Sobrien rtx dest, seq; 64290087Sobrien int seq_uid; 64390087Sobrien 64490087Sobrien if (! INSN_ADDRESSES_SET_P ()) 64590087Sobrien return 0; 64690087Sobrien 64790087Sobrien seq = NEXT_INSN (PREV_INSN (branch)); 64890087Sobrien seq_uid = INSN_UID (seq); 649169699Skan if (!JUMP_P (branch)) 65050503Sobrien /* This can happen for example on the PA; the objective is to know the 65150503Sobrien offset to address something in front of the start of the function. 65250503Sobrien Thus, we can treat it like a backward branch. 65350503Sobrien We assume here that FUNCTION_BOUNDARY / BITS_PER_UNIT is larger than 65450503Sobrien any alignment we'd encounter, so we skip the call to align_fuzz. */ 65550503Sobrien return insn_current_address; 65650503Sobrien dest = JUMP_LABEL (branch); 65790087Sobrien 65890087Sobrien /* BRANCH has no proper alignment chain set, so use SEQ. 65990087Sobrien BRANCH also has no INSN_SHUID. */ 66090087Sobrien if (INSN_SHUID (seq) < INSN_SHUID (dest)) 66150503Sobrien { 66290087Sobrien /* Forward branch. */ 66350503Sobrien return (insn_last_address + insn_lengths[seq_uid] 66450503Sobrien - align_fuzz (seq, dest, length_unit_log, ~0)); 66550503Sobrien } 66650503Sobrien else 66750503Sobrien { 66890087Sobrien /* Backward branch. */ 66950503Sobrien return (insn_current_address 67050503Sobrien + align_fuzz (dest, seq, length_unit_log, ~0)); 67150503Sobrien } 67250503Sobrien} 67350503Sobrien#endif /* HAVE_ATTR_length */ 67450503Sobrien 675169699Skan/* Compute branch alignments based on frequency information in the 676169699Skan CFG. */ 677169699Skan 678169699Skanstatic unsigned int 679132727Skancompute_alignments (void) 68090087Sobrien{ 681260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 682260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 683117404Skan basic_block bb; 68490087Sobrien 685260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 686260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 68790087Sobrien 68890087Sobrien /* If not optimizing or optimizing for size, don't assign any alignments. */ 68990087Sobrien if (! optimize || optimize_size) 690169699Skan return 0; 69190087Sobrien 692117404Skan FOR_EACH_BB (bb) 69390087Sobrien { 694132727Skan rtx label = BB_HEAD (bb); 69590087Sobrien int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0; 69690087Sobrien edge e; 697169699Skan edge_iterator ei; 698260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 699260919Spfg int log, max_skip, max_log; 70090087Sobrien 701260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 702169699Skan if (!LABEL_P (label) 703132727Skan || probably_never_executed_bb_p (bb)) 70490087Sobrien continue; 705260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 706260919Spfg /* If user has specified an alignment, honour it. */ 707260919Spfg if (LABEL_ALIGN_LOG (label) > 0) 708260919Spfg continue; 709260919Spfg 710260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 71190087Sobrien max_log = LABEL_ALIGN (label); 71290087Sobrien max_skip = LABEL_ALIGN_MAX_SKIP; 71390087Sobrien 714169699Skan FOR_EACH_EDGE (e, ei, bb->preds) 71590087Sobrien { 71690087Sobrien if (e->flags & EDGE_FALLTHRU) 71790087Sobrien has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e); 71890087Sobrien else 71990087Sobrien branch_frequency += EDGE_FREQUENCY (e); 72090087Sobrien } 72190087Sobrien 72290087Sobrien /* There are two purposes to align block with no fallthru incoming edge: 72390087Sobrien 1) to avoid fetch stalls when branch destination is near cache boundary 72490087Sobrien 2) to improve cache efficiency in case the previous block is not executed 72590087Sobrien (so it does not need to be in the cache). 72690087Sobrien 72790087Sobrien We to catch first case, we align frequently executed blocks. 72890087Sobrien To catch the second, we align blocks that are executed more frequently 72990087Sobrien than the predecessor and the predecessor is likely to not be executed 73090087Sobrien when function is called. */ 73190087Sobrien 73290087Sobrien if (!has_fallthru 73390087Sobrien && (branch_frequency > BB_FREQ_MAX / 10 734117404Skan || (bb->frequency > bb->prev_bb->frequency * 10 735117404Skan && (bb->prev_bb->frequency 73690087Sobrien <= ENTRY_BLOCK_PTR->frequency / 2)))) 73790087Sobrien { 73890087Sobrien log = JUMP_ALIGN (label); 73990087Sobrien if (max_log < log) 74090087Sobrien { 74190087Sobrien max_log = log; 74290087Sobrien max_skip = JUMP_ALIGN_MAX_SKIP; 74390087Sobrien } 74490087Sobrien } 74590087Sobrien /* In case block is frequent and reached mostly by non-fallthru edge, 746117404Skan align it. It is most likely a first block of loop. */ 74790087Sobrien if (has_fallthru 748132727Skan && maybe_hot_bb_p (bb) 74990087Sobrien && branch_frequency + fallthru_frequency > BB_FREQ_MAX / 10 750117404Skan && branch_frequency > fallthru_frequency * 2) 75190087Sobrien { 75290087Sobrien log = LOOP_ALIGN (label); 75390087Sobrien if (max_log < log) 75490087Sobrien { 75590087Sobrien max_log = log; 75690087Sobrien max_skip = LOOP_ALIGN_MAX_SKIP; 75790087Sobrien } 75890087Sobrien } 759260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 760260919Spfg SET_LABEL_ALIGN (label, max_log, max_skip); 761260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 76290087Sobrien } 763169699Skan return 0; 76490087Sobrien} 765169699Skan 766169699Skanstruct tree_opt_pass pass_compute_alignments = 767169699Skan{ 768169699Skan NULL, /* name */ 769169699Skan NULL, /* gate */ 770169699Skan compute_alignments, /* execute */ 771169699Skan NULL, /* sub */ 772169699Skan NULL, /* next */ 773169699Skan 0, /* static_pass_number */ 774169699Skan 0, /* tv_id */ 775169699Skan 0, /* properties_required */ 776169699Skan 0, /* properties_provided */ 777169699Skan 0, /* properties_destroyed */ 778169699Skan 0, /* todo_flags_start */ 779169699Skan 0, /* todo_flags_finish */ 780169699Skan 0 /* letter */ 781169699Skan}; 782169699Skan 78390087Sobrien 78418334Speter/* Make a pass over all insns and compute their actual lengths by shortening 78518334Speter any branches of variable length if possible. */ 78618334Speter 78750503Sobrien/* shorten_branches might be called multiple times: for example, the SH 78850503Sobrien port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG. 78950503Sobrien In order to do this, it needs proper length information, which it obtains 79050503Sobrien by calling shorten_branches. This cannot be collapsed with 79190087Sobrien shorten_branches itself into a single pass unless we also want to integrate 79250503Sobrien reorg.c, since the branch splitting exposes new instructions with delay 79350503Sobrien slots. */ 79450503Sobrien 79518334Spetervoid 796132727Skanshorten_branches (rtx first ATTRIBUTE_UNUSED) 79718334Speter{ 79850503Sobrien rtx insn; 79950503Sobrien int max_uid; 80050503Sobrien int i; 80150503Sobrien int max_log; 80250503Sobrien int max_skip; 80318334Speter#ifdef HAVE_ATTR_length 80450503Sobrien#define MAX_CODE_ALIGN 16 80550503Sobrien rtx seq; 80618334Speter int something_changed = 1; 80718334Speter char *varying_length; 80818334Speter rtx body; 80918334Speter int uid; 81050503Sobrien rtx align_tab[MAX_CODE_ALIGN]; 81118334Speter 81250503Sobrien#endif 81318334Speter 814260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 815260919Spfg /* Compute maximum UID and allocate uid_shuid. */ 816260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 81750503Sobrien max_uid = get_max_uid (); 81850503Sobrien 819169699Skan /* Free uid_shuid before reallocating it. */ 820169699Skan free (uid_shuid); 82150503Sobrien 822169699Skan uid_shuid = XNEWVEC (int, max_uid); 823169699Skan 824260919Spfg /* APPLE LOCAL for-fsf-4_4 3274130 5295549 */ \ 825260919Spfg /* Initialize set up uid_shuid to be strictly 82650503Sobrien monotonically rising with insn order. */ 82750503Sobrien /* We use max_log here to keep track of the maximum alignment we want to 82850503Sobrien impose on the next CODE_LABEL (or the current one if we are processing 82950503Sobrien the CODE_LABEL itself). */ 83090087Sobrien 83150503Sobrien max_log = 0; 83250503Sobrien max_skip = 0; 83350503Sobrien 83450503Sobrien for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn)) 83550503Sobrien { 83650503Sobrien int log; 83750503Sobrien 83850503Sobrien INSN_SHUID (insn) = i++; 83990087Sobrien if (INSN_P (insn)) 840169699Skan continue; 841169699Skan 842169699Skan if (LABEL_P (insn)) 84350503Sobrien { 84450503Sobrien rtx next; 84550503Sobrien 84690087Sobrien /* Merge in alignments computed by compute_alignments. */ 847260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 848260919Spfg log = LABEL_ALIGN_LOG (insn); 849260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 85090087Sobrien if (max_log < log) 85190087Sobrien { 85290087Sobrien max_log = log; 853260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 854260919Spfg max_skip = LABEL_MAX_SKIP (insn); 855260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 85690087Sobrien } 85790087Sobrien 85850503Sobrien log = LABEL_ALIGN (insn); 85950503Sobrien if (max_log < log) 86050503Sobrien { 86150503Sobrien max_log = log; 86250503Sobrien max_skip = LABEL_ALIGN_MAX_SKIP; 86350503Sobrien } 864169699Skan next = next_nonnote_insn (insn); 86550503Sobrien /* ADDR_VECs only take room if read-only data goes into the text 86650503Sobrien section. */ 867169699Skan if (JUMP_TABLES_IN_TEXT_SECTION 868169699Skan || readonly_data_section == text_section) 869169699Skan if (next && JUMP_P (next)) 87050503Sobrien { 87150503Sobrien rtx nextbody = PATTERN (next); 87250503Sobrien if (GET_CODE (nextbody) == ADDR_VEC 87350503Sobrien || GET_CODE (nextbody) == ADDR_DIFF_VEC) 87450503Sobrien { 87550503Sobrien log = ADDR_VEC_ALIGN (next); 87650503Sobrien if (max_log < log) 87750503Sobrien { 87850503Sobrien max_log = log; 87950503Sobrien max_skip = LABEL_ALIGN_MAX_SKIP; 88050503Sobrien } 88150503Sobrien } 88250503Sobrien } 883260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 884260919Spfg SET_LABEL_ALIGN (insn, max_log, max_skip); 885260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 88650503Sobrien max_log = 0; 88750503Sobrien max_skip = 0; 88850503Sobrien } 889169699Skan else if (BARRIER_P (insn)) 89050503Sobrien { 89150503Sobrien rtx label; 89250503Sobrien 89390087Sobrien for (label = insn; label && ! INSN_P (label); 89450503Sobrien label = NEXT_INSN (label)) 895169699Skan if (LABEL_P (label)) 89650503Sobrien { 89750503Sobrien log = LABEL_ALIGN_AFTER_BARRIER (insn); 89850503Sobrien if (max_log < log) 89950503Sobrien { 90050503Sobrien max_log = log; 90150503Sobrien max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP; 90250503Sobrien } 90350503Sobrien break; 90450503Sobrien } 90550503Sobrien } 90650503Sobrien } 90750503Sobrien#ifdef HAVE_ATTR_length 90850503Sobrien 90950503Sobrien /* Allocate the rest of the arrays. */ 910169699Skan insn_lengths = XNEWVEC (int, max_uid); 91152515Sobrien insn_lengths_max_uid = max_uid; 91250503Sobrien /* Syntax errors can lead to labels being outside of the main insn stream. 91350503Sobrien Initialize insn_addresses, so that we get reproducible results. */ 91490087Sobrien INSN_ADDRESSES_ALLOC (max_uid); 91550503Sobrien 916169699Skan varying_length = XCNEWVEC (char, max_uid); 91750503Sobrien 91850503Sobrien /* Initialize uid_align. We scan instructions 91950503Sobrien from end to start, and keep in align_tab[n] the last seen insn 92050503Sobrien that does an alignment of at least n+1, i.e. the successor 92150503Sobrien in the alignment chain for an insn that does / has a known 92250503Sobrien alignment of n. */ 923169699Skan uid_align = XCNEWVEC (rtx, max_uid); 92450503Sobrien 92590087Sobrien for (i = MAX_CODE_ALIGN; --i >= 0;) 92650503Sobrien align_tab[i] = NULL_RTX; 92750503Sobrien seq = get_last_insn (); 92850503Sobrien for (; seq; seq = PREV_INSN (seq)) 92950503Sobrien { 93050503Sobrien int uid = INSN_UID (seq); 93150503Sobrien int log; 932260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 933260919Spfg log = (LABEL_P (seq) ? LABEL_ALIGN_LOG (seq) : 0); 934260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 93550503Sobrien uid_align[uid] = align_tab[0]; 93650503Sobrien if (log) 93750503Sobrien { 93850503Sobrien /* Found an alignment label. */ 93950503Sobrien uid_align[uid] = align_tab[log]; 94050503Sobrien for (i = log - 1; i >= 0; i--) 94150503Sobrien align_tab[i] = seq; 94250503Sobrien } 94350503Sobrien } 94450503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE 94550503Sobrien if (optimize) 94650503Sobrien { 94750503Sobrien /* Look for ADDR_DIFF_VECs, and initialize their minimum and maximum 94850503Sobrien label fields. */ 94950503Sobrien 95050503Sobrien int min_shuid = INSN_SHUID (get_insns ()) - 1; 95150503Sobrien int max_shuid = INSN_SHUID (get_last_insn ()) + 1; 95250503Sobrien int rel; 95350503Sobrien 95450503Sobrien for (insn = first; insn != 0; insn = NEXT_INSN (insn)) 95550503Sobrien { 95650503Sobrien rtx min_lab = NULL_RTX, max_lab = NULL_RTX, pat; 95750503Sobrien int len, i, min, max, insn_shuid; 95850503Sobrien int min_align; 95950503Sobrien addr_diff_vec_flags flags; 96050503Sobrien 961169699Skan if (!JUMP_P (insn) 96250503Sobrien || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC) 96350503Sobrien continue; 96450503Sobrien pat = PATTERN (insn); 96550503Sobrien len = XVECLEN (pat, 1); 966169699Skan gcc_assert (len > 0); 96750503Sobrien min_align = MAX_CODE_ALIGN; 96850503Sobrien for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--) 96950503Sobrien { 97050503Sobrien rtx lab = XEXP (XVECEXP (pat, 1, i), 0); 97150503Sobrien int shuid = INSN_SHUID (lab); 97250503Sobrien if (shuid < min) 97350503Sobrien { 97450503Sobrien min = shuid; 97550503Sobrien min_lab = lab; 97650503Sobrien } 97750503Sobrien if (shuid > max) 97850503Sobrien { 97950503Sobrien max = shuid; 98050503Sobrien max_lab = lab; 98150503Sobrien } 982260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 983260919Spfg if (min_align > (int) LABEL_ALIGN_LOG (lab)) 984260919Spfg min_align = LABEL_ALIGN_LOG (lab); 985260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 98650503Sobrien } 987169699Skan XEXP (pat, 2) = gen_rtx_LABEL_REF (Pmode, min_lab); 988169699Skan XEXP (pat, 3) = gen_rtx_LABEL_REF (Pmode, max_lab); 98950503Sobrien insn_shuid = INSN_SHUID (insn); 99050503Sobrien rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0)); 991169699Skan memset (&flags, 0, sizeof (flags)); 99250503Sobrien flags.min_align = min_align; 99350503Sobrien flags.base_after_vec = rel > insn_shuid; 99450503Sobrien flags.min_after_vec = min > insn_shuid; 99550503Sobrien flags.max_after_vec = max > insn_shuid; 99650503Sobrien flags.min_after_base = min > rel; 99750503Sobrien flags.max_after_base = max > rel; 99850503Sobrien ADDR_DIFF_VEC_FLAGS (pat) = flags; 99950503Sobrien } 100050503Sobrien } 100150503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */ 100250503Sobrien 100318334Speter /* Compute initial lengths, addresses, and varying flags for each insn. */ 1004132727Skan for (insn_current_address = 0, insn = first; 100518334Speter insn != 0; 100618334Speter insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn)) 100718334Speter { 100818334Speter uid = INSN_UID (insn); 100950503Sobrien 101050503Sobrien insn_lengths[uid] = 0; 101150503Sobrien 1012169699Skan if (LABEL_P (insn)) 101350503Sobrien { 1014260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 1015260919Spfg int log = LABEL_ALIGN_LOG (insn); 1016260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 101750503Sobrien if (log) 101850503Sobrien { 101950503Sobrien int align = 1 << log; 102050503Sobrien int new_address = (insn_current_address + align - 1) & -align; 102150503Sobrien insn_lengths[uid] = new_address - insn_current_address; 102250503Sobrien } 102350503Sobrien } 102450503Sobrien 1025117404Skan INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid]; 102690087Sobrien 1027169699Skan if (NOTE_P (insn) || BARRIER_P (insn) 1028169699Skan || LABEL_P (insn)) 102918334Speter continue; 103050503Sobrien if (INSN_DELETED_P (insn)) 103150503Sobrien continue; 103218334Speter 103318334Speter body = PATTERN (insn); 103418334Speter if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) 103518334Speter { 103618334Speter /* This only takes room if read-only data goes into the text 103718334Speter section. */ 1038169699Skan if (JUMP_TABLES_IN_TEXT_SECTION 1039169699Skan || readonly_data_section == text_section) 104050503Sobrien insn_lengths[uid] = (XVECLEN (body, 104150503Sobrien GET_CODE (body) == ADDR_DIFF_VEC) 104250503Sobrien * GET_MODE_SIZE (GET_MODE (body))); 104350503Sobrien /* Alignment is handled by ADDR_VEC_ALIGN. */ 104418334Speter } 104590087Sobrien else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0) 104618334Speter insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn); 104718334Speter else if (GET_CODE (body) == SEQUENCE) 104818334Speter { 104918334Speter int i; 105018334Speter int const_delay_slots; 105118334Speter#ifdef DELAY_SLOTS 105218334Speter const_delay_slots = const_num_delay_slots (XVECEXP (body, 0, 0)); 105318334Speter#else 105418334Speter const_delay_slots = 0; 105518334Speter#endif 105618334Speter /* Inside a delay slot sequence, we do not do any branch shortening 105718334Speter if the shortening could change the number of delay slots 105850503Sobrien of the branch. */ 105918334Speter for (i = 0; i < XVECLEN (body, 0); i++) 106018334Speter { 106118334Speter rtx inner_insn = XVECEXP (body, 0, i); 106218334Speter int inner_uid = INSN_UID (inner_insn); 106318334Speter int inner_length; 106418334Speter 106590087Sobrien if (GET_CODE (body) == ASM_INPUT 106690087Sobrien || asm_noperands (PATTERN (XVECEXP (body, 0, i))) >= 0) 106718334Speter inner_length = (asm_insn_count (PATTERN (inner_insn)) 106818334Speter * insn_default_length (inner_insn)); 106918334Speter else 107018334Speter inner_length = insn_default_length (inner_insn); 107190087Sobrien 107218334Speter insn_lengths[inner_uid] = inner_length; 107318334Speter if (const_delay_slots) 107418334Speter { 107518334Speter if ((varying_length[inner_uid] 107618334Speter = insn_variable_length_p (inner_insn)) != 0) 107718334Speter varying_length[uid] = 1; 107890087Sobrien INSN_ADDRESSES (inner_uid) = (insn_current_address 107990087Sobrien + insn_lengths[uid]); 108018334Speter } 108118334Speter else 108218334Speter varying_length[inner_uid] = 0; 108318334Speter insn_lengths[uid] += inner_length; 108418334Speter } 108518334Speter } 108618334Speter else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER) 108718334Speter { 108818334Speter insn_lengths[uid] = insn_default_length (insn); 108918334Speter varying_length[uid] = insn_variable_length_p (insn); 109018334Speter } 109118334Speter 109218334Speter /* If needed, do any adjustment. */ 109318334Speter#ifdef ADJUST_INSN_LENGTH 109418334Speter ADJUST_INSN_LENGTH (insn, insn_lengths[uid]); 109552515Sobrien if (insn_lengths[uid] < 0) 109690087Sobrien fatal_insn ("negative insn length", insn); 109718334Speter#endif 109818334Speter } 109918334Speter 110018334Speter /* Now loop over all the insns finding varying length insns. For each, 110118334Speter get the current insn length. If it has changed, reflect the change. 110218334Speter When nothing changes for a full pass, we are done. */ 110318334Speter 110418334Speter while (something_changed) 110518334Speter { 110618334Speter something_changed = 0; 110750503Sobrien insn_current_align = MAX_CODE_ALIGN - 1; 1108132727Skan for (insn_current_address = 0, insn = first; 110918334Speter insn != 0; 111018334Speter insn = NEXT_INSN (insn)) 111118334Speter { 111218334Speter int new_length; 111350503Sobrien#ifdef ADJUST_INSN_LENGTH 111418334Speter int tmp_length; 111550503Sobrien#endif 111650503Sobrien int length_align; 111718334Speter 111818334Speter uid = INSN_UID (insn); 111950503Sobrien 1120169699Skan if (LABEL_P (insn)) 112150503Sobrien { 1122260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 1123260919Spfg int log = LABEL_ALIGN_LOG (insn); 1124260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 112550503Sobrien if (log > insn_current_align) 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 insn_current_align = log; 113150503Sobrien insn_current_address = new_address; 113250503Sobrien } 113350503Sobrien else 113450503Sobrien insn_lengths[uid] = 0; 113590087Sobrien INSN_ADDRESSES (uid) = insn_current_address; 113650503Sobrien continue; 113750503Sobrien } 113850503Sobrien 113950503Sobrien length_align = INSN_LENGTH_ALIGNMENT (insn); 114050503Sobrien if (length_align < insn_current_align) 114150503Sobrien insn_current_align = length_align; 114250503Sobrien 114390087Sobrien insn_last_address = INSN_ADDRESSES (uid); 114490087Sobrien INSN_ADDRESSES (uid) = insn_current_address; 114550503Sobrien 114650503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE 1147169699Skan if (optimize && JUMP_P (insn) 114850503Sobrien && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC) 114918334Speter { 115050503Sobrien rtx body = PATTERN (insn); 115150503Sobrien int old_length = insn_lengths[uid]; 115250503Sobrien rtx rel_lab = XEXP (XEXP (body, 0), 0); 115350503Sobrien rtx min_lab = XEXP (XEXP (body, 2), 0); 115450503Sobrien rtx max_lab = XEXP (XEXP (body, 3), 0); 115590087Sobrien int rel_addr = INSN_ADDRESSES (INSN_UID (rel_lab)); 115690087Sobrien int min_addr = INSN_ADDRESSES (INSN_UID (min_lab)); 115790087Sobrien int max_addr = INSN_ADDRESSES (INSN_UID (max_lab)); 115850503Sobrien rtx prev; 115950503Sobrien int rel_align = 0; 116090087Sobrien addr_diff_vec_flags flags; 116150503Sobrien 116290087Sobrien /* Avoid automatic aggregate initialization. */ 116390087Sobrien flags = ADDR_DIFF_VEC_FLAGS (body); 116490087Sobrien 116550503Sobrien /* Try to find a known alignment for rel_lab. */ 116650503Sobrien for (prev = rel_lab; 116750503Sobrien prev 116850503Sobrien && ! insn_lengths[INSN_UID (prev)] 116950503Sobrien && ! (varying_length[INSN_UID (prev)] & 1); 117050503Sobrien prev = PREV_INSN (prev)) 117150503Sobrien if (varying_length[INSN_UID (prev)] & 2) 117250503Sobrien { 1173260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 1174260919Spfg rel_align = LABEL_ALIGN_LOG (prev); 1175260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 117650503Sobrien break; 117750503Sobrien } 117850503Sobrien 117950503Sobrien /* See the comment on addr_diff_vec_flags in rtl.h for the 118050503Sobrien meaning of the flags values. base: REL_LAB vec: INSN */ 118150503Sobrien /* Anything after INSN has still addresses from the last 118250503Sobrien pass; adjust these so that they reflect our current 118350503Sobrien estimate for this pass. */ 118450503Sobrien if (flags.base_after_vec) 118550503Sobrien rel_addr += insn_current_address - insn_last_address; 118650503Sobrien if (flags.min_after_vec) 118750503Sobrien min_addr += insn_current_address - insn_last_address; 118850503Sobrien if (flags.max_after_vec) 118950503Sobrien max_addr += insn_current_address - insn_last_address; 119050503Sobrien /* We want to know the worst case, i.e. lowest possible value 119150503Sobrien for the offset of MIN_LAB. If MIN_LAB is after REL_LAB, 119250503Sobrien its offset is positive, and we have to be wary of code shrink; 119350503Sobrien otherwise, it is negative, and we have to be vary of code 119450503Sobrien size increase. */ 119550503Sobrien if (flags.min_after_base) 119650503Sobrien { 119750503Sobrien /* If INSN is between REL_LAB and MIN_LAB, the size 119850503Sobrien changes we are about to make can change the alignment 119950503Sobrien within the observed offset, therefore we have to break 120050503Sobrien it up into two parts that are independent. */ 120150503Sobrien if (! flags.base_after_vec && flags.min_after_vec) 120250503Sobrien { 120350503Sobrien min_addr -= align_fuzz (rel_lab, insn, rel_align, 0); 120450503Sobrien min_addr -= align_fuzz (insn, min_lab, 0, 0); 120550503Sobrien } 120650503Sobrien else 120750503Sobrien min_addr -= align_fuzz (rel_lab, min_lab, rel_align, 0); 120850503Sobrien } 120950503Sobrien else 121050503Sobrien { 121150503Sobrien if (flags.base_after_vec && ! flags.min_after_vec) 121250503Sobrien { 121350503Sobrien min_addr -= align_fuzz (min_lab, insn, 0, ~0); 121450503Sobrien min_addr -= align_fuzz (insn, rel_lab, 0, ~0); 121550503Sobrien } 121650503Sobrien else 121750503Sobrien min_addr -= align_fuzz (min_lab, rel_lab, 0, ~0); 121850503Sobrien } 121950503Sobrien /* Likewise, determine the highest lowest possible value 122050503Sobrien for the offset of MAX_LAB. */ 122150503Sobrien if (flags.max_after_base) 122250503Sobrien { 122350503Sobrien if (! flags.base_after_vec && flags.max_after_vec) 122450503Sobrien { 122550503Sobrien max_addr += align_fuzz (rel_lab, insn, rel_align, ~0); 122650503Sobrien max_addr += align_fuzz (insn, max_lab, 0, ~0); 122750503Sobrien } 122850503Sobrien else 122950503Sobrien max_addr += align_fuzz (rel_lab, max_lab, rel_align, ~0); 123050503Sobrien } 123150503Sobrien else 123250503Sobrien { 123350503Sobrien if (flags.base_after_vec && ! flags.max_after_vec) 123450503Sobrien { 123550503Sobrien max_addr += align_fuzz (max_lab, insn, 0, 0); 123650503Sobrien max_addr += align_fuzz (insn, rel_lab, 0, 0); 123750503Sobrien } 123850503Sobrien else 123950503Sobrien max_addr += align_fuzz (max_lab, rel_lab, 0, 0); 124050503Sobrien } 124150503Sobrien PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr, 124250503Sobrien max_addr - rel_addr, 124350503Sobrien body)); 1244169699Skan if (JUMP_TABLES_IN_TEXT_SECTION 1245169699Skan || readonly_data_section == text_section) 124650503Sobrien { 124750503Sobrien insn_lengths[uid] 124850503Sobrien = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body))); 124950503Sobrien insn_current_address += insn_lengths[uid]; 125050503Sobrien if (insn_lengths[uid] != old_length) 125150503Sobrien something_changed = 1; 125250503Sobrien } 125350503Sobrien 125450503Sobrien continue; 125550503Sobrien } 125650503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */ 125750503Sobrien 125850503Sobrien if (! (varying_length[uid])) 125950503Sobrien { 1260169699Skan if (NONJUMP_INSN_P (insn) 126190087Sobrien && GET_CODE (PATTERN (insn)) == SEQUENCE) 126290087Sobrien { 126390087Sobrien int i; 126490087Sobrien 126590087Sobrien body = PATTERN (insn); 126690087Sobrien for (i = 0; i < XVECLEN (body, 0); i++) 126790087Sobrien { 126890087Sobrien rtx inner_insn = XVECEXP (body, 0, i); 126990087Sobrien int inner_uid = INSN_UID (inner_insn); 127090087Sobrien 127190087Sobrien INSN_ADDRESSES (inner_uid) = insn_current_address; 127290087Sobrien 127390087Sobrien insn_current_address += insn_lengths[inner_uid]; 127490087Sobrien } 1275117404Skan } 127690087Sobrien else 127790087Sobrien insn_current_address += insn_lengths[uid]; 127890087Sobrien 127918334Speter continue; 128018334Speter } 128190087Sobrien 1282169699Skan if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE) 128318334Speter { 128418334Speter int i; 128590087Sobrien 128618334Speter body = PATTERN (insn); 128718334Speter new_length = 0; 128818334Speter for (i = 0; i < XVECLEN (body, 0); i++) 128918334Speter { 129018334Speter rtx inner_insn = XVECEXP (body, 0, i); 129118334Speter int inner_uid = INSN_UID (inner_insn); 129218334Speter int inner_length; 129318334Speter 129490087Sobrien INSN_ADDRESSES (inner_uid) = insn_current_address; 129518334Speter 129618334Speter /* insn_current_length returns 0 for insns with a 129718334Speter non-varying length. */ 129818334Speter if (! varying_length[inner_uid]) 129918334Speter inner_length = insn_lengths[inner_uid]; 130018334Speter else 130118334Speter inner_length = insn_current_length (inner_insn); 130218334Speter 130318334Speter if (inner_length != insn_lengths[inner_uid]) 130418334Speter { 130518334Speter insn_lengths[inner_uid] = inner_length; 130618334Speter something_changed = 1; 130718334Speter } 130818334Speter insn_current_address += insn_lengths[inner_uid]; 130918334Speter new_length += inner_length; 131018334Speter } 131118334Speter } 131218334Speter else 131318334Speter { 131418334Speter new_length = insn_current_length (insn); 131518334Speter insn_current_address += new_length; 131618334Speter } 131718334Speter 131818334Speter#ifdef ADJUST_INSN_LENGTH 131918334Speter /* If needed, do any adjustment. */ 132018334Speter tmp_length = new_length; 132118334Speter ADJUST_INSN_LENGTH (insn, new_length); 132218334Speter insn_current_address += (new_length - tmp_length); 132318334Speter#endif 132418334Speter 132518334Speter if (new_length != insn_lengths[uid]) 132618334Speter { 132718334Speter insn_lengths[uid] = new_length; 132818334Speter something_changed = 1; 132918334Speter } 133018334Speter } 133118334Speter /* For a non-optimizing compile, do only a single pass. */ 133218334Speter if (!optimize) 133318334Speter break; 133418334Speter } 133550503Sobrien 133650503Sobrien free (varying_length); 133750503Sobrien 133818334Speter#endif /* HAVE_ATTR_length */ 133918334Speter} 134018334Speter 134118334Speter#ifdef HAVE_ATTR_length 134218334Speter/* Given the body of an INSN known to be generated by an ASM statement, return 134318334Speter the number of machine instructions likely to be generated for this insn. 134418334Speter This is used to compute its length. */ 134518334Speter 134618334Speterstatic int 1347132727Skanasm_insn_count (rtx body) 134818334Speter{ 134990087Sobrien const char *template; 135018334Speter int count = 1; 135118334Speter 135218334Speter if (GET_CODE (body) == ASM_INPUT) 135318334Speter template = XSTR (body, 0); 135418334Speter else 135590087Sobrien template = decode_asm_operands (body, NULL, NULL, NULL, NULL); 135618334Speter 135790087Sobrien for (; *template; template++) 135890087Sobrien if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n') 135918334Speter count++; 136018334Speter 136118334Speter return count; 136218334Speter} 136318334Speter#endif 136418334Speter 136518334Speter/* Output assembler code for the start of a function, 136618334Speter and initialize some of the variables in this file 136718334Speter for the new function. The label for the function and associated 136818334Speter assembler pseudo-ops have already been output in `assemble_start_function'. 136918334Speter 137018334Speter FIRST is the first insn of the rtl for the function being compiled. 137118334Speter FILE is the file to write assembler code to. 137218334Speter OPTIMIZE is nonzero if we should eliminate redundant 137318334Speter test and compare insns. */ 137418334Speter 137518334Spetervoid 1376132727Skanfinal_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file, 1377132727Skan int optimize ATTRIBUTE_UNUSED) 137818334Speter{ 137918334Speter block_depth = 0; 138018334Speter 138118334Speter this_is_asm_operands = 0; 138218334Speter 1383132727Skan last_filename = locator_file (prologue_locator); 1384132727Skan last_linenum = locator_line (prologue_locator); 138518334Speter 138690087Sobrien high_block_linenum = high_function_linenum = last_linenum; 138718334Speter 138890087Sobrien (*debug_hooks->begin_prologue) (last_linenum, last_filename); 138950503Sobrien 1390169699Skan#if defined (DWARF2_UNWIND_INFO) || defined (TARGET_UNWIND_INFO) 139190087Sobrien if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG) 139290087Sobrien dwarf2out_begin_prologue (0, NULL); 139318334Speter#endif 139418334Speter 139518334Speter#ifdef LEAF_REG_REMAP 139652515Sobrien if (current_function_uses_only_leaf_regs) 139718334Speter leaf_renumber_regs (first); 139818334Speter#endif 139918334Speter 140018334Speter /* The Sun386i and perhaps other machines don't work right 140118334Speter if the profiling code comes after the prologue. */ 140218334Speter#ifdef PROFILE_BEFORE_PROLOGUE 140390087Sobrien if (current_function_profile) 140418334Speter profile_function (file); 140518334Speter#endif /* PROFILE_BEFORE_PROLOGUE */ 140618334Speter 140750503Sobrien#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue) 140850503Sobrien if (dwarf2out_do_frame ()) 1409169699Skan dwarf2out_frame_debug (NULL_RTX, false); 141050503Sobrien#endif 141150503Sobrien 141290087Sobrien /* If debugging, assign block numbers to all of the blocks in this 141390087Sobrien function. */ 141490087Sobrien if (write_symbols) 141590087Sobrien { 1416132727Skan reemit_insn_block_notes (); 141790087Sobrien number_blocks (current_function_decl); 141890087Sobrien /* We never actually put out begin/end notes for the top-level 141990087Sobrien block in the function. But, conceptually, that block is 142090087Sobrien always needed. */ 142190087Sobrien TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1; 142290087Sobrien } 142390087Sobrien 1424259406Spfg if (warn_frame_larger_than 1425259406Spfg && get_frame_size () > frame_larger_than_size) 1426259406Spfg { 1427259406Spfg /* Issue a warning */ 1428259406Spfg warning (OPT_Wframe_larger_than_, 1429259406Spfg "the frame size of %wd bytes is larger than %wd bytes", 1430259406Spfg get_frame_size (), frame_larger_than_size); 1431259406Spfg } 1432259406Spfg 143318334Speter /* First output the function prologue: code to set up the stack frame. */ 1434169699Skan targetm.asm_out.function_prologue (file, get_frame_size ()); 143518334Speter 143618334Speter /* If the machine represents the prologue as RTL, the profiling code must 143718334Speter be emitted when NOTE_INSN_PROLOGUE_END is scanned. */ 143818334Speter#ifdef HAVE_prologue 143918334Speter if (! HAVE_prologue) 144018334Speter#endif 144118334Speter profile_after_prologue (file); 144218334Speter} 144318334Speter 144418334Speterstatic void 1445132727Skanprofile_after_prologue (FILE *file ATTRIBUTE_UNUSED) 144618334Speter{ 144718334Speter#ifndef PROFILE_BEFORE_PROLOGUE 144890087Sobrien if (current_function_profile) 144918334Speter profile_function (file); 145018334Speter#endif /* not PROFILE_BEFORE_PROLOGUE */ 145118334Speter} 145218334Speter 145318334Speterstatic void 1454132727Skanprofile_function (FILE *file ATTRIBUTE_UNUSED) 145518334Speter{ 145674478Sobrien#ifndef NO_PROFILE_COUNTERS 1457132727Skan# define NO_PROFILE_COUNTERS 0 145874478Sobrien#endif 145950503Sobrien#if defined(ASM_OUTPUT_REG_PUSH) 146018334Speter int sval = current_function_returns_struct; 1461132727Skan rtx svrtx = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl), 1); 146250503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM) 1463169699Skan int cxt = cfun->static_chain_decl != NULL; 146450503Sobrien#endif 146550503Sobrien#endif /* ASM_OUTPUT_REG_PUSH */ 146618334Speter 1467132727Skan if (! NO_PROFILE_COUNTERS) 1468132727Skan { 1469132727Skan int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE); 1470169699Skan switch_to_section (data_section); 1471132727Skan ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT)); 1472169699Skan targetm.asm_out.internal_label (file, "LP", current_function_funcdef_no); 1473132727Skan assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1); 1474132727Skan } 147518334Speter 1476169699Skan switch_to_section (current_function_section ()); 147718334Speter 1478132727Skan#if defined(ASM_OUTPUT_REG_PUSH) 1479169699Skan if (sval && svrtx != NULL_RTX && REG_P (svrtx)) 1480132727Skan ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx)); 148118334Speter#endif 148218334Speter 148350503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 148418334Speter if (cxt) 148518334Speter ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM); 148618334Speter#else 148750503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 148818334Speter if (cxt) 148950503Sobrien { 149050503Sobrien ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM); 149150503Sobrien } 149218334Speter#endif 149318334Speter#endif 149418334Speter 1495117404Skan FUNCTION_PROFILER (file, current_function_funcdef_no); 149618334Speter 149750503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 149818334Speter if (cxt) 149918334Speter ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM); 150018334Speter#else 150150503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 150218334Speter if (cxt) 150350503Sobrien { 150450503Sobrien ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM); 150550503Sobrien } 150618334Speter#endif 150718334Speter#endif 150818334Speter 1509132727Skan#if defined(ASM_OUTPUT_REG_PUSH) 1510169699Skan if (sval && svrtx != NULL_RTX && REG_P (svrtx)) 1511132727Skan ASM_OUTPUT_REG_POP (file, REGNO (svrtx)); 151218334Speter#endif 151318334Speter} 151418334Speter 151518334Speter/* Output assembler code for the end of a function. 151618334Speter For clarity, args are same as those of `final_start_function' 151718334Speter even though not all of them are needed. */ 151818334Speter 151918334Spetervoid 1520132727Skanfinal_end_function (void) 152118334Speter{ 152290087Sobrien app_disable (); 152318334Speter 152490087Sobrien (*debug_hooks->end_function) (high_function_linenum); 152518334Speter 152618334Speter /* Finally, output the function epilogue: 152718334Speter code to restore the stack frame and return to the caller. */ 1528169699Skan targetm.asm_out.function_epilogue (asm_out_file, get_frame_size ()); 152918334Speter 153090087Sobrien /* And debug output. */ 1531117404Skan (*debug_hooks->end_epilogue) (last_linenum, last_filename); 153290087Sobrien 153390087Sobrien#if defined (DWARF2_UNWIND_INFO) 153490087Sobrien if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG 153590087Sobrien && dwarf2out_do_frame ()) 1536117404Skan dwarf2out_end_epilogue (last_linenum, last_filename); 153750503Sobrien#endif 153818334Speter} 153918334Speter 154018334Speter/* Output assembler code for some insns: all or part of a function. 1541169699Skan For description of args, see `final_start_function', above. */ 154218334Speter 154318334Spetervoid 1544169699Skanfinal (rtx first, FILE *file, int optimize) 154518334Speter{ 154690087Sobrien rtx insn; 154750503Sobrien int max_uid = 0; 1548132727Skan int seen = 0; 154918334Speter 155018334Speter last_ignored_compare = 0; 155118334Speter 1552132727Skan#ifdef SDB_DEBUGGING_INFO 1553132727Skan /* When producing SDB debugging info, delete troublesome line number 155418334Speter notes from inlined functions in other files as well as duplicate 155518334Speter line number notes. */ 155618334Speter if (write_symbols == SDB_DEBUG) 155718334Speter { 155818334Speter rtx last = 0; 155918334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 1560169699Skan if (NOTE_P (insn) && NOTE_LINE_NUMBER (insn) > 0) 156118334Speter { 1562169699Skan if (last != 0 1563169699Skan#ifdef USE_MAPPED_LOCATION 1564169699Skan && NOTE_SOURCE_LOCATION (insn) == NOTE_SOURCE_LOCATION (last) 1565169699Skan#else 1566169699Skan && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last) 1567169699Skan && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last) 1568169699Skan#endif 1569169699Skan ) 157018334Speter { 157190087Sobrien delete_insn (insn); /* Use delete_note. */ 157218334Speter continue; 157318334Speter } 157418334Speter last = insn; 157518334Speter } 157618334Speter } 157718334Speter#endif 157818334Speter 157918334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 158050503Sobrien { 1581132727Skan if (INSN_UID (insn) > max_uid) /* Find largest UID. */ 158290087Sobrien max_uid = INSN_UID (insn); 158352515Sobrien#ifdef HAVE_cc0 158452515Sobrien /* If CC tracking across branches is enabled, record the insn which 158552515Sobrien jumps to each branch only reached from one place. */ 1586169699Skan if (optimize && JUMP_P (insn)) 158752515Sobrien { 158852515Sobrien rtx lab = JUMP_LABEL (insn); 158952515Sobrien if (lab && LABEL_NUSES (lab) == 1) 159052515Sobrien { 159152515Sobrien LABEL_REFS (lab) = insn; 159252515Sobrien } 159352515Sobrien } 159452515Sobrien#endif 159550503Sobrien } 159618334Speter 159718334Speter init_recog (); 159818334Speter 159918334Speter CC_STATUS_INIT; 160018334Speter 160118334Speter /* Output the insns. */ 160218334Speter for (insn = NEXT_INSN (first); insn;) 160350503Sobrien { 160450503Sobrien#ifdef HAVE_ATTR_length 160590087Sobrien if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ()) 160690087Sobrien { 160790087Sobrien /* This can be triggered by bugs elsewhere in the compiler if 160890087Sobrien new insns are created after init_insn_lengths is called. */ 1609169699Skan gcc_assert (NOTE_P (insn)); 1610169699Skan insn_current_address = -1; 161190087Sobrien } 161290087Sobrien else 161390087Sobrien insn_current_address = INSN_ADDRESSES (INSN_UID (insn)); 161490087Sobrien#endif /* HAVE_ATTR_length */ 161590087Sobrien 1616169699Skan insn = final_scan_insn (insn, file, optimize, 0, &seen); 161750503Sobrien } 161890087Sobrien} 161990087Sobrien 162090087Sobrienconst char * 1621132727Skanget_insn_template (int code, rtx insn) 162290087Sobrien{ 162390087Sobrien switch (insn_data[code].output_format) 162490087Sobrien { 162590087Sobrien case INSN_OUTPUT_FORMAT_SINGLE: 1626132727Skan return insn_data[code].output.single; 162790087Sobrien case INSN_OUTPUT_FORMAT_MULTI: 1628132727Skan return insn_data[code].output.multi[which_alternative]; 162990087Sobrien case INSN_OUTPUT_FORMAT_FUNCTION: 1630169699Skan gcc_assert (insn); 1631132727Skan return (*insn_data[code].output.function) (recog_data.operand, insn); 163250503Sobrien 163390087Sobrien default: 1634169699Skan gcc_unreachable (); 163590087Sobrien } 163618334Speter} 163790087Sobrien 1638117404Skan/* Emit the appropriate declaration for an alternate-entry-point 1639117404Skan symbol represented by INSN, to FILE. INSN is a CODE_LABEL with 1640117404Skan LABEL_KIND != LABEL_NORMAL. 1641117404Skan 1642117404Skan The case fall-through in this function is intentional. */ 1643117404Skanstatic void 1644132727Skanoutput_alternate_entry_point (FILE *file, rtx insn) 1645117404Skan{ 1646117404Skan const char *name = LABEL_NAME (insn); 1647117404Skan 1648117404Skan switch (LABEL_KIND (insn)) 1649117404Skan { 1650117404Skan case LABEL_WEAK_ENTRY: 1651117404Skan#ifdef ASM_WEAKEN_LABEL 1652117404Skan ASM_WEAKEN_LABEL (file, name); 1653117404Skan#endif 1654117404Skan case LABEL_GLOBAL_ENTRY: 1655169699Skan targetm.asm_out.globalize_label (file, name); 1656117404Skan case LABEL_STATIC_ENTRY: 1657117404Skan#ifdef ASM_OUTPUT_TYPE_DIRECTIVE 1658117404Skan ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function"); 1659117404Skan#endif 1660117404Skan ASM_OUTPUT_LABEL (file, name); 1661117404Skan break; 1662117404Skan 1663117404Skan case LABEL_NORMAL: 1664117404Skan default: 1665169699Skan gcc_unreachable (); 1666117404Skan } 1667117404Skan} 1668117404Skan 166918334Speter/* The final scan for one insn, INSN. 167018334Speter Args are same as in `final', except that INSN 167118334Speter is the insn being scanned. 167218334Speter Value returned is the next insn to be scanned. 167318334Speter 167418334Speter NOPEEPHOLES is the flag to disallow peephole processing (currently 1675132727Skan used for within delayed branch sequence output). 167618334Speter 1677132727Skan SEEN is used to track the end of the prologue, for emitting 1678132727Skan debug information. We force the emission of a line note after 1679132727Skan both NOTE_INSN_PROLOGUE_END and NOTE_INSN_FUNCTION_BEG, or 1680132727Skan at the beginning of the second basic block, whichever comes 1681132727Skan first. */ 1682132727Skan 168318334Speterrtx 1684132727Skanfinal_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, 1685169699Skan int nopeepholes ATTRIBUTE_UNUSED, int *seen) 168618334Speter{ 168750503Sobrien#ifdef HAVE_cc0 168850503Sobrien rtx set; 168950503Sobrien#endif 1690169699Skan rtx next; 169150503Sobrien 169218334Speter insn_counter++; 169318334Speter 169418334Speter /* Ignore deleted insns. These can occur when we split insns (due to a 169518334Speter template of "#") while not optimizing. */ 169618334Speter if (INSN_DELETED_P (insn)) 169718334Speter return NEXT_INSN (insn); 169818334Speter 169918334Speter switch (GET_CODE (insn)) 170018334Speter { 170118334Speter case NOTE: 170290087Sobrien switch (NOTE_LINE_NUMBER (insn)) 170318334Speter { 170490087Sobrien case NOTE_INSN_DELETED: 170590087Sobrien case NOTE_INSN_FUNCTION_END: 170690087Sobrien case NOTE_INSN_REPEATED_LINE_NUMBER: 170790087Sobrien case NOTE_INSN_EXPECTED_VALUE: 170818334Speter break; 170918334Speter 1710169699Skan case NOTE_INSN_SWITCH_TEXT_SECTIONS: 1711169699Skan in_cold_section_p = !in_cold_section_p; 1712169699Skan (*debug_hooks->switch_text_section) (); 1713169699Skan switch_to_section (current_function_section ()); 1714169699Skan break; 1715169699Skan 171690087Sobrien case NOTE_INSN_BASIC_BLOCK: 1717169699Skan#ifdef TARGET_UNWIND_INFO 1718169699Skan targetm.asm_out.unwind_emit (asm_out_file, insn); 171950503Sobrien#endif 1720169699Skan 172190087Sobrien if (flag_debug_asm) 172290087Sobrien fprintf (asm_out_file, "\t%s basic block %d\n", 172390087Sobrien ASM_COMMENT_START, NOTE_BASIC_BLOCK (insn)->index); 1724132727Skan 1725132727Skan if ((*seen & (SEEN_EMITTED | SEEN_BB)) == SEEN_BB) 1726132727Skan { 1727132727Skan *seen |= SEEN_EMITTED; 1728169699Skan force_source_line = true; 1729132727Skan } 1730132727Skan else 1731132727Skan *seen |= SEEN_BB; 1732132727Skan 173350503Sobrien break; 173450503Sobrien 173590087Sobrien case NOTE_INSN_EH_REGION_BEG: 173690087Sobrien ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHB", 173790087Sobrien NOTE_EH_HANDLER (insn)); 173890087Sobrien break; 173990087Sobrien 174090087Sobrien case NOTE_INSN_EH_REGION_END: 174190087Sobrien ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHE", 174290087Sobrien NOTE_EH_HANDLER (insn)); 174390087Sobrien break; 174490087Sobrien 174590087Sobrien case NOTE_INSN_PROLOGUE_END: 1746169699Skan targetm.asm_out.function_end_prologue (file); 174718334Speter profile_after_prologue (file); 1748132727Skan 1749132727Skan if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE) 1750132727Skan { 1751132727Skan *seen |= SEEN_EMITTED; 1752169699Skan force_source_line = true; 1753132727Skan } 1754132727Skan else 1755132727Skan *seen |= SEEN_NOTE; 1756132727Skan 175718334Speter break; 175818334Speter 175990087Sobrien case NOTE_INSN_EPILOGUE_BEG: 1760169699Skan targetm.asm_out.function_begin_epilogue (file); 176118334Speter break; 176218334Speter 176390087Sobrien case NOTE_INSN_FUNCTION_BEG: 176490087Sobrien app_disable (); 1765117404Skan (*debug_hooks->end_prologue) (last_linenum, last_filename); 1766132727Skan 1767132727Skan if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE) 1768132727Skan { 1769132727Skan *seen |= SEEN_EMITTED; 1770169699Skan force_source_line = true; 1771132727Skan } 1772132727Skan else 1773132727Skan *seen |= SEEN_NOTE; 1774132727Skan 177518334Speter break; 177690087Sobrien 177790087Sobrien case NOTE_INSN_BLOCK_BEG: 177890087Sobrien if (debug_info_level == DINFO_LEVEL_NORMAL 177918334Speter || debug_info_level == DINFO_LEVEL_VERBOSE 178090087Sobrien || write_symbols == DWARF2_DEBUG 178190087Sobrien || write_symbols == VMS_AND_DWARF2_DEBUG 178290087Sobrien || write_symbols == VMS_DEBUG) 178390087Sobrien { 178490087Sobrien int n = BLOCK_NUMBER (NOTE_BLOCK (insn)); 178518334Speter 178690087Sobrien app_disable (); 178790087Sobrien ++block_depth; 178890087Sobrien high_block_linenum = last_linenum; 178990087Sobrien 179090087Sobrien /* Output debugging info about the symbol-block beginning. */ 179190087Sobrien (*debug_hooks->begin_block) (last_linenum, n); 179290087Sobrien 179390087Sobrien /* Mark this block as output. */ 179490087Sobrien TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1; 179518334Speter } 179690087Sobrien break; 179718334Speter 179890087Sobrien case NOTE_INSN_BLOCK_END: 179990087Sobrien if (debug_info_level == DINFO_LEVEL_NORMAL 180090087Sobrien || debug_info_level == DINFO_LEVEL_VERBOSE 180190087Sobrien || write_symbols == DWARF2_DEBUG 180290087Sobrien || write_symbols == VMS_AND_DWARF2_DEBUG 180390087Sobrien || write_symbols == VMS_DEBUG) 180490087Sobrien { 180590087Sobrien int n = BLOCK_NUMBER (NOTE_BLOCK (insn)); 180618334Speter 180790087Sobrien app_disable (); 180818334Speter 180990087Sobrien /* End of a symbol-block. */ 181090087Sobrien --block_depth; 1811169699Skan gcc_assert (block_depth >= 0); 181218334Speter 181390087Sobrien (*debug_hooks->end_block) (high_block_linenum, n); 181490087Sobrien } 181590087Sobrien break; 181618334Speter 181790087Sobrien case NOTE_INSN_DELETED_LABEL: 181890087Sobrien /* Emit the label. We may have deleted the CODE_LABEL because 181990087Sobrien the label could be proved to be unreachable, though still 182090087Sobrien referenced (in the form of having its address taken. */ 182190087Sobrien ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); 182290087Sobrien break; 182318334Speter 1824169699Skan case NOTE_INSN_VAR_LOCATION: 1825169699Skan (*debug_hooks->var_location) (insn); 1826169699Skan break; 1827169699Skan 182890087Sobrien case 0: 182990087Sobrien break; 183018334Speter 183190087Sobrien default: 1832169699Skan gcc_assert (NOTE_LINE_NUMBER (insn) > 0); 183390087Sobrien break; 183418334Speter } 183518334Speter break; 183618334Speter 183718334Speter case BARRIER: 183890087Sobrien#if defined (DWARF2_UNWIND_INFO) 183990087Sobrien if (dwarf2out_do_frame ()) 1840169699Skan dwarf2out_frame_debug (insn, false); 184118334Speter#endif 184218334Speter break; 184318334Speter 184418334Speter case CODE_LABEL: 184550503Sobrien /* The target port might emit labels in the output function for 184650503Sobrien some insn, e.g. sh.c output_branchy_insn. */ 1847260919Spfg/* APPLE LOCAL begin for-fsf-4_4 3274130 5295549 */ \ 1848260919Spfg { 1849260919Spfg int align = LABEL_ALIGN_LOG (insn); 185050503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN 1851260919Spfg int max_skip = LABEL_MAX_SKIP (insn); 185250503Sobrien#endif 1853260919Spfg 1854260919Spfg if (align && NEXT_INSN (insn)) 1855260919Spfg { 185650503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN 1857260919Spfg ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip); 185850503Sobrien#else 1859117404Skan#ifdef ASM_OUTPUT_ALIGN_WITH_NOP 1860260919Spfg ASM_OUTPUT_ALIGN_WITH_NOP (file, align); 1861117404Skan#else 1862260919Spfg ASM_OUTPUT_ALIGN (file, align); 186350503Sobrien#endif 1864117404Skan#endif 1865260919Spfg } 1866260919Spfg } 1867260919Spfg/* APPLE LOCAL end for-fsf-4_4 3274130 5295549 */ \ 186852515Sobrien#ifdef HAVE_cc0 186918334Speter CC_STATUS_INIT; 187052515Sobrien /* If this label is reached from only one place, set the condition 187152515Sobrien codes from the instruction just before the branch. */ 187252515Sobrien 187352515Sobrien /* Disabled because some insns set cc_status in the C output code 187452515Sobrien and NOTICE_UPDATE_CC alone can set incorrect status. */ 187552515Sobrien if (0 /* optimize && LABEL_NUSES (insn) == 1*/) 187652515Sobrien { 187752515Sobrien rtx jump = LABEL_REFS (insn); 187852515Sobrien rtx barrier = prev_nonnote_insn (insn); 187952515Sobrien rtx prev; 188052515Sobrien /* If the LABEL_REFS field of this label has been set to point 188152515Sobrien at a branch, the predecessor of the branch is a regular 188252515Sobrien insn, and that branch is the only way to reach this label, 188352515Sobrien set the condition codes based on the branch and its 188452515Sobrien predecessor. */ 1885169699Skan if (barrier && BARRIER_P (barrier) 1886169699Skan && jump && JUMP_P (jump) 188752515Sobrien && (prev = prev_nonnote_insn (jump)) 1888169699Skan && NONJUMP_INSN_P (prev)) 188952515Sobrien { 189052515Sobrien NOTICE_UPDATE_CC (PATTERN (prev), prev); 189152515Sobrien NOTICE_UPDATE_CC (PATTERN (jump), jump); 189252515Sobrien } 189352515Sobrien } 189452515Sobrien#endif 189550503Sobrien 189690087Sobrien if (LABEL_NAME (insn)) 189790087Sobrien (*debug_hooks->label) (insn); 189890087Sobrien 189918334Speter if (app_on) 190018334Speter { 190150503Sobrien fputs (ASM_APP_OFF, file); 190218334Speter app_on = 0; 190318334Speter } 1904169699Skan 1905169699Skan next = next_nonnote_insn (insn); 1906169699Skan if (next != 0 && JUMP_P (next)) 190718334Speter { 1908169699Skan rtx nextbody = PATTERN (next); 190918334Speter 191018334Speter /* If this label is followed by a jump-table, 191118334Speter make sure we put the label in the read-only section. Also 191218334Speter possibly write the label and jump table together. */ 191318334Speter 191418334Speter if (GET_CODE (nextbody) == ADDR_VEC 191518334Speter || GET_CODE (nextbody) == ADDR_DIFF_VEC) 191618334Speter { 191752515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC) 191852515Sobrien /* In this case, the case vector is being moved by the 191952515Sobrien target, so don't output the label at all. Leave that 192052515Sobrien to the back end macros. */ 192152515Sobrien#else 192250503Sobrien if (! JUMP_TABLES_IN_TEXT_SECTION) 192350503Sobrien { 192490087Sobrien int log_align; 192590087Sobrien 1926169699Skan switch_to_section (targetm.asm_out.function_rodata_section 1927169699Skan (current_function_decl)); 192890087Sobrien 192990087Sobrien#ifdef ADDR_VEC_ALIGN 1930169699Skan log_align = ADDR_VEC_ALIGN (next); 193190087Sobrien#else 193290087Sobrien log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT); 193390087Sobrien#endif 193490087Sobrien ASM_OUTPUT_ALIGN (file, log_align); 193550503Sobrien } 193650503Sobrien else 1937169699Skan switch_to_section (current_function_section ()); 193850503Sobrien 193918334Speter#ifdef ASM_OUTPUT_CASE_LABEL 194018334Speter ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), 1941169699Skan next); 194218334Speter#else 1943169699Skan targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn)); 194418334Speter#endif 194552515Sobrien#endif 194618334Speter break; 194718334Speter } 194818334Speter } 1949117404Skan if (LABEL_ALT_ENTRY_P (insn)) 1950117404Skan output_alternate_entry_point (file, insn); 195190087Sobrien else 1952169699Skan targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn)); 195318334Speter break; 195418334Speter 195518334Speter default: 195618334Speter { 195790087Sobrien rtx body = PATTERN (insn); 195818334Speter int insn_code_number; 195952515Sobrien const char *template; 196018334Speter 1961169699Skan#ifdef HAVE_conditional_execution 1962169699Skan /* Reset this early so it is correct for ASM statements. */ 1963169699Skan current_insn_predicate = NULL_RTX; 1964169699Skan#endif 196518334Speter /* An INSN, JUMP_INSN or CALL_INSN. 196618334Speter First check for special kinds that recog doesn't recognize. */ 196718334Speter 1968132727Skan if (GET_CODE (body) == USE /* These are just declarations. */ 196918334Speter || GET_CODE (body) == CLOBBER) 197018334Speter break; 197118334Speter 197218334Speter#ifdef HAVE_cc0 1973169699Skan { 1974169699Skan /* If there is a REG_CC_SETTER note on this insn, it means that 1975169699Skan the setting of the condition code was done in the delay slot 1976169699Skan of the insn that branched here. So recover the cc status 1977169699Skan from the insn that set it. */ 197818334Speter 1979169699Skan rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX); 1980169699Skan if (note) 1981169699Skan { 1982169699Skan NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0)); 1983169699Skan cc_prev_status = cc_status; 1984169699Skan } 1985169699Skan } 198618334Speter#endif 198718334Speter 198818334Speter /* Detect insns that are really jump-tables 198918334Speter and output them as such. */ 199018334Speter 199118334Speter if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) 199218334Speter { 199352515Sobrien#if !(defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)) 199490087Sobrien int vlen, idx; 199552515Sobrien#endif 199618334Speter 1997169699Skan if (! JUMP_TABLES_IN_TEXT_SECTION) 1998169699Skan switch_to_section (targetm.asm_out.function_rodata_section 1999169699Skan (current_function_decl)); 2000169699Skan else 2001169699Skan switch_to_section (current_function_section ()); 200218334Speter 200318334Speter if (app_on) 200418334Speter { 200550503Sobrien fputs (ASM_APP_OFF, file); 200618334Speter app_on = 0; 200718334Speter } 200818334Speter 200952515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC) 201052515Sobrien if (GET_CODE (body) == ADDR_VEC) 201152515Sobrien { 201252515Sobrien#ifdef ASM_OUTPUT_ADDR_VEC 201352515Sobrien ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body); 201452515Sobrien#else 2015169699Skan gcc_unreachable (); 201652515Sobrien#endif 201752515Sobrien } 201852515Sobrien else 201952515Sobrien { 202052515Sobrien#ifdef ASM_OUTPUT_ADDR_DIFF_VEC 202152515Sobrien ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body); 202252515Sobrien#else 2023169699Skan gcc_unreachable (); 202452515Sobrien#endif 202552515Sobrien } 202652515Sobrien#else 202718334Speter vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC); 202818334Speter for (idx = 0; idx < vlen; idx++) 202918334Speter { 203018334Speter if (GET_CODE (body) == ADDR_VEC) 203118334Speter { 203218334Speter#ifdef ASM_OUTPUT_ADDR_VEC_ELT 203318334Speter ASM_OUTPUT_ADDR_VEC_ELT 203418334Speter (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0))); 203518334Speter#else 2036169699Skan gcc_unreachable (); 203718334Speter#endif 203818334Speter } 203918334Speter else 204018334Speter { 204118334Speter#ifdef ASM_OUTPUT_ADDR_DIFF_ELT 204218334Speter ASM_OUTPUT_ADDR_DIFF_ELT 204318334Speter (file, 204450503Sobrien body, 204518334Speter CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)), 204618334Speter CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0))); 204718334Speter#else 2048169699Skan gcc_unreachable (); 204918334Speter#endif 205018334Speter } 205118334Speter } 205218334Speter#ifdef ASM_OUTPUT_CASE_END 205318334Speter ASM_OUTPUT_CASE_END (file, 205418334Speter CODE_LABEL_NUMBER (PREV_INSN (insn)), 205518334Speter insn); 205618334Speter#endif 205752515Sobrien#endif 205818334Speter 2059169699Skan switch_to_section (current_function_section ()); 206018334Speter 206118334Speter break; 206218334Speter } 2063132727Skan /* Output this line note if it is the first or the last line 2064132727Skan note in a row. */ 2065132727Skan if (notice_source_line (insn)) 2066132727Skan { 2067132727Skan (*debug_hooks->source_line) (last_linenum, last_filename); 2068132727Skan } 206918334Speter 207018334Speter if (GET_CODE (body) == ASM_INPUT) 207118334Speter { 207290087Sobrien const char *string = XSTR (body, 0); 207390087Sobrien 207418334Speter /* There's no telling what that did to the condition codes. */ 207518334Speter CC_STATUS_INIT; 207690087Sobrien 207790087Sobrien if (string[0]) 207818334Speter { 207990087Sobrien if (! app_on) 208090087Sobrien { 208190087Sobrien fputs (ASM_APP_ON, file); 208290087Sobrien app_on = 1; 208390087Sobrien } 208490087Sobrien fprintf (asm_out_file, "\t%s\n", string); 208518334Speter } 208618334Speter break; 208718334Speter } 208818334Speter 208918334Speter /* Detect `asm' construct with operands. */ 209018334Speter if (asm_noperands (body) >= 0) 209118334Speter { 209250503Sobrien unsigned int noperands = asm_noperands (body); 2093132727Skan rtx *ops = alloca (noperands * sizeof (rtx)); 209490087Sobrien const char *string; 209518334Speter 209618334Speter /* There's no telling what that did to the condition codes. */ 209718334Speter CC_STATUS_INIT; 209818334Speter 209918334Speter /* Get out the operand values. */ 210090087Sobrien string = decode_asm_operands (body, ops, NULL, NULL, NULL); 2101169699Skan /* Inhibit dieing on what would otherwise be compiler bugs. */ 210218334Speter insn_noperands = noperands; 210318334Speter this_is_asm_operands = insn; 210418334Speter 2105132727Skan#ifdef FINAL_PRESCAN_INSN 2106132727Skan FINAL_PRESCAN_INSN (insn, ops, insn_noperands); 2107132727Skan#endif 2108132727Skan 210918334Speter /* Output the insn using them. */ 211090087Sobrien if (string[0]) 211190087Sobrien { 211290087Sobrien if (! app_on) 211390087Sobrien { 211490087Sobrien fputs (ASM_APP_ON, file); 211590087Sobrien app_on = 1; 211690087Sobrien } 211790087Sobrien output_asm_insn (string, ops); 211890087Sobrien } 211990087Sobrien 212018334Speter this_is_asm_operands = 0; 212118334Speter break; 212218334Speter } 212318334Speter 2124169699Skan if (app_on) 212518334Speter { 212650503Sobrien fputs (ASM_APP_OFF, file); 212718334Speter app_on = 0; 212818334Speter } 212918334Speter 213018334Speter if (GET_CODE (body) == SEQUENCE) 213118334Speter { 213218334Speter /* A delayed-branch sequence */ 213390087Sobrien int i; 213418334Speter 213518334Speter final_sequence = body; 213618334Speter 2137132727Skan /* Record the delay slots' frame information before the branch. 2138132727Skan This is needed for delayed calls: see execute_cfa_program(). */ 2139132727Skan#if defined (DWARF2_UNWIND_INFO) 2140132727Skan if (dwarf2out_do_frame ()) 2141132727Skan for (i = 1; i < XVECLEN (body, 0); i++) 2142169699Skan dwarf2out_frame_debug (XVECEXP (body, 0, i), false); 2143132727Skan#endif 2144132727Skan 214518334Speter /* The first insn in this SEQUENCE might be a JUMP_INSN that will 214618334Speter force the restoration of a comparison that was previously 214718334Speter thought unnecessary. If that happens, cancel this sequence 214818334Speter and cause that insn to be restored. */ 214918334Speter 2150169699Skan next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, 1, seen); 215118334Speter if (next != XVECEXP (body, 0, 1)) 215218334Speter { 215318334Speter final_sequence = 0; 215418334Speter return next; 215518334Speter } 215618334Speter 215718334Speter for (i = 1; i < XVECLEN (body, 0); i++) 215818334Speter { 215918334Speter rtx insn = XVECEXP (body, 0, i); 216018334Speter rtx next = NEXT_INSN (insn); 216118334Speter /* We loop in case any instruction in a delay slot gets 216218334Speter split. */ 216318334Speter do 2164169699Skan insn = final_scan_insn (insn, file, 0, 1, seen); 216518334Speter while (insn != next); 216618334Speter } 216718334Speter#ifdef DBR_OUTPUT_SEQEND 216818334Speter DBR_OUTPUT_SEQEND (file); 216918334Speter#endif 217018334Speter final_sequence = 0; 217118334Speter 217218334Speter /* If the insn requiring the delay slot was a CALL_INSN, the 217318334Speter insns in the delay slot are actually executed before the 217418334Speter called function. Hence we don't preserve any CC-setting 217518334Speter actions in these insns and the CC must be marked as being 217618334Speter clobbered by the function. */ 2177169699Skan if (CALL_P (XVECEXP (body, 0, 0))) 217850503Sobrien { 217950503Sobrien CC_STATUS_INIT; 218050503Sobrien } 218118334Speter break; 218218334Speter } 218318334Speter 218418334Speter /* We have a real machine instruction as rtl. */ 218518334Speter 218618334Speter body = PATTERN (insn); 218718334Speter 218818334Speter#ifdef HAVE_cc0 218990087Sobrien set = single_set (insn); 219050503Sobrien 219118334Speter /* Check for redundant test and compare instructions 219218334Speter (when the condition codes are already set up as desired). 219318334Speter This is done only when optimizing; if not optimizing, 219418334Speter it should be possible for the user to alter a variable 219518334Speter with the debugger in between statements 219618334Speter and the next statement should reexamine the variable 219718334Speter to compute the condition codes. */ 219818334Speter 219950503Sobrien if (optimize) 220018334Speter { 220150503Sobrien if (set 220250503Sobrien && GET_CODE (SET_DEST (set)) == CC0 220350503Sobrien && insn != last_ignored_compare) 220418334Speter { 220550503Sobrien if (GET_CODE (SET_SRC (set)) == SUBREG) 220690087Sobrien SET_SRC (set) = alter_subreg (&SET_SRC (set)); 220750503Sobrien else if (GET_CODE (SET_SRC (set)) == COMPARE) 220818334Speter { 220950503Sobrien if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG) 221050503Sobrien XEXP (SET_SRC (set), 0) 221190087Sobrien = alter_subreg (&XEXP (SET_SRC (set), 0)); 221250503Sobrien if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG) 221350503Sobrien XEXP (SET_SRC (set), 1) 221490087Sobrien = alter_subreg (&XEXP (SET_SRC (set), 1)); 221518334Speter } 221650503Sobrien if ((cc_status.value1 != 0 221750503Sobrien && rtx_equal_p (SET_SRC (set), cc_status.value1)) 221850503Sobrien || (cc_status.value2 != 0 221950503Sobrien && rtx_equal_p (SET_SRC (set), cc_status.value2))) 222050503Sobrien { 222150503Sobrien /* Don't delete insn if it has an addressing side-effect. */ 222290087Sobrien if (! FIND_REG_INC_NOTE (insn, NULL_RTX) 222350503Sobrien /* or if anything in it is volatile. */ 222450503Sobrien && ! volatile_refs_p (PATTERN (insn))) 222550503Sobrien { 222650503Sobrien /* We don't really delete the insn; just ignore it. */ 222750503Sobrien last_ignored_compare = insn; 222850503Sobrien break; 222950503Sobrien } 223050503Sobrien } 223118334Speter } 223218334Speter } 223318334Speter#endif 223418334Speter 223518334Speter#ifdef HAVE_cc0 223618334Speter /* If this is a conditional branch, maybe modify it 223718334Speter if the cc's are in a nonstandard state 223818334Speter so that it accomplishes the same thing that it would 223918334Speter do straightforwardly if the cc's were set up normally. */ 224018334Speter 224118334Speter if (cc_status.flags != 0 2242169699Skan && JUMP_P (insn) 224318334Speter && GET_CODE (body) == SET 224418334Speter && SET_DEST (body) == pc_rtx 224518334Speter && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE 2246169699Skan && COMPARISON_P (XEXP (SET_SRC (body), 0)) 2247169699Skan && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx) 224818334Speter { 224918334Speter /* This function may alter the contents of its argument 225018334Speter and clear some of the cc_status.flags bits. 225118334Speter It may also return 1 meaning condition now always true 225218334Speter or -1 meaning condition now always false 225318334Speter or 2 meaning condition nontrivial but altered. */ 225490087Sobrien int result = alter_cond (XEXP (SET_SRC (body), 0)); 225518334Speter /* If condition now has fixed value, replace the IF_THEN_ELSE 225618334Speter with its then-operand or its else-operand. */ 225718334Speter if (result == 1) 225818334Speter SET_SRC (body) = XEXP (SET_SRC (body), 1); 225918334Speter if (result == -1) 226018334Speter SET_SRC (body) = XEXP (SET_SRC (body), 2); 226118334Speter 226218334Speter /* The jump is now either unconditional or a no-op. 226318334Speter If it has become a no-op, don't try to output it. 226418334Speter (It would not be recognized.) */ 226518334Speter if (SET_SRC (body) == pc_rtx) 226618334Speter { 226790087Sobrien delete_insn (insn); 226818334Speter break; 226918334Speter } 227018334Speter else if (GET_CODE (SET_SRC (body)) == RETURN) 227118334Speter /* Replace (set (pc) (return)) with (return). */ 227218334Speter PATTERN (insn) = body = SET_SRC (body); 227318334Speter 227418334Speter /* Rerecognize the instruction if it has changed. */ 227518334Speter if (result != 0) 227618334Speter INSN_CODE (insn) = -1; 227718334Speter } 227818334Speter 227918334Speter /* Make same adjustments to instructions that examine the 228050503Sobrien condition codes without jumping and instructions that 228150503Sobrien handle conditional moves (if this machine has either one). */ 228218334Speter 228318334Speter if (cc_status.flags != 0 228450503Sobrien && set != 0) 228518334Speter { 228650503Sobrien rtx cond_rtx, then_rtx, else_rtx; 228790087Sobrien 2288169699Skan if (!JUMP_P (insn) 228950503Sobrien && GET_CODE (SET_SRC (set)) == IF_THEN_ELSE) 229018334Speter { 229150503Sobrien cond_rtx = XEXP (SET_SRC (set), 0); 229250503Sobrien then_rtx = XEXP (SET_SRC (set), 1); 229350503Sobrien else_rtx = XEXP (SET_SRC (set), 2); 229450503Sobrien } 229550503Sobrien else 229650503Sobrien { 229750503Sobrien cond_rtx = SET_SRC (set); 229850503Sobrien then_rtx = const_true_rtx; 229950503Sobrien else_rtx = const0_rtx; 230050503Sobrien } 230190087Sobrien 230250503Sobrien switch (GET_CODE (cond_rtx)) 230350503Sobrien { 230418334Speter case GTU: 230518334Speter case GT: 230618334Speter case LTU: 230718334Speter case LT: 230818334Speter case GEU: 230918334Speter case GE: 231018334Speter case LEU: 231118334Speter case LE: 231218334Speter case EQ: 231318334Speter case NE: 231418334Speter { 231590087Sobrien int result; 231650503Sobrien if (XEXP (cond_rtx, 0) != cc0_rtx) 231718334Speter break; 231850503Sobrien result = alter_cond (cond_rtx); 231918334Speter if (result == 1) 232050503Sobrien validate_change (insn, &SET_SRC (set), then_rtx, 0); 232118334Speter else if (result == -1) 232250503Sobrien validate_change (insn, &SET_SRC (set), else_rtx, 0); 232318334Speter else if (result == 2) 232418334Speter INSN_CODE (insn) = -1; 232550503Sobrien if (SET_DEST (set) == SET_SRC (set)) 232690087Sobrien delete_insn (insn); 232718334Speter } 232850503Sobrien break; 232950503Sobrien 233050503Sobrien default: 233150503Sobrien break; 233218334Speter } 233318334Speter } 233450503Sobrien 233518334Speter#endif 233618334Speter 233790087Sobrien#ifdef HAVE_peephole 233818334Speter /* Do machine-specific peephole optimizations if desired. */ 233918334Speter 234018334Speter if (optimize && !flag_no_peephole && !nopeepholes) 234118334Speter { 234218334Speter rtx next = peephole (insn); 234318334Speter /* When peepholing, if there were notes within the peephole, 234418334Speter emit them before the peephole. */ 234518334Speter if (next != 0 && next != NEXT_INSN (insn)) 234618334Speter { 2347169699Skan rtx note, prev = PREV_INSN (insn); 234818334Speter 234918334Speter for (note = NEXT_INSN (insn); note != next; 235018334Speter note = NEXT_INSN (note)) 2351169699Skan final_scan_insn (note, file, optimize, nopeepholes, seen); 235218334Speter 2353169699Skan /* Put the notes in the proper position for a later 2354169699Skan rescan. For example, the SH target can do this 2355169699Skan when generating a far jump in a delayed branch 2356169699Skan sequence. */ 235718334Speter note = NEXT_INSN (insn); 235818334Speter PREV_INSN (note) = prev; 235918334Speter NEXT_INSN (prev) = note; 236018334Speter NEXT_INSN (PREV_INSN (next)) = insn; 236118334Speter PREV_INSN (insn) = PREV_INSN (next); 236218334Speter NEXT_INSN (insn) = next; 236318334Speter PREV_INSN (next) = insn; 236418334Speter } 236518334Speter 236618334Speter /* PEEPHOLE might have changed this. */ 236718334Speter body = PATTERN (insn); 236818334Speter } 236990087Sobrien#endif 237018334Speter 237118334Speter /* Try to recognize the instruction. 237218334Speter If successful, verify that the operands satisfy the 237318334Speter constraints for the instruction. Crash if they don't, 237418334Speter since `reload' should have changed them so that they do. */ 237518334Speter 237618334Speter insn_code_number = recog_memoized (insn); 237752515Sobrien cleanup_subreg_operands (insn); 237818334Speter 2379117404Skan /* Dump the insn in the assembly for debugging. */ 2380117404Skan if (flag_dump_rtl_in_asm) 2381117404Skan { 2382117404Skan print_rtx_head = ASM_COMMENT_START; 2383117404Skan print_rtl_single (asm_out_file, insn); 2384117404Skan print_rtx_head = ""; 2385117404Skan } 238690087Sobrien 238790087Sobrien if (! constrain_operands_cached (1)) 238818334Speter fatal_insn_not_found (insn); 238918334Speter 239018334Speter /* Some target machines need to prescan each insn before 239118334Speter it is output. */ 239218334Speter 239318334Speter#ifdef FINAL_PRESCAN_INSN 239490087Sobrien FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands); 239518334Speter#endif 239618334Speter 239790087Sobrien#ifdef HAVE_conditional_execution 239890087Sobrien if (GET_CODE (PATTERN (insn)) == COND_EXEC) 239990087Sobrien current_insn_predicate = COND_EXEC_TEST (PATTERN (insn)); 240090087Sobrien#endif 240190087Sobrien 240218334Speter#ifdef HAVE_cc0 240318334Speter cc_prev_status = cc_status; 240418334Speter 240518334Speter /* Update `cc_status' for this instruction. 240618334Speter The instruction's output routine may change it further. 240718334Speter If the output routine for a jump insn needs to depend 240818334Speter on the cc status, it should look at cc_prev_status. */ 240918334Speter 241018334Speter NOTICE_UPDATE_CC (body, insn); 241118334Speter#endif 241218334Speter 241390087Sobrien current_output_insn = debug_insn = insn; 241418334Speter 241590087Sobrien#if defined (DWARF2_UNWIND_INFO) 2416169699Skan if (CALL_P (insn) && dwarf2out_do_frame ()) 2417169699Skan dwarf2out_frame_debug (insn, false); 241850503Sobrien#endif 241950503Sobrien 242090087Sobrien /* Find the proper template for this insn. */ 242190087Sobrien template = get_insn_template (insn_code_number, insn); 242218334Speter 242390087Sobrien /* If the C code returns 0, it means that it is a jump insn 242490087Sobrien which follows a deleted test insn, and that test insn 242590087Sobrien needs to be reinserted. */ 242618334Speter if (template == 0) 242718334Speter { 242890087Sobrien rtx prev; 242918334Speter 2430169699Skan gcc_assert (prev_nonnote_insn (insn) == last_ignored_compare); 243190087Sobrien 243290087Sobrien /* We have already processed the notes between the setter and 243390087Sobrien the user. Make sure we don't process them again, this is 243490087Sobrien particularly important if one of the notes is a block 243590087Sobrien scope note or an EH note. */ 243690087Sobrien for (prev = insn; 243790087Sobrien prev != last_ignored_compare; 243890087Sobrien prev = PREV_INSN (prev)) 243918334Speter { 2440169699Skan if (NOTE_P (prev)) 244190087Sobrien delete_insn (prev); /* Use delete_note. */ 244218334Speter } 244390087Sobrien 244490087Sobrien return prev; 244518334Speter } 244618334Speter 244718334Speter /* If the template is the string "#", it means that this insn must 244818334Speter be split. */ 244918334Speter if (template[0] == '#' && template[1] == '\0') 245018334Speter { 245118334Speter rtx new = try_split (body, insn, 0); 245218334Speter 245318334Speter /* If we didn't split the insn, go away. */ 245418334Speter if (new == insn && PATTERN (new) == body) 245590087Sobrien fatal_insn ("could not split insn", insn); 245690087Sobrien 245750503Sobrien#ifdef HAVE_ATTR_length 245850503Sobrien /* This instruction should have been split in shorten_branches, 245950503Sobrien to ensure that we would have valid length info for the 246050503Sobrien splitees. */ 2461169699Skan gcc_unreachable (); 246250503Sobrien#endif 246350503Sobrien 246418334Speter return new; 246518334Speter } 246690087Sobrien 2467169699Skan#ifdef TARGET_UNWIND_INFO 2468169699Skan /* ??? This will put the directives in the wrong place if 2469169699Skan get_insn_template outputs assembly directly. However calling it 2470169699Skan before get_insn_template breaks if the insns is split. */ 2471169699Skan targetm.asm_out.unwind_emit (asm_out_file, insn); 2472169699Skan#endif 247318334Speter 247418334Speter /* Output assembler code from the template. */ 247590087Sobrien output_asm_insn (template, recog_data.operand); 247618334Speter 2477132727Skan /* If necessary, report the effect that the instruction has on 2478132727Skan the unwind info. We've already done this for delay slots 2479132727Skan and call instructions. */ 248050503Sobrien#if defined (DWARF2_UNWIND_INFO) 2481169699Skan if (final_sequence == 0 2482132727Skan#if !defined (HAVE_prologue) 2483132727Skan && !ACCUMULATE_OUTGOING_ARGS 2484132727Skan#endif 248590087Sobrien && dwarf2out_do_frame ()) 2486169699Skan dwarf2out_frame_debug (insn, true); 248750503Sobrien#endif 248850503Sobrien 248990087Sobrien current_output_insn = debug_insn = 0; 249018334Speter } 249118334Speter } 249218334Speter return NEXT_INSN (insn); 249318334Speter} 249418334Speter 2495169699Skan/* Return whether a source line note needs to be emitted before INSN. */ 249618334Speter 2497132727Skanstatic bool 2498132727Skannotice_source_line (rtx insn) 249918334Speter{ 2500132727Skan const char *filename = insn_file (insn); 2501132727Skan int linenum = insn_line (insn); 250218334Speter 2503169699Skan if (filename 2504169699Skan && (force_source_line 2505169699Skan || filename != last_filename 2506169699Skan || last_linenum != linenum)) 2507132727Skan { 2508169699Skan force_source_line = false; 2509132727Skan last_filename = filename; 2510132727Skan last_linenum = linenum; 2511132727Skan high_block_linenum = MAX (last_linenum, high_block_linenum); 2512132727Skan high_function_linenum = MAX (last_linenum, high_function_linenum); 2513132727Skan return true; 2514132727Skan } 2515132727Skan return false; 251618334Speter} 251718334Speter 251852515Sobrien/* For each operand in INSN, simplify (subreg (reg)) so that it refers 251952515Sobrien directly to the desired hard register. */ 252090087Sobrien 252152515Sobrienvoid 2522132727Skancleanup_subreg_operands (rtx insn) 252352515Sobrien{ 252452515Sobrien int i; 252590087Sobrien extract_insn_cached (insn); 252690087Sobrien for (i = 0; i < recog_data.n_operands; i++) 252752515Sobrien { 2528132727Skan /* The following test cannot use recog_data.operand when testing 252990087Sobrien for a SUBREG: the underlying object might have been changed 253090087Sobrien already if we are inside a match_operator expression that 253190087Sobrien matches the else clause. Instead we test the underlying 253290087Sobrien expression directly. */ 253390087Sobrien if (GET_CODE (*recog_data.operand_loc[i]) == SUBREG) 253490087Sobrien recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]); 253590087Sobrien else if (GET_CODE (recog_data.operand[i]) == PLUS 253690087Sobrien || GET_CODE (recog_data.operand[i]) == MULT 2537169699Skan || MEM_P (recog_data.operand[i])) 253890087Sobrien recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i]); 253952515Sobrien } 254052515Sobrien 254190087Sobrien for (i = 0; i < recog_data.n_dups; i++) 254252515Sobrien { 254390087Sobrien if (GET_CODE (*recog_data.dup_loc[i]) == SUBREG) 254490087Sobrien *recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]); 254590087Sobrien else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS 254690087Sobrien || GET_CODE (*recog_data.dup_loc[i]) == MULT 2547169699Skan || MEM_P (*recog_data.dup_loc[i])) 254890087Sobrien *recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]); 254952515Sobrien } 255052515Sobrien} 255152515Sobrien 255218334Speter/* If X is a SUBREG, replace it with a REG or a MEM, 255318334Speter based on the thing it is a subreg of. */ 255418334Speter 255518334Speterrtx 2556132727Skanalter_subreg (rtx *xp) 255718334Speter{ 255890087Sobrien rtx x = *xp; 255990087Sobrien rtx y = SUBREG_REG (x); 256050503Sobrien 256190087Sobrien /* simplify_subreg does not remove subreg from volatile references. 256290087Sobrien We are required to. */ 2563169699Skan if (MEM_P (y)) 2564169699Skan { 2565169699Skan int offset = SUBREG_BYTE (x); 2566169699Skan 2567169699Skan /* For paradoxical subregs on big-endian machines, SUBREG_BYTE 2568169699Skan contains 0 instead of the proper offset. See simplify_subreg. */ 2569169699Skan if (offset == 0 2570169699Skan && GET_MODE_SIZE (GET_MODE (y)) < GET_MODE_SIZE (GET_MODE (x))) 2571169699Skan { 2572169699Skan int difference = GET_MODE_SIZE (GET_MODE (y)) 2573169699Skan - GET_MODE_SIZE (GET_MODE (x)); 2574169699Skan if (WORDS_BIG_ENDIAN) 2575169699Skan offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; 2576169699Skan if (BYTES_BIG_ENDIAN) 2577169699Skan offset += difference % UNITS_PER_WORD; 2578169699Skan } 2579169699Skan 2580169699Skan *xp = adjust_address (y, GET_MODE (x), offset); 2581169699Skan } 258290087Sobrien else 258318334Speter { 258490087Sobrien rtx new = simplify_subreg (GET_MODE (x), y, GET_MODE (y), 258590087Sobrien SUBREG_BYTE (x)); 258650503Sobrien 258790087Sobrien if (new != 0) 258890087Sobrien *xp = new; 2589169699Skan else if (REG_P (y)) 259090087Sobrien { 2591169699Skan /* Simplify_subreg can't handle some REG cases, but we have to. */ 2592169699Skan unsigned int regno = subreg_regno (x); 2593132727Skan *xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, SUBREG_BYTE (x)); 259490087Sobrien } 259518334Speter } 259618334Speter 259790087Sobrien return *xp; 259818334Speter} 259918334Speter 260018334Speter/* Do alter_subreg on all the SUBREGs contained in X. */ 260118334Speter 260218334Speterstatic rtx 2603132727Skanwalk_alter_subreg (rtx *xp) 260418334Speter{ 260590087Sobrien rtx x = *xp; 260618334Speter switch (GET_CODE (x)) 260718334Speter { 260818334Speter case PLUS: 260918334Speter case MULT: 2610169699Skan case AND: 261190087Sobrien XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0)); 261290087Sobrien XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1)); 261318334Speter break; 261418334Speter 261518334Speter case MEM: 2616169699Skan case ZERO_EXTEND: 261790087Sobrien XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0)); 261818334Speter break; 261918334Speter 262018334Speter case SUBREG: 262190087Sobrien return alter_subreg (xp); 262290087Sobrien 262350503Sobrien default: 262450503Sobrien break; 262518334Speter } 262618334Speter 262790087Sobrien return *xp; 262818334Speter} 262918334Speter 263018334Speter#ifdef HAVE_cc0 263118334Speter 263218334Speter/* Given BODY, the body of a jump instruction, alter the jump condition 263318334Speter as required by the bits that are set in cc_status.flags. 263418334Speter Not all of the bits there can be handled at this level in all cases. 263518334Speter 263618334Speter The value is normally 0. 263718334Speter 1 means that the condition has become always true. 263818334Speter -1 means that the condition has become always false. 263918334Speter 2 means that COND has been altered. */ 264018334Speter 264118334Speterstatic int 2642132727Skanalter_cond (rtx cond) 264318334Speter{ 264418334Speter int value = 0; 264518334Speter 264618334Speter if (cc_status.flags & CC_REVERSED) 264718334Speter { 264818334Speter value = 2; 264918334Speter PUT_CODE (cond, swap_condition (GET_CODE (cond))); 265018334Speter } 265118334Speter 265218334Speter if (cc_status.flags & CC_INVERTED) 265318334Speter { 265418334Speter value = 2; 265518334Speter PUT_CODE (cond, reverse_condition (GET_CODE (cond))); 265618334Speter } 265718334Speter 265818334Speter if (cc_status.flags & CC_NOT_POSITIVE) 265918334Speter switch (GET_CODE (cond)) 266018334Speter { 266118334Speter case LE: 266218334Speter case LEU: 266318334Speter case GEU: 266418334Speter /* Jump becomes unconditional. */ 266518334Speter return 1; 266618334Speter 266718334Speter case GT: 266818334Speter case GTU: 266918334Speter case LTU: 267018334Speter /* Jump becomes no-op. */ 267118334Speter return -1; 267218334Speter 267318334Speter case GE: 267418334Speter PUT_CODE (cond, EQ); 267518334Speter value = 2; 267618334Speter break; 267718334Speter 267818334Speter case LT: 267918334Speter PUT_CODE (cond, NE); 268018334Speter value = 2; 268118334Speter break; 268290087Sobrien 268350503Sobrien default: 268450503Sobrien break; 268518334Speter } 268618334Speter 268718334Speter if (cc_status.flags & CC_NOT_NEGATIVE) 268818334Speter switch (GET_CODE (cond)) 268918334Speter { 269018334Speter case GE: 269118334Speter case GEU: 269218334Speter /* Jump becomes unconditional. */ 269318334Speter return 1; 269418334Speter 269518334Speter case LT: 269618334Speter case LTU: 269718334Speter /* Jump becomes no-op. */ 269818334Speter return -1; 269918334Speter 270018334Speter case LE: 270118334Speter case LEU: 270218334Speter PUT_CODE (cond, EQ); 270318334Speter value = 2; 270418334Speter break; 270518334Speter 270618334Speter case GT: 270718334Speter case GTU: 270818334Speter PUT_CODE (cond, NE); 270918334Speter value = 2; 271018334Speter break; 271190087Sobrien 271250503Sobrien default: 271350503Sobrien break; 271418334Speter } 271518334Speter 271618334Speter if (cc_status.flags & CC_NO_OVERFLOW) 271718334Speter switch (GET_CODE (cond)) 271818334Speter { 271918334Speter case GEU: 272018334Speter /* Jump becomes unconditional. */ 272118334Speter return 1; 272218334Speter 272318334Speter case LEU: 272418334Speter PUT_CODE (cond, EQ); 272518334Speter value = 2; 272618334Speter break; 272718334Speter 272818334Speter case GTU: 272918334Speter PUT_CODE (cond, NE); 273018334Speter value = 2; 273118334Speter break; 273218334Speter 273318334Speter case LTU: 273418334Speter /* Jump becomes no-op. */ 273518334Speter return -1; 273690087Sobrien 273750503Sobrien default: 273850503Sobrien break; 273918334Speter } 274018334Speter 274118334Speter if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N)) 274218334Speter switch (GET_CODE (cond)) 274318334Speter { 274450503Sobrien default: 2745169699Skan gcc_unreachable (); 274618334Speter 274718334Speter case NE: 274818334Speter PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT); 274918334Speter value = 2; 275018334Speter break; 275118334Speter 275218334Speter case EQ: 275318334Speter PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE); 275418334Speter value = 2; 275518334Speter break; 275618334Speter } 275718334Speter 275818334Speter if (cc_status.flags & CC_NOT_SIGNED) 275918334Speter /* The flags are valid if signed condition operators are converted 276018334Speter to unsigned. */ 276118334Speter switch (GET_CODE (cond)) 276218334Speter { 276318334Speter case LE: 276418334Speter PUT_CODE (cond, LEU); 276518334Speter value = 2; 276618334Speter break; 276718334Speter 276818334Speter case LT: 276918334Speter PUT_CODE (cond, LTU); 277018334Speter value = 2; 277118334Speter break; 277218334Speter 277318334Speter case GT: 277418334Speter PUT_CODE (cond, GTU); 277518334Speter value = 2; 277618334Speter break; 277718334Speter 277818334Speter case GE: 277918334Speter PUT_CODE (cond, GEU); 278018334Speter value = 2; 278118334Speter break; 278250503Sobrien 278350503Sobrien default: 278450503Sobrien break; 278518334Speter } 278618334Speter 278718334Speter return value; 278818334Speter} 278918334Speter#endif 279018334Speter 279118334Speter/* Report inconsistency between the assembler template and the operands. 279218334Speter In an `asm', it's the user's fault; otherwise, the compiler's fault. */ 279318334Speter 279418334Spetervoid 2795169699Skanoutput_operand_lossage (const char *cmsgid, ...) 279618334Speter{ 279796281Sobrien char *fmt_string; 279896281Sobrien char *new_message; 279996281Sobrien const char *pfx_str; 2800132727Skan va_list ap; 280196281Sobrien 2802169699Skan va_start (ap, cmsgid); 2803132727Skan 2804169699Skan pfx_str = this_is_asm_operands ? _("invalid 'asm': ") : "output_operand: "; 2805169699Skan asprintf (&fmt_string, "%s%s", pfx_str, _(cmsgid)); 280696281Sobrien vasprintf (&new_message, fmt_string, ap); 2807117404Skan 280818334Speter if (this_is_asm_operands) 280996281Sobrien error_for_asm (this_is_asm_operands, "%s", new_message); 281018334Speter else 281196281Sobrien internal_error ("%s", new_message); 281296281Sobrien 281396281Sobrien free (fmt_string); 281496281Sobrien free (new_message); 2815132727Skan va_end (ap); 281618334Speter} 281718334Speter 281818334Speter/* Output of assembler code from a template, and its subroutines. */ 281918334Speter 282090087Sobrien/* Annotate the assembly with a comment describing the pattern and 282190087Sobrien alternative used. */ 282290087Sobrien 282390087Sobrienstatic void 2824132727Skanoutput_asm_name (void) 282590087Sobrien{ 282690087Sobrien if (debug_insn) 282790087Sobrien { 282890087Sobrien int num = INSN_CODE (debug_insn); 282990087Sobrien fprintf (asm_out_file, "\t%s %d\t%s", 283090087Sobrien ASM_COMMENT_START, INSN_UID (debug_insn), 283190087Sobrien insn_data[num].name); 283290087Sobrien if (insn_data[num].n_alternatives > 1) 283390087Sobrien fprintf (asm_out_file, "/%d", which_alternative + 1); 283490087Sobrien#ifdef HAVE_ATTR_length 283590087Sobrien fprintf (asm_out_file, "\t[length = %d]", 283690087Sobrien get_attr_length (debug_insn)); 283790087Sobrien#endif 283890087Sobrien /* Clear this so only the first assembler insn 283990087Sobrien of any rtl insn will get the special comment for -dp. */ 284090087Sobrien debug_insn = 0; 284190087Sobrien } 284290087Sobrien} 284390087Sobrien 284490087Sobrien/* If OP is a REG or MEM and we can find a MEM_EXPR corresponding to it 284590087Sobrien or its address, return that expr . Set *PADDRESSP to 1 if the expr 284690087Sobrien corresponds to the address of the object and 0 if to the object. */ 284790087Sobrien 284890087Sobrienstatic tree 2849132727Skanget_mem_expr_from_op (rtx op, int *paddressp) 285090087Sobrien{ 285190087Sobrien tree expr; 285290087Sobrien int inner_addressp; 285390087Sobrien 285490087Sobrien *paddressp = 0; 285590087Sobrien 2856169699Skan if (REG_P (op)) 2857132727Skan return REG_EXPR (op); 2858169699Skan else if (!MEM_P (op)) 285990087Sobrien return 0; 286090087Sobrien 286190087Sobrien if (MEM_EXPR (op) != 0) 286290087Sobrien return MEM_EXPR (op); 286390087Sobrien 286490087Sobrien /* Otherwise we have an address, so indicate it and look at the address. */ 286590087Sobrien *paddressp = 1; 286690087Sobrien op = XEXP (op, 0); 286790087Sobrien 286890087Sobrien /* First check if we have a decl for the address, then look at the right side 286990087Sobrien if it is a PLUS. Otherwise, strip off arithmetic and keep looking. 287090087Sobrien But don't allow the address to itself be indirect. */ 287190087Sobrien if ((expr = get_mem_expr_from_op (op, &inner_addressp)) && ! inner_addressp) 287290087Sobrien return expr; 287390087Sobrien else if (GET_CODE (op) == PLUS 287490087Sobrien && (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp))) 287590087Sobrien return expr; 287690087Sobrien 2877169699Skan while (GET_RTX_CLASS (GET_CODE (op)) == RTX_UNARY 2878169699Skan || GET_RTX_CLASS (GET_CODE (op)) == RTX_BIN_ARITH) 287990087Sobrien op = XEXP (op, 0); 288090087Sobrien 288190087Sobrien expr = get_mem_expr_from_op (op, &inner_addressp); 288290087Sobrien return inner_addressp ? 0 : expr; 288390087Sobrien} 288490087Sobrien 288590087Sobrien/* Output operand names for assembler instructions. OPERANDS is the 288690087Sobrien operand vector, OPORDER is the order to write the operands, and NOPS 288790087Sobrien is the number of operands to write. */ 288890087Sobrien 288990087Sobrienstatic void 2890132727Skanoutput_asm_operand_names (rtx *operands, int *oporder, int nops) 289190087Sobrien{ 289290087Sobrien int wrote = 0; 289390087Sobrien int i; 289490087Sobrien 289590087Sobrien for (i = 0; i < nops; i++) 289690087Sobrien { 289790087Sobrien int addressp; 2898132727Skan rtx op = operands[oporder[i]]; 2899132727Skan tree expr = get_mem_expr_from_op (op, &addressp); 290090087Sobrien 2901132727Skan fprintf (asm_out_file, "%c%s", 2902132727Skan wrote ? ',' : '\t', wrote ? "" : ASM_COMMENT_START); 2903132727Skan wrote = 1; 290490087Sobrien if (expr) 290590087Sobrien { 2906132727Skan fprintf (asm_out_file, "%s", 290790087Sobrien addressp ? "*" : ""); 290890087Sobrien print_mem_expr (asm_out_file, expr); 290990087Sobrien wrote = 1; 291090087Sobrien } 2911132727Skan else if (REG_P (op) && ORIGINAL_REGNO (op) 2912132727Skan && ORIGINAL_REGNO (op) != REGNO (op)) 2913132727Skan fprintf (asm_out_file, " tmp%i", ORIGINAL_REGNO (op)); 291490087Sobrien } 291590087Sobrien} 291690087Sobrien 291718334Speter/* Output text from TEMPLATE to the assembler output file, 291818334Speter obeying %-directions to substitute operands taken from 291918334Speter the vector OPERANDS. 292018334Speter 292118334Speter %N (for N a digit) means print operand N in usual manner. 292218334Speter %lN means require operand N to be a CODE_LABEL or LABEL_REF 292318334Speter and print the label name with no punctuation. 292418334Speter %cN means require operand N to be a constant 292518334Speter and print the constant expression with no punctuation. 292618334Speter %aN means expect operand N to be a memory address 292718334Speter (not a memory reference!) and print a reference 292818334Speter to that address. 292918334Speter %nN means expect operand N to be a constant 293018334Speter and print a constant expression for minus the value 293118334Speter of the operand, with no other punctuation. */ 293218334Speter 293318334Spetervoid 2934132727Skanoutput_asm_insn (const char *template, rtx *operands) 293518334Speter{ 293690087Sobrien const char *p; 293790087Sobrien int c; 293890087Sobrien#ifdef ASSEMBLER_DIALECT 293990087Sobrien int dialect = 0; 294090087Sobrien#endif 294190087Sobrien int oporder[MAX_RECOG_OPERANDS]; 294290087Sobrien char opoutput[MAX_RECOG_OPERANDS]; 294390087Sobrien int ops = 0; 294418334Speter 294518334Speter /* An insn may return a null string template 294618334Speter in a case where no assembler code is needed. */ 294718334Speter if (*template == 0) 294818334Speter return; 294918334Speter 295090087Sobrien memset (opoutput, 0, sizeof opoutput); 295118334Speter p = template; 295218334Speter putc ('\t', asm_out_file); 295318334Speter 295418334Speter#ifdef ASM_OUTPUT_OPCODE 295518334Speter ASM_OUTPUT_OPCODE (asm_out_file, p); 295618334Speter#endif 295718334Speter 295850503Sobrien while ((c = *p++)) 295918334Speter switch (c) 296018334Speter { 296118334Speter case '\n': 296290087Sobrien if (flag_verbose_asm) 296390087Sobrien output_asm_operand_names (operands, oporder, ops); 296490087Sobrien if (flag_print_asm_name) 296590087Sobrien output_asm_name (); 296690087Sobrien 296790087Sobrien ops = 0; 296890087Sobrien memset (opoutput, 0, sizeof opoutput); 296990087Sobrien 297018334Speter putc (c, asm_out_file); 297118334Speter#ifdef ASM_OUTPUT_OPCODE 297218334Speter while ((c = *p) == '\t') 297318334Speter { 297418334Speter putc (c, asm_out_file); 297518334Speter p++; 297618334Speter } 297718334Speter ASM_OUTPUT_OPCODE (asm_out_file, p); 297818334Speter#endif 297918334Speter break; 298018334Speter 298118334Speter#ifdef ASSEMBLER_DIALECT 298218334Speter case '{': 298350503Sobrien { 298490087Sobrien int i; 298590087Sobrien 298690087Sobrien if (dialect) 298790087Sobrien output_operand_lossage ("nested assembly dialect alternatives"); 298890087Sobrien else 298990087Sobrien dialect = 1; 299090087Sobrien 299150503Sobrien /* If we want the first dialect, do nothing. Otherwise, skip 299250503Sobrien DIALECT_NUMBER of strings ending with '|'. */ 299350503Sobrien for (i = 0; i < dialect_number; i++) 299450503Sobrien { 299590087Sobrien while (*p && *p != '}' && *p++ != '|') 299650503Sobrien ; 299790087Sobrien if (*p == '}') 299890087Sobrien break; 299950503Sobrien if (*p == '|') 300050503Sobrien p++; 300150503Sobrien } 300290087Sobrien 300390087Sobrien if (*p == '\0') 300490087Sobrien output_operand_lossage ("unterminated assembly dialect alternative"); 300550503Sobrien } 300618334Speter break; 300718334Speter 300818334Speter case '|': 300990087Sobrien if (dialect) 301090087Sobrien { 301190087Sobrien /* Skip to close brace. */ 301290087Sobrien do 301390087Sobrien { 301490087Sobrien if (*p == '\0') 301590087Sobrien { 301690087Sobrien output_operand_lossage ("unterminated assembly dialect alternative"); 301790087Sobrien break; 301890087Sobrien } 301990087Sobrien } 302090087Sobrien while (*p++ != '}'); 302190087Sobrien dialect = 0; 302290087Sobrien } 302390087Sobrien else 302490087Sobrien putc (c, asm_out_file); 302518334Speter break; 302618334Speter 302718334Speter case '}': 302890087Sobrien if (! dialect) 302990087Sobrien putc (c, asm_out_file); 303090087Sobrien dialect = 0; 303118334Speter break; 303218334Speter#endif 303318334Speter 303418334Speter case '%': 303518334Speter /* %% outputs a single %. */ 303618334Speter if (*p == '%') 303718334Speter { 303818334Speter p++; 303918334Speter putc (c, asm_out_file); 304018334Speter } 304118334Speter /* %= outputs a number which is unique to each insn in the entire 304218334Speter compilation. This is useful for making local labels that are 304318334Speter referred to more than once in a given insn. */ 304418334Speter else if (*p == '=') 304518334Speter { 304618334Speter p++; 304718334Speter fprintf (asm_out_file, "%d", insn_counter); 304818334Speter } 304918334Speter /* % followed by a letter and some digits 305018334Speter outputs an operand in a special way depending on the letter. 305118334Speter Letters `acln' are implemented directly. 305218334Speter Other letters are passed to `output_operand' so that 305318334Speter the PRINT_OPERAND macro can define them. */ 305490087Sobrien else if (ISALPHA (*p)) 305518334Speter { 305618334Speter int letter = *p++; 3057169699Skan unsigned long opnum; 3058169699Skan char *endptr; 305918334Speter 3060169699Skan opnum = strtoul (p, &endptr, 10); 3061169699Skan 3062169699Skan if (endptr == p) 3063169699Skan output_operand_lossage ("operand number missing " 3064169699Skan "after %%-letter"); 3065169699Skan else if (this_is_asm_operands && opnum >= insn_noperands) 306618334Speter output_operand_lossage ("operand number out of range"); 306718334Speter else if (letter == 'l') 3068169699Skan output_asm_label (operands[opnum]); 306918334Speter else if (letter == 'a') 3070169699Skan output_address (operands[opnum]); 307118334Speter else if (letter == 'c') 307218334Speter { 3073169699Skan if (CONSTANT_ADDRESS_P (operands[opnum])) 3074169699Skan output_addr_const (asm_out_file, operands[opnum]); 307518334Speter else 3076169699Skan output_operand (operands[opnum], 'c'); 307718334Speter } 307818334Speter else if (letter == 'n') 307918334Speter { 3080169699Skan if (GET_CODE (operands[opnum]) == CONST_INT) 308150503Sobrien fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, 3082169699Skan - INTVAL (operands[opnum])); 308318334Speter else 308418334Speter { 308518334Speter putc ('-', asm_out_file); 3086169699Skan output_addr_const (asm_out_file, operands[opnum]); 308718334Speter } 308818334Speter } 308918334Speter else 3090169699Skan output_operand (operands[opnum], letter); 309190087Sobrien 3092169699Skan if (!opoutput[opnum]) 3093169699Skan oporder[ops++] = opnum; 3094169699Skan opoutput[opnum] = 1; 309590087Sobrien 3096169699Skan p = endptr; 3097169699Skan c = *p; 309818334Speter } 309918334Speter /* % followed by a digit outputs an operand the default way. */ 310090087Sobrien else if (ISDIGIT (*p)) 310118334Speter { 3102169699Skan unsigned long opnum; 3103169699Skan char *endptr; 3104169699Skan 3105169699Skan opnum = strtoul (p, &endptr, 10); 3106169699Skan if (this_is_asm_operands && opnum >= insn_noperands) 310718334Speter output_operand_lossage ("operand number out of range"); 310818334Speter else 3109169699Skan output_operand (operands[opnum], 0); 311090087Sobrien 3111169699Skan if (!opoutput[opnum]) 3112169699Skan oporder[ops++] = opnum; 3113169699Skan opoutput[opnum] = 1; 311490087Sobrien 3115169699Skan p = endptr; 3116169699Skan c = *p; 311718334Speter } 311818334Speter /* % followed by punctuation: output something for that 311918334Speter punctuation character alone, with no operand. 312018334Speter The PRINT_OPERAND macro decides what is actually done. */ 312118334Speter#ifdef PRINT_OPERAND_PUNCT_VALID_P 312290087Sobrien else if (PRINT_OPERAND_PUNCT_VALID_P ((unsigned char) *p)) 312318334Speter output_operand (NULL_RTX, *p++); 312418334Speter#endif 312518334Speter else 312618334Speter output_operand_lossage ("invalid %%-code"); 312718334Speter break; 312818334Speter 312918334Speter default: 313018334Speter putc (c, asm_out_file); 313118334Speter } 313218334Speter 313390087Sobrien /* Write out the variable names for operands, if we know them. */ 313490087Sobrien if (flag_verbose_asm) 313590087Sobrien output_asm_operand_names (operands, oporder, ops); 313690087Sobrien if (flag_print_asm_name) 313790087Sobrien output_asm_name (); 313818334Speter 313918334Speter putc ('\n', asm_out_file); 314018334Speter} 314118334Speter 314218334Speter/* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol. */ 314318334Speter 314418334Spetervoid 3145132727Skanoutput_asm_label (rtx x) 314618334Speter{ 314718334Speter char buf[256]; 314818334Speter 314918334Speter if (GET_CODE (x) == LABEL_REF) 315090087Sobrien x = XEXP (x, 0); 3151169699Skan if (LABEL_P (x) 3152169699Skan || (NOTE_P (x) 315390087Sobrien && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL)) 315418334Speter ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); 315518334Speter else 3156169699Skan output_operand_lossage ("'%%l' operand isn't a label"); 315718334Speter 315818334Speter assemble_name (asm_out_file, buf); 315918334Speter} 316018334Speter 316118334Speter/* Print operand X using machine-dependent assembler syntax. 316218334Speter The macro PRINT_OPERAND is defined just to control this function. 316318334Speter CODE is a non-digit that preceded the operand-number in the % spec, 316418334Speter such as 'z' if the spec was `%z3'. CODE is 0 if there was no char 316518334Speter between the % and the digits. 316618334Speter When CODE is a non-letter, X is 0. 316718334Speter 316818334Speter The meanings of the letters are machine-dependent and controlled 316918334Speter by PRINT_OPERAND. */ 317018334Speter 317118334Speterstatic void 3172132727Skanoutput_operand (rtx x, int code ATTRIBUTE_UNUSED) 317318334Speter{ 317418334Speter if (x && GET_CODE (x) == SUBREG) 317590087Sobrien x = alter_subreg (&x); 317618334Speter 3177169699Skan /* X must not be a pseudo reg. */ 3178169699Skan gcc_assert (!x || !REG_P (x) || REGNO (x) < FIRST_PSEUDO_REGISTER); 317918334Speter 318018334Speter PRINT_OPERAND (asm_out_file, x, code); 318118334Speter} 318218334Speter 318318334Speter/* Print a memory reference operand for address X 318418334Speter using machine-dependent assembler syntax. 318518334Speter The macro PRINT_OPERAND_ADDRESS exists just to control this function. */ 318618334Speter 318718334Spetervoid 3188132727Skanoutput_address (rtx x) 318918334Speter{ 319090087Sobrien walk_alter_subreg (&x); 319118334Speter PRINT_OPERAND_ADDRESS (asm_out_file, x); 319218334Speter} 319318334Speter 319418334Speter/* Print an integer constant expression in assembler syntax. 319518334Speter Addition and subtraction are the only arithmetic 319618334Speter that may appear in these expressions. */ 319718334Speter 319818334Spetervoid 3199132727Skanoutput_addr_const (FILE *file, rtx x) 320018334Speter{ 320118334Speter char buf[256]; 320218334Speter 320318334Speter restart: 320418334Speter switch (GET_CODE (x)) 320518334Speter { 320618334Speter case PC: 320790087Sobrien putc ('.', file); 320818334Speter break; 320918334Speter 321018334Speter case SYMBOL_REF: 3211169699Skan if (SYMBOL_REF_DECL (x)) 3212169699Skan mark_decl_referenced (SYMBOL_REF_DECL (x)); 321390087Sobrien#ifdef ASM_OUTPUT_SYMBOL_REF 321490087Sobrien ASM_OUTPUT_SYMBOL_REF (file, x); 321590087Sobrien#else 321618334Speter assemble_name (file, XSTR (x, 0)); 321790087Sobrien#endif 321818334Speter break; 321918334Speter 322018334Speter case LABEL_REF: 322190087Sobrien x = XEXP (x, 0); 322290087Sobrien /* Fall through. */ 322318334Speter case CODE_LABEL: 322418334Speter ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); 322590087Sobrien#ifdef ASM_OUTPUT_LABEL_REF 322690087Sobrien ASM_OUTPUT_LABEL_REF (file, buf); 322790087Sobrien#else 322818334Speter assemble_name (file, buf); 322990087Sobrien#endif 323018334Speter break; 323118334Speter 323218334Speter case CONST_INT: 323350503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); 323418334Speter break; 323518334Speter 323618334Speter case CONST: 323718334Speter /* This used to output parentheses around the expression, 323818334Speter but that does not work on the 386 (either ATT or BSD assembler). */ 323918334Speter output_addr_const (file, XEXP (x, 0)); 324018334Speter break; 324118334Speter 324218334Speter case CONST_DOUBLE: 324318334Speter if (GET_MODE (x) == VOIDmode) 324418334Speter { 324518334Speter /* We can use %d if the number is one word and positive. */ 324618334Speter if (CONST_DOUBLE_HIGH (x)) 324750503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX, 324818334Speter CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x)); 324990087Sobrien else if (CONST_DOUBLE_LOW (x) < 0) 325050503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x)); 325118334Speter else 325250503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x)); 325318334Speter } 325418334Speter else 325518334Speter /* We can't handle floating point constants; 325618334Speter PRINT_OPERAND must handle them. */ 325718334Speter output_operand_lossage ("floating constant misused"); 325818334Speter break; 325918334Speter 326018334Speter case PLUS: 326118334Speter /* Some assemblers need integer constants to appear last (eg masm). */ 326218334Speter if (GET_CODE (XEXP (x, 0)) == CONST_INT) 326318334Speter { 326418334Speter output_addr_const (file, XEXP (x, 1)); 326518334Speter if (INTVAL (XEXP (x, 0)) >= 0) 326618334Speter fprintf (file, "+"); 326718334Speter output_addr_const (file, XEXP (x, 0)); 326818334Speter } 326918334Speter else 327018334Speter { 327118334Speter output_addr_const (file, XEXP (x, 0)); 327290087Sobrien if (GET_CODE (XEXP (x, 1)) != CONST_INT 327390087Sobrien || INTVAL (XEXP (x, 1)) >= 0) 327418334Speter fprintf (file, "+"); 327518334Speter output_addr_const (file, XEXP (x, 1)); 327618334Speter } 327718334Speter break; 327818334Speter 327918334Speter case MINUS: 328018334Speter /* Avoid outputting things like x-x or x+5-x, 328118334Speter since some assemblers can't handle that. */ 328218334Speter x = simplify_subtraction (x); 328318334Speter if (GET_CODE (x) != MINUS) 328418334Speter goto restart; 328518334Speter 328618334Speter output_addr_const (file, XEXP (x, 0)); 328718334Speter fprintf (file, "-"); 328890087Sobrien if ((GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0) 328990087Sobrien || GET_CODE (XEXP (x, 1)) == PC 329090087Sobrien || GET_CODE (XEXP (x, 1)) == SYMBOL_REF) 329190087Sobrien output_addr_const (file, XEXP (x, 1)); 329290087Sobrien else 329318334Speter { 329490087Sobrien fputs (targetm.asm_out.open_paren, file); 329518334Speter output_addr_const (file, XEXP (x, 1)); 329690087Sobrien fputs (targetm.asm_out.close_paren, file); 329718334Speter } 329818334Speter break; 329918334Speter 330018334Speter case ZERO_EXTEND: 330118334Speter case SIGN_EXTEND: 330296281Sobrien case SUBREG: 330318334Speter output_addr_const (file, XEXP (x, 0)); 330418334Speter break; 330518334Speter 330618334Speter default: 330790087Sobrien#ifdef OUTPUT_ADDR_CONST_EXTRA 330890087Sobrien OUTPUT_ADDR_CONST_EXTRA (file, x, fail); 330990087Sobrien break; 331090087Sobrien 331190087Sobrien fail: 331290087Sobrien#endif 331318334Speter output_operand_lossage ("invalid expression as operand"); 331418334Speter } 331518334Speter} 331618334Speter 331718334Speter/* A poor man's fprintf, with the added features of %I, %R, %L, and %U. 331818334Speter %R prints the value of REGISTER_PREFIX. 331918334Speter %L prints the value of LOCAL_LABEL_PREFIX. 332018334Speter %U prints the value of USER_LABEL_PREFIX. 332118334Speter %I prints the value of IMMEDIATE_PREFIX. 332218334Speter %O runs ASM_OUTPUT_OPCODE to transform what follows in the string. 3323132727Skan Also supported are %d, %i, %u, %x, %X, %o, %c, %s and %%. 332418334Speter 332518334Speter We handle alternate assembler dialects here, just like output_asm_insn. */ 332618334Speter 332718334Spetervoid 3328132727Skanasm_fprintf (FILE *file, const char *p, ...) 332918334Speter{ 333018334Speter char buf[10]; 333118334Speter char *q, c; 3332132727Skan va_list argptr; 333318334Speter 3334132727Skan va_start (argptr, p); 333518334Speter 333618334Speter buf[0] = '%'; 333718334Speter 333850503Sobrien while ((c = *p++)) 333918334Speter switch (c) 334018334Speter { 334118334Speter#ifdef ASSEMBLER_DIALECT 334218334Speter case '{': 334350503Sobrien { 334450503Sobrien int i; 334518334Speter 334650503Sobrien /* If we want the first dialect, do nothing. Otherwise, skip 334750503Sobrien DIALECT_NUMBER of strings ending with '|'. */ 334850503Sobrien for (i = 0; i < dialect_number; i++) 334950503Sobrien { 335050503Sobrien while (*p && *p++ != '|') 335150503Sobrien ; 335250503Sobrien 335350503Sobrien if (*p == '|') 335450503Sobrien p++; 335590087Sobrien } 335650503Sobrien } 335718334Speter break; 335818334Speter 335918334Speter case '|': 336018334Speter /* Skip to close brace. */ 336118334Speter while (*p && *p++ != '}') 336218334Speter ; 336318334Speter break; 336418334Speter 336518334Speter case '}': 336618334Speter break; 336718334Speter#endif 336818334Speter 336918334Speter case '%': 337018334Speter c = *p++; 337118334Speter q = &buf[1]; 3372132727Skan while (strchr ("-+ #0", c)) 3373132727Skan { 3374132727Skan *q++ = c; 3375132727Skan c = *p++; 3376132727Skan } 337790087Sobrien while (ISDIGIT (c) || c == '.') 337818334Speter { 337918334Speter *q++ = c; 338018334Speter c = *p++; 338118334Speter } 338218334Speter switch (c) 338318334Speter { 338418334Speter case '%': 3385132727Skan putc ('%', file); 338618334Speter break; 338718334Speter 338818334Speter case 'd': case 'i': case 'u': 3389132727Skan case 'x': case 'X': case 'o': 3390132727Skan case 'c': 339118334Speter *q++ = c; 339218334Speter *q = 0; 339318334Speter fprintf (file, buf, va_arg (argptr, int)); 339418334Speter break; 339518334Speter 339618334Speter case 'w': 3397132727Skan /* This is a prefix to the 'd', 'i', 'u', 'x', 'X', and 3398132727Skan 'o' cases, but we do not check for those cases. It 3399132727Skan means that the value is a HOST_WIDE_INT, which may be 3400132727Skan either `long' or `long long'. */ 3401132727Skan memcpy (q, HOST_WIDE_INT_PRINT, strlen (HOST_WIDE_INT_PRINT)); 3402132727Skan q += strlen (HOST_WIDE_INT_PRINT); 340318334Speter *q++ = *p++; 340418334Speter *q = 0; 340518334Speter fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT)); 340618334Speter break; 340718334Speter 340818334Speter case 'l': 340918334Speter *q++ = c; 3410132727Skan#ifdef HAVE_LONG_LONG 3411132727Skan if (*p == 'l') 3412132727Skan { 3413132727Skan *q++ = *p++; 3414132727Skan *q++ = *p++; 3415132727Skan *q = 0; 3416132727Skan fprintf (file, buf, va_arg (argptr, long long)); 3417132727Skan } 3418132727Skan else 3419132727Skan#endif 3420132727Skan { 3421132727Skan *q++ = *p++; 3422132727Skan *q = 0; 3423132727Skan fprintf (file, buf, va_arg (argptr, long)); 3424132727Skan } 342518334Speter 342618334Speter break; 342718334Speter 342818334Speter case 's': 342918334Speter *q++ = c; 343018334Speter *q = 0; 343118334Speter fprintf (file, buf, va_arg (argptr, char *)); 343218334Speter break; 343318334Speter 343418334Speter case 'O': 343518334Speter#ifdef ASM_OUTPUT_OPCODE 343618334Speter ASM_OUTPUT_OPCODE (asm_out_file, p); 343718334Speter#endif 343818334Speter break; 343918334Speter 344018334Speter case 'R': 344118334Speter#ifdef REGISTER_PREFIX 344218334Speter fprintf (file, "%s", REGISTER_PREFIX); 344318334Speter#endif 344418334Speter break; 344518334Speter 344618334Speter case 'I': 344718334Speter#ifdef IMMEDIATE_PREFIX 344818334Speter fprintf (file, "%s", IMMEDIATE_PREFIX); 344918334Speter#endif 345018334Speter break; 345118334Speter 345218334Speter case 'L': 345318334Speter#ifdef LOCAL_LABEL_PREFIX 345418334Speter fprintf (file, "%s", LOCAL_LABEL_PREFIX); 345518334Speter#endif 345618334Speter break; 345718334Speter 345818334Speter case 'U': 345952515Sobrien fputs (user_label_prefix, file); 346018334Speter break; 346118334Speter 346290087Sobrien#ifdef ASM_FPRINTF_EXTENSIONS 3463132727Skan /* Uppercase letters are reserved for general use by asm_fprintf 346490087Sobrien and so are not available to target specific code. In order to 346590087Sobrien prevent the ASM_FPRINTF_EXTENSIONS macro from using them then, 346690087Sobrien they are defined here. As they get turned into real extensions 346790087Sobrien to asm_fprintf they should be removed from this list. */ 346890087Sobrien case 'A': case 'B': case 'C': case 'D': case 'E': 346990087Sobrien case 'F': case 'G': case 'H': case 'J': case 'K': 347090087Sobrien case 'M': case 'N': case 'P': case 'Q': case 'S': 347190087Sobrien case 'T': case 'V': case 'W': case 'Y': case 'Z': 347290087Sobrien break; 347390087Sobrien 347490087Sobrien ASM_FPRINTF_EXTENSIONS (file, argptr, p) 347590087Sobrien#endif 347618334Speter default: 3477169699Skan gcc_unreachable (); 347818334Speter } 347918334Speter break; 348018334Speter 348118334Speter default: 3482132727Skan putc (c, file); 348318334Speter } 3484132727Skan va_end (argptr); 348518334Speter} 348618334Speter 348718334Speter/* Split up a CONST_DOUBLE or integer constant rtx 348818334Speter into two rtx's for single words, 348918334Speter storing in *FIRST the word that comes first in memory in the target 349018334Speter and in *SECOND the other. */ 349118334Speter 349218334Spetervoid 3493132727Skansplit_double (rtx value, rtx *first, rtx *second) 349418334Speter{ 349518334Speter if (GET_CODE (value) == CONST_INT) 349618334Speter { 349718334Speter if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD)) 349818334Speter { 349918334Speter /* In this case the CONST_INT holds both target words. 350050503Sobrien Extract the bits from it into two word-sized pieces. 350150503Sobrien Sign extend each half to HOST_WIDE_INT. */ 350290087Sobrien unsigned HOST_WIDE_INT low, high; 350390087Sobrien unsigned HOST_WIDE_INT mask, sign_bit, sign_extend; 350418334Speter 350590087Sobrien /* Set sign_bit to the most significant bit of a word. */ 350690087Sobrien sign_bit = 1; 350790087Sobrien sign_bit <<= BITS_PER_WORD - 1; 350890087Sobrien 350990087Sobrien /* Set mask so that all bits of the word are set. We could 351090087Sobrien have used 1 << BITS_PER_WORD instead of basing the 351190087Sobrien calculation on sign_bit. However, on machines where 351290087Sobrien HOST_BITS_PER_WIDE_INT == BITS_PER_WORD, it could cause a 351390087Sobrien compiler warning, even though the code would never be 351490087Sobrien executed. */ 351590087Sobrien mask = sign_bit << 1; 351690087Sobrien mask--; 351790087Sobrien 351890087Sobrien /* Set sign_extend as any remaining bits. */ 351990087Sobrien sign_extend = ~mask; 352090087Sobrien 352190087Sobrien /* Pick the lower word and sign-extend it. */ 352290087Sobrien low = INTVAL (value); 352390087Sobrien low &= mask; 352490087Sobrien if (low & sign_bit) 352590087Sobrien low |= sign_extend; 352690087Sobrien 352790087Sobrien /* Pick the higher word, shifted to the least significant 352890087Sobrien bits, and sign-extend it. */ 352990087Sobrien high = INTVAL (value); 353090087Sobrien high >>= BITS_PER_WORD - 1; 353190087Sobrien high >>= 1; 353290087Sobrien high &= mask; 353390087Sobrien if (high & sign_bit) 353490087Sobrien high |= sign_extend; 353590087Sobrien 353690087Sobrien /* Store the words in the target machine order. */ 353718334Speter if (WORDS_BIG_ENDIAN) 353818334Speter { 353990087Sobrien *first = GEN_INT (high); 354090087Sobrien *second = GEN_INT (low); 354118334Speter } 354218334Speter else 354318334Speter { 354490087Sobrien *first = GEN_INT (low); 354590087Sobrien *second = GEN_INT (high); 354618334Speter } 354718334Speter } 354818334Speter else 354918334Speter { 355018334Speter /* The rule for using CONST_INT for a wider mode 355118334Speter is that we regard the value as signed. 355218334Speter So sign-extend it. */ 355318334Speter rtx high = (INTVAL (value) < 0 ? constm1_rtx : const0_rtx); 355418334Speter if (WORDS_BIG_ENDIAN) 355518334Speter { 355618334Speter *first = high; 355718334Speter *second = value; 355818334Speter } 355918334Speter else 356018334Speter { 356118334Speter *first = value; 356218334Speter *second = high; 356318334Speter } 356418334Speter } 356518334Speter } 356618334Speter else if (GET_CODE (value) != CONST_DOUBLE) 356718334Speter { 356818334Speter if (WORDS_BIG_ENDIAN) 356918334Speter { 357018334Speter *first = const0_rtx; 357118334Speter *second = value; 357218334Speter } 357318334Speter else 357418334Speter { 357518334Speter *first = value; 357618334Speter *second = const0_rtx; 357718334Speter } 357818334Speter } 357918334Speter else if (GET_MODE (value) == VOIDmode 358018334Speter /* This is the old way we did CONST_DOUBLE integers. */ 358118334Speter || GET_MODE_CLASS (GET_MODE (value)) == MODE_INT) 358218334Speter { 358318334Speter /* In an integer, the words are defined as most and least significant. 358418334Speter So order them by the target's convention. */ 358518334Speter if (WORDS_BIG_ENDIAN) 358618334Speter { 358718334Speter *first = GEN_INT (CONST_DOUBLE_HIGH (value)); 358818334Speter *second = GEN_INT (CONST_DOUBLE_LOW (value)); 358918334Speter } 359018334Speter else 359118334Speter { 359218334Speter *first = GEN_INT (CONST_DOUBLE_LOW (value)); 359318334Speter *second = GEN_INT (CONST_DOUBLE_HIGH (value)); 359418334Speter } 359518334Speter } 359618334Speter else 359718334Speter { 359890087Sobrien REAL_VALUE_TYPE r; 359990087Sobrien long l[2]; 360018334Speter REAL_VALUE_FROM_CONST_DOUBLE (r, value); 360118334Speter 360218334Speter /* Note, this converts the REAL_VALUE_TYPE to the target's 360318334Speter format, splits up the floating point double and outputs 360418334Speter exactly 32 bits of it into each of l[0] and l[1] -- 360550503Sobrien not necessarily BITS_PER_WORD bits. */ 360618334Speter REAL_VALUE_TO_TARGET_DOUBLE (r, l); 360718334Speter 360852515Sobrien /* If 32 bits is an entire word for the target, but not for the host, 360952515Sobrien then sign-extend on the host so that the number will look the same 361052515Sobrien way on the host that it would on the target. See for instance 361152515Sobrien simplify_unary_operation. The #if is needed to avoid compiler 361252515Sobrien warnings. */ 361352515Sobrien 361452515Sobrien#if HOST_BITS_PER_LONG > 32 361552515Sobrien if (BITS_PER_WORD < HOST_BITS_PER_LONG && BITS_PER_WORD == 32) 361652515Sobrien { 361752515Sobrien if (l[0] & ((long) 1 << 31)) 361852515Sobrien l[0] |= ((long) (-1) << 32); 361952515Sobrien if (l[1] & ((long) 1 << 31)) 362052515Sobrien l[1] |= ((long) (-1) << 32); 362152515Sobrien } 362252515Sobrien#endif 362352515Sobrien 3624169699Skan *first = GEN_INT (l[0]); 3625169699Skan *second = GEN_INT (l[1]); 362618334Speter } 362718334Speter} 362818334Speter 362918334Speter/* Return nonzero if this function has no function calls. */ 363018334Speter 363118334Speterint 3632132727Skanleaf_function_p (void) 363318334Speter{ 363418334Speter rtx insn; 363590087Sobrien rtx link; 363618334Speter 363790087Sobrien if (current_function_profile || profile_arc_flag) 363818334Speter return 0; 363918334Speter 364018334Speter for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 364118334Speter { 3642169699Skan if (CALL_P (insn) 364390087Sobrien && ! SIBLING_CALL_P (insn)) 364418334Speter return 0; 3645169699Skan if (NONJUMP_INSN_P (insn) 364618334Speter && GET_CODE (PATTERN (insn)) == SEQUENCE 3647169699Skan && CALL_P (XVECEXP (PATTERN (insn), 0, 0)) 364890087Sobrien && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0))) 364918334Speter return 0; 365018334Speter } 365190087Sobrien for (link = current_function_epilogue_delay_list; 365290087Sobrien link; 365390087Sobrien link = XEXP (link, 1)) 365418334Speter { 365590087Sobrien insn = XEXP (link, 0); 365690087Sobrien 3657169699Skan if (CALL_P (insn) 365890087Sobrien && ! SIBLING_CALL_P (insn)) 365918334Speter return 0; 3660169699Skan if (NONJUMP_INSN_P (insn) 366190087Sobrien && GET_CODE (PATTERN (insn)) == SEQUENCE 3662169699Skan && CALL_P (XVECEXP (PATTERN (insn), 0, 0)) 366390087Sobrien && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0))) 366418334Speter return 0; 366518334Speter } 366618334Speter 366718334Speter return 1; 366818334Speter} 366918334Speter 3670117404Skan/* Return 1 if branch is a forward branch. 367190087Sobrien Uses insn_shuid array, so it works only in the final pass. May be used by 367290087Sobrien output templates to customary add branch prediction hints. 367390087Sobrien */ 367490087Sobrienint 3675132727Skanfinal_forward_branch_p (rtx insn) 367690087Sobrien{ 367790087Sobrien int insn_id, label_id; 3678169699Skan 3679169699Skan gcc_assert (uid_shuid); 368090087Sobrien insn_id = INSN_SHUID (insn); 368190087Sobrien label_id = INSN_SHUID (JUMP_LABEL (insn)); 368290087Sobrien /* We've hit some insns that does not have id information available. */ 3683169699Skan gcc_assert (insn_id && label_id); 368490087Sobrien return insn_id < label_id; 368590087Sobrien} 368690087Sobrien 368718334Speter/* On some machines, a function with no call insns 368818334Speter can run faster if it doesn't create its own register window. 368918334Speter When output, the leaf function should use only the "output" 369018334Speter registers. Ordinarily, the function would be compiled to use 369118334Speter the "input" registers to find its arguments; it is a candidate 369218334Speter for leaf treatment if it uses only the "input" registers. 369318334Speter Leaf function treatment means renumbering so the function 369418334Speter uses the "output" registers instead. */ 369518334Speter 369618334Speter#ifdef LEAF_REGISTERS 369718334Speter 369818334Speter/* Return 1 if this function uses only the registers that can be 369918334Speter safely renumbered. */ 370018334Speter 370118334Speterint 3702132727Skanonly_leaf_regs_used (void) 370318334Speter{ 370418334Speter int i; 3705132727Skan const char *const permitted_reg_in_leaf_functions = LEAF_REGISTERS; 370618334Speter 370718334Speter for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 370850503Sobrien if ((regs_ever_live[i] || global_regs[i]) 370950503Sobrien && ! permitted_reg_in_leaf_functions[i]) 371050503Sobrien return 0; 371150503Sobrien 371250503Sobrien if (current_function_uses_pic_offset_table 371350503Sobrien && pic_offset_table_rtx != 0 3714169699Skan && REG_P (pic_offset_table_rtx) 371550503Sobrien && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)]) 371650503Sobrien return 0; 371750503Sobrien 371818334Speter return 1; 371918334Speter} 372018334Speter 372118334Speter/* Scan all instructions and renumber all registers into those 372218334Speter available in leaf functions. */ 372318334Speter 372418334Speterstatic void 3725132727Skanleaf_renumber_regs (rtx first) 372618334Speter{ 372718334Speter rtx insn; 372818334Speter 372918334Speter /* Renumber only the actual patterns. 373018334Speter The reg-notes can contain frame pointer refs, 373118334Speter and renumbering them could crash, and should not be needed. */ 373218334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 373390087Sobrien if (INSN_P (insn)) 373418334Speter leaf_renumber_regs_insn (PATTERN (insn)); 373590087Sobrien for (insn = current_function_epilogue_delay_list; 373690087Sobrien insn; 373790087Sobrien insn = XEXP (insn, 1)) 373890087Sobrien if (INSN_P (XEXP (insn, 0))) 373918334Speter leaf_renumber_regs_insn (PATTERN (XEXP (insn, 0))); 374018334Speter} 374118334Speter 374218334Speter/* Scan IN_RTX and its subexpressions, and renumber all regs into those 374318334Speter available in leaf functions. */ 374418334Speter 374518334Spetervoid 3746132727Skanleaf_renumber_regs_insn (rtx in_rtx) 374718334Speter{ 374890087Sobrien int i, j; 374990087Sobrien const char *format_ptr; 375018334Speter 375118334Speter if (in_rtx == 0) 375218334Speter return; 375318334Speter 375418334Speter /* Renumber all input-registers into output-registers. 375518334Speter renumbered_regs would be 1 for an output-register; 375618334Speter they */ 375718334Speter 3758169699Skan if (REG_P (in_rtx)) 375918334Speter { 376018334Speter int newreg; 376118334Speter 376218334Speter /* Don't renumber the same reg twice. */ 376318334Speter if (in_rtx->used) 376418334Speter return; 376518334Speter 376618334Speter newreg = REGNO (in_rtx); 376718334Speter /* Don't try to renumber pseudo regs. It is possible for a pseudo reg 376818334Speter to reach here as part of a REG_NOTE. */ 376918334Speter if (newreg >= FIRST_PSEUDO_REGISTER) 377018334Speter { 377118334Speter in_rtx->used = 1; 377218334Speter return; 377318334Speter } 377418334Speter newreg = LEAF_REG_REMAP (newreg); 3775169699Skan gcc_assert (newreg >= 0); 377618334Speter regs_ever_live[REGNO (in_rtx)] = 0; 377718334Speter regs_ever_live[newreg] = 1; 377818334Speter REGNO (in_rtx) = newreg; 377918334Speter in_rtx->used = 1; 378018334Speter } 378118334Speter 378290087Sobrien if (INSN_P (in_rtx)) 378318334Speter { 378418334Speter /* Inside a SEQUENCE, we find insns. 378518334Speter Renumber just the patterns of these insns, 378618334Speter just as we do for the top-level insns. */ 378718334Speter leaf_renumber_regs_insn (PATTERN (in_rtx)); 378818334Speter return; 378918334Speter } 379018334Speter 379118334Speter format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx)); 379218334Speter 379318334Speter for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++) 379418334Speter switch (*format_ptr++) 379518334Speter { 379618334Speter case 'e': 379718334Speter leaf_renumber_regs_insn (XEXP (in_rtx, i)); 379818334Speter break; 379918334Speter 380018334Speter case 'E': 380118334Speter if (NULL != XVEC (in_rtx, i)) 380218334Speter { 380318334Speter for (j = 0; j < XVECLEN (in_rtx, i); j++) 380418334Speter leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j)); 380518334Speter } 380618334Speter break; 380718334Speter 380818334Speter case 'S': 380918334Speter case 's': 381018334Speter case '0': 381118334Speter case 'i': 381218334Speter case 'w': 381318334Speter case 'n': 381418334Speter case 'u': 381518334Speter break; 381618334Speter 381718334Speter default: 3818169699Skan gcc_unreachable (); 381918334Speter } 382018334Speter} 382118334Speter#endif 3822132727Skan 3823132727Skan 3824132727Skan/* When -gused is used, emit debug info for only used symbols. But in 3825132727Skan addition to the standard intercepted debug_hooks there are some direct 3826132727Skan calls into this file, i.e., dbxout_symbol, dbxout_parms, and dbxout_reg_params. 3827132727Skan Those routines may also be called from a higher level intercepted routine. So 3828132727Skan to prevent recording data for an inner call to one of these for an intercept, 3829132727Skan we maintain an intercept nesting counter (debug_nesting). We only save the 3830132727Skan intercepted arguments if the nesting is 1. */ 3831132727Skanint debug_nesting = 0; 3832132727Skan 3833132727Skanstatic tree *symbol_queue; 3834132727Skanint symbol_queue_index = 0; 3835132727Skanstatic int symbol_queue_size = 0; 3836132727Skan 3837132727Skan/* Generate the symbols for any queued up type symbols we encountered 3838132727Skan while generating the type info for some originally used symbol. 3839132727Skan This might generate additional entries in the queue. Only when 3840132727Skan the nesting depth goes to 0 is this routine called. */ 3841132727Skan 3842132727Skanvoid 3843132727Skandebug_flush_symbol_queue (void) 3844132727Skan{ 3845132727Skan int i; 3846132727Skan 3847132727Skan /* Make sure that additionally queued items are not flushed 3848132727Skan prematurely. */ 3849132727Skan 3850132727Skan ++debug_nesting; 3851132727Skan 3852132727Skan for (i = 0; i < symbol_queue_index; ++i) 3853132727Skan { 3854169699Skan /* If we pushed queued symbols then such symbols must be 3855132727Skan output no matter what anyone else says. Specifically, 3856132727Skan we need to make sure dbxout_symbol() thinks the symbol was 3857132727Skan used and also we need to override TYPE_DECL_SUPPRESS_DEBUG 3858132727Skan which may be set for outside reasons. */ 3859132727Skan int saved_tree_used = TREE_USED (symbol_queue[i]); 3860132727Skan int saved_suppress_debug = TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]); 3861132727Skan TREE_USED (symbol_queue[i]) = 1; 3862132727Skan TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = 0; 3863132727Skan 3864132727Skan#ifdef DBX_DEBUGGING_INFO 3865132727Skan dbxout_symbol (symbol_queue[i], 0); 3866132727Skan#endif 3867132727Skan 3868132727Skan TREE_USED (symbol_queue[i]) = saved_tree_used; 3869132727Skan TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = saved_suppress_debug; 3870132727Skan } 3871132727Skan 3872132727Skan symbol_queue_index = 0; 3873132727Skan --debug_nesting; 3874132727Skan} 3875132727Skan 3876132727Skan/* Queue a type symbol needed as part of the definition of a decl 3877132727Skan symbol. These symbols are generated when debug_flush_symbol_queue() 3878132727Skan is called. */ 3879132727Skan 3880132727Skanvoid 3881132727Skandebug_queue_symbol (tree decl) 3882132727Skan{ 3883132727Skan if (symbol_queue_index >= symbol_queue_size) 3884132727Skan { 3885132727Skan symbol_queue_size += 10; 3886132727Skan symbol_queue = xrealloc (symbol_queue, 3887132727Skan symbol_queue_size * sizeof (tree)); 3888132727Skan } 3889132727Skan 3890132727Skan symbol_queue[symbol_queue_index++] = decl; 3891132727Skan} 3892132727Skan 3893132727Skan/* Free symbol queue. */ 3894132727Skanvoid 3895132727Skandebug_free_queue (void) 3896132727Skan{ 3897132727Skan if (symbol_queue) 3898132727Skan { 3899132727Skan free (symbol_queue); 3900132727Skan symbol_queue = NULL; 3901132727Skan symbol_queue_size = 0; 3902132727Skan } 3903132727Skan} 3904169699Skan 3905169699Skan/* Turn the RTL into assembly. */ 3906169699Skanstatic unsigned int 3907169699Skanrest_of_handle_final (void) 3908169699Skan{ 3909169699Skan rtx x; 3910169699Skan const char *fnname; 3911169699Skan 3912169699Skan /* Get the function's name, as described by its RTL. This may be 3913169699Skan different from the DECL_NAME name used in the source file. */ 3914169699Skan 3915169699Skan x = DECL_RTL (current_function_decl); 3916169699Skan gcc_assert (MEM_P (x)); 3917169699Skan x = XEXP (x, 0); 3918169699Skan gcc_assert (GET_CODE (x) == SYMBOL_REF); 3919169699Skan fnname = XSTR (x, 0); 3920169699Skan 3921169699Skan assemble_start_function (current_function_decl, fnname); 3922169699Skan final_start_function (get_insns (), asm_out_file, optimize); 3923169699Skan final (get_insns (), asm_out_file, optimize); 3924169699Skan final_end_function (); 3925169699Skan 3926169699Skan#ifdef TARGET_UNWIND_INFO 3927169699Skan /* ??? The IA-64 ".handlerdata" directive must be issued before 3928169699Skan the ".endp" directive that closes the procedure descriptor. */ 3929169699Skan output_function_exception_table (); 3930169699Skan#endif 3931169699Skan 3932169699Skan assemble_end_function (current_function_decl, fnname); 3933169699Skan 3934169699Skan#ifndef TARGET_UNWIND_INFO 3935169699Skan /* Otherwise, it feels unclean to switch sections in the middle. */ 3936169699Skan output_function_exception_table (); 3937169699Skan#endif 3938169699Skan 3939169699Skan user_defined_section_attribute = false; 3940169699Skan 3941169699Skan if (! quiet_flag) 3942169699Skan fflush (asm_out_file); 3943169699Skan 3944169699Skan /* Release all memory allocated by flow. */ 3945169699Skan free_basic_block_vars (); 3946169699Skan 3947169699Skan /* Write DBX symbols if requested. */ 3948169699Skan 3949169699Skan /* Note that for those inline functions where we don't initially 3950169699Skan know for certain that we will be generating an out-of-line copy, 3951169699Skan the first invocation of this routine (rest_of_compilation) will 3952169699Skan skip over this code by doing a `goto exit_rest_of_compilation;'. 3953169699Skan Later on, wrapup_global_declarations will (indirectly) call 3954169699Skan rest_of_compilation again for those inline functions that need 3955169699Skan to have out-of-line copies generated. During that call, we 3956169699Skan *will* be routed past here. */ 3957169699Skan 3958169699Skan timevar_push (TV_SYMOUT); 3959169699Skan (*debug_hooks->function_decl) (current_function_decl); 3960169699Skan timevar_pop (TV_SYMOUT); 3961169699Skan return 0; 3962169699Skan} 3963169699Skan 3964169699Skanstruct tree_opt_pass pass_final = 3965169699Skan{ 3966169699Skan NULL, /* name */ 3967169699Skan NULL, /* gate */ 3968169699Skan rest_of_handle_final, /* execute */ 3969169699Skan NULL, /* sub */ 3970169699Skan NULL, /* next */ 3971169699Skan 0, /* static_pass_number */ 3972169699Skan TV_FINAL, /* tv_id */ 3973169699Skan 0, /* properties_required */ 3974169699Skan 0, /* properties_provided */ 3975169699Skan 0, /* properties_destroyed */ 3976169699Skan 0, /* todo_flags_start */ 3977169699Skan TODO_ggc_collect, /* todo_flags_finish */ 3978169699Skan 0 /* letter */ 3979169699Skan}; 3980169699Skan 3981169699Skan 3982169699Skanstatic unsigned int 3983169699Skanrest_of_handle_shorten_branches (void) 3984169699Skan{ 3985169699Skan /* Shorten branches. */ 3986169699Skan shorten_branches (get_insns ()); 3987169699Skan return 0; 3988169699Skan} 3989169699Skan 3990169699Skanstruct tree_opt_pass pass_shorten_branches = 3991169699Skan{ 3992169699Skan "shorten", /* name */ 3993169699Skan NULL, /* gate */ 3994169699Skan rest_of_handle_shorten_branches, /* execute */ 3995169699Skan NULL, /* sub */ 3996169699Skan NULL, /* next */ 3997169699Skan 0, /* static_pass_number */ 3998169699Skan TV_FINAL, /* tv_id */ 3999169699Skan 0, /* properties_required */ 4000169699Skan 0, /* properties_provided */ 4001169699Skan 0, /* properties_destroyed */ 4002169699Skan 0, /* todo_flags_start */ 4003169699Skan TODO_dump_func, /* todo_flags_finish */ 4004169699Skan 0 /* letter */ 4005169699Skan}; 4006169699Skan 4007169699Skan 4008169699Skanstatic unsigned int 4009169699Skanrest_of_clean_state (void) 4010169699Skan{ 4011169699Skan rtx insn, next; 4012169699Skan 4013169699Skan /* It is very important to decompose the RTL instruction chain here: 4014169699Skan debug information keeps pointing into CODE_LABEL insns inside the function 4015169699Skan body. If these remain pointing to the other insns, we end up preserving 4016169699Skan whole RTL chain and attached detailed debug info in memory. */ 4017169699Skan for (insn = get_insns (); insn; insn = next) 4018169699Skan { 4019169699Skan next = NEXT_INSN (insn); 4020169699Skan NEXT_INSN (insn) = NULL; 4021169699Skan PREV_INSN (insn) = NULL; 4022169699Skan } 4023169699Skan 4024169699Skan /* In case the function was not output, 4025169699Skan don't leave any temporary anonymous types 4026169699Skan queued up for sdb output. */ 4027169699Skan#ifdef SDB_DEBUGGING_INFO 4028169699Skan if (write_symbols == SDB_DEBUG) 4029169699Skan sdbout_types (NULL_TREE); 4030169699Skan#endif 4031169699Skan 4032169699Skan reload_completed = 0; 4033169699Skan epilogue_completed = 0; 4034169699Skan flow2_completed = 0; 4035169699Skan no_new_pseudos = 0; 4036169699Skan#ifdef STACK_REGS 4037169699Skan regstack_completed = 0; 4038169699Skan#endif 4039169699Skan 4040169699Skan /* Clear out the insn_length contents now that they are no 4041169699Skan longer valid. */ 4042169699Skan init_insn_lengths (); 4043169699Skan 4044169699Skan /* Show no temporary slots allocated. */ 4045169699Skan init_temp_slots (); 4046169699Skan 4047169699Skan free_basic_block_vars (); 4048169699Skan free_bb_for_insn (); 4049169699Skan 4050169699Skan 4051169699Skan if (targetm.binds_local_p (current_function_decl)) 4052169699Skan { 4053169699Skan int pref = cfun->preferred_stack_boundary; 4054169699Skan if (cfun->stack_alignment_needed > cfun->preferred_stack_boundary) 4055169699Skan pref = cfun->stack_alignment_needed; 4056169699Skan cgraph_rtl_info (current_function_decl)->preferred_incoming_stack_boundary 4057169699Skan = pref; 4058169699Skan } 4059169699Skan 4060169699Skan /* Make sure volatile mem refs aren't considered valid operands for 4061169699Skan arithmetic insns. We must call this here if this is a nested inline 4062169699Skan function, since the above code leaves us in the init_recog state, 4063169699Skan and the function context push/pop code does not save/restore volatile_ok. 4064169699Skan 4065169699Skan ??? Maybe it isn't necessary for expand_start_function to call this 4066169699Skan anymore if we do it here? */ 4067169699Skan 4068169699Skan init_recog_no_volatile (); 4069169699Skan 4070169699Skan /* We're done with this function. Free up memory if we can. */ 4071169699Skan free_after_parsing (cfun); 4072169699Skan free_after_compilation (cfun); 4073169699Skan return 0; 4074169699Skan} 4075169699Skan 4076169699Skanstruct tree_opt_pass pass_clean_state = 4077169699Skan{ 4078169699Skan NULL, /* name */ 4079169699Skan NULL, /* gate */ 4080169699Skan rest_of_clean_state, /* execute */ 4081169699Skan NULL, /* sub */ 4082169699Skan NULL, /* next */ 4083169699Skan 0, /* static_pass_number */ 4084169699Skan TV_FINAL, /* tv_id */ 4085169699Skan 0, /* properties_required */ 4086169699Skan 0, /* properties_provided */ 4087169699Skan PROP_rtl, /* properties_destroyed */ 4088169699Skan 0, /* todo_flags_start */ 4089169699Skan 0, /* todo_flags_finish */ 4090169699Skan 0 /* letter */ 4091169699Skan}; 4092