final.c revision 117404
118334Speter/* Convert RTL to assembler code and output it, for GNU compiler. 290087Sobrien Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 390087Sobrien 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. 418334Speter 590087SobrienThis file is part of GCC. 618334Speter 790087SobrienGCC is free software; you can redistribute it and/or modify it under 890087Sobrienthe terms of the GNU General Public License as published by the Free 990087SobrienSoftware Foundation; either version 2, or (at your option) any later 1090087Sobrienversion. 1118334Speter 1290087SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1390087SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1490087SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1590087Sobrienfor more details. 1618334Speter 1718334SpeterYou should have received a copy of the GNU General Public License 1890087Sobrienalong with GCC; see the file COPYING. If not, write to the Free 1990087SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 2090087Sobrien02111-1307, USA. */ 2118334Speter 2218334Speter/* This is the final pass of the compiler. 2318334Speter It looks at the rtl code for a function and outputs assembler code. 2418334Speter 2518334Speter Call `final_start_function' to output the assembler code for function entry, 2618334Speter `final' to output assembler code for some RTL code, 2718334Speter `final_end_function' to output assembler code for function exit. 2818334Speter If a function is compiled in several pieces, each piece is 2918334Speter output separately with `final'. 3018334Speter 3118334Speter Some optimizations are also done at this level. 3218334Speter Move instructions that were made unnecessary by good register allocation 3318334Speter are detected and omitted from the output. (Though most of these 3418334Speter are removed by the last jump pass.) 3518334Speter 3618334Speter Instructions to set the condition codes are omitted when it can be 3718334Speter seen that the condition codes already had the desired values. 3818334Speter 3918334Speter In some cases it is sufficient if the inherited condition codes 4018334Speter have related values, but this may require the following insn 4118334Speter (the one that tests the condition codes) to be modified. 4218334Speter 4318334Speter The code for the function prologue and epilogue are generated 4490087Sobrien directly in assembler by the target functions function_prologue and 4590087Sobrien function_epilogue. Those instructions never exist as rtl. */ 4618334Speter 4718334Speter#include "config.h" 4850503Sobrien#include "system.h" 4918334Speter 5018334Speter#include "tree.h" 5118334Speter#include "rtl.h" 5290087Sobrien#include "tm_p.h" 5318334Speter#include "regs.h" 5418334Speter#include "insn-config.h" 5518334Speter#include "insn-attr.h" 5618334Speter#include "recog.h" 5718334Speter#include "conditions.h" 5818334Speter#include "flags.h" 5918334Speter#include "real.h" 6018334Speter#include "hard-reg-set.h" 6118334Speter#include "output.h" 6250503Sobrien#include "except.h" 6390087Sobrien#include "function.h" 6450503Sobrien#include "toplev.h" 6550503Sobrien#include "reload.h" 6652515Sobrien#include "intl.h" 6790087Sobrien#include "basic-block.h" 6890087Sobrien#include "target.h" 6990087Sobrien#include "debug.h" 7090087Sobrien#include "expr.h" 71117404Skan#include "profile.h" 72117404Skan#include "cfglayout.h" 7318334Speter 7418334Speter#ifdef XCOFF_DEBUGGING_INFO 7590087Sobrien#include "xcoffout.h" /* Needed for external data 7690087Sobrien declarations for e.g. AIX 4.x. */ 7718334Speter#endif 7818334Speter 7950503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO) 8050503Sobrien#include "dwarf2out.h" 8150503Sobrien#endif 8250503Sobrien 8318334Speter/* If we aren't using cc0, CC_STATUS_INIT shouldn't exist. So define a 8418334Speter null default for it to save conditionalization later. */ 8518334Speter#ifndef CC_STATUS_INIT 8618334Speter#define CC_STATUS_INIT 8718334Speter#endif 8818334Speter 8918334Speter/* How to start an assembler comment. */ 9018334Speter#ifndef ASM_COMMENT_START 9118334Speter#define ASM_COMMENT_START ";#" 9218334Speter#endif 9318334Speter 9418334Speter/* Is the given character a logical line separator for the assembler? */ 9518334Speter#ifndef IS_ASM_LOGICAL_LINE_SEPARATOR 9618334Speter#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';') 9718334Speter#endif 9818334Speter 9950503Sobrien#ifndef JUMP_TABLES_IN_TEXT_SECTION 10050503Sobrien#define JUMP_TABLES_IN_TEXT_SECTION 0 10150503Sobrien#endif 10250503Sobrien 103117404Skan#if defined(READONLY_DATA_SECTION) || defined(READONLY_DATA_SECTION_ASM_OP) 104117404Skan#define HAVE_READONLY_DATA_SECTION 1 105117404Skan#else 106117404Skan#define HAVE_READONLY_DATA_SECTION 0 107117404Skan#endif 108117404Skan 10918334Speter/* Last insn processed by final_scan_insn. */ 11090087Sobrienstatic rtx debug_insn; 11190087Sobrienrtx current_output_insn; 11218334Speter 11318334Speter/* Line number of last NOTE. */ 11418334Speterstatic int last_linenum; 11518334Speter 11618334Speter/* Highest line number in current block. */ 11718334Speterstatic int high_block_linenum; 11818334Speter 11918334Speter/* Likewise for function. */ 12018334Speterstatic int high_function_linenum; 12118334Speter 12218334Speter/* Filename of last NOTE. */ 12390087Sobrienstatic const char *last_filename; 12418334Speter 12550503Sobrienextern int length_unit_log; /* This is defined in insn-attrtab.c. */ 12650503Sobrien 12718334Speter/* Nonzero while outputting an `asm' with operands. 12818334Speter This means that inconsistencies are the user's fault, so don't abort. 12918334Speter The precise value is the insn being output, to pass to error_for_asm. */ 130117404Skanrtx this_is_asm_operands; 13118334Speter 13218334Speter/* Number of operands of this insn, for an `asm' with operands. */ 13350503Sobrienstatic unsigned int insn_noperands; 13418334Speter 13518334Speter/* Compare optimization flag. */ 13618334Speter 13718334Speterstatic rtx last_ignored_compare = 0; 13818334Speter 13918334Speter/* Flag indicating this insn is the start of a new basic block. */ 14018334Speter 14118334Speterstatic int new_block = 1; 14218334Speter 14318334Speter/* Assign a unique number to each insn that is output. 14418334Speter This can be used to generate unique local labels. */ 14518334Speter 14618334Speterstatic int insn_counter = 0; 14718334Speter 14818334Speter#ifdef HAVE_cc0 14918334Speter/* This variable contains machine-dependent flags (defined in tm.h) 15018334Speter set and examined by output routines 15118334Speter that describe how to interpret the condition codes properly. */ 15218334Speter 15318334SpeterCC_STATUS cc_status; 15418334Speter 15518334Speter/* During output of an insn, this contains a copy of cc_status 15618334Speter from before the insn. */ 15718334Speter 15818334SpeterCC_STATUS cc_prev_status; 15918334Speter#endif 16018334Speter 16118334Speter/* Indexed by hardware reg number, is 1 if that register is ever 16218334Speter used in the current function. 16318334Speter 16418334Speter In life_analysis, or in stupid_life_analysis, this is set 16518334Speter up to record the hard regs used explicitly. Reload adds 16618334Speter in the hard regs used for holding pseudo regs. Final uses 16718334Speter it to generate the code in the function prologue and epilogue 16818334Speter to save and restore registers as needed. */ 16918334Speter 17018334Speterchar regs_ever_live[FIRST_PSEUDO_REGISTER]; 17118334Speter 17218334Speter/* Nonzero means current function must be given a frame pointer. 17318334Speter Set in stmt.c if anything is allocated on the stack there. 17418334Speter Set in reload1.c if anything is allocated on the stack there. */ 17518334Speter 17618334Speterint frame_pointer_needed; 17718334Speter 17890087Sobrien/* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen. */ 17918334Speter 18018334Speterstatic int block_depth; 18118334Speter 18218334Speter/* Nonzero if have enabled APP processing of our assembler output. */ 18318334Speter 18418334Speterstatic int app_on; 18518334Speter 18618334Speter/* If we are outputting an insn sequence, this contains the sequence rtx. 18718334Speter Zero otherwise. */ 18818334Speter 18918334Speterrtx final_sequence; 19018334Speter 19118334Speter#ifdef ASSEMBLER_DIALECT 19218334Speter 19318334Speter/* Number of the assembler dialect to use, starting at 0. */ 19418334Speterstatic int dialect_number; 19518334Speter#endif 19618334Speter 19718334Speter/* Indexed by line number, nonzero if there is a note for that line. */ 19818334Speter 19918334Speterstatic char *line_note_exists; 20018334Speter 20190087Sobrien#ifdef HAVE_conditional_execution 20290087Sobrien/* Nonnull if the insn currently being emitted was a COND_EXEC pattern. */ 20390087Sobrienrtx current_insn_predicate; 20490087Sobrien#endif 20518334Speter 206117404Skanstruct function_list 207117404Skan{ 208117404Skan struct function_list *next; /* next function */ 209117404Skan const char *name; /* function name */ 210117404Skan long cfg_checksum; /* function checksum */ 211117404Skan long count_edges; /* number of intrumented edges in this function */ 212117404Skan}; 213117404Skan 214117404Skanstatic struct function_list *functions_head = 0; 215117404Skanstatic struct function_list **functions_tail = &functions_head; 216117404Skan 21750503Sobrien#ifdef HAVE_ATTR_length 21890087Sobrienstatic int asm_insn_count PARAMS ((rtx)); 21950503Sobrien#endif 22090087Sobrienstatic void profile_function PARAMS ((FILE *)); 22190087Sobrienstatic void profile_after_prologue PARAMS ((FILE *)); 22290087Sobrienstatic void notice_source_line PARAMS ((rtx)); 22390087Sobrienstatic rtx walk_alter_subreg PARAMS ((rtx *)); 22490087Sobrienstatic void output_asm_name PARAMS ((void)); 225117404Skanstatic void output_alternate_entry_point PARAMS ((FILE *, rtx)); 22690087Sobrienstatic tree get_mem_expr_from_op PARAMS ((rtx, int *)); 22790087Sobrienstatic void output_asm_operand_names PARAMS ((rtx *, int *, int)); 22890087Sobrienstatic void output_operand PARAMS ((rtx, int)); 22950503Sobrien#ifdef LEAF_REGISTERS 23090087Sobrienstatic void leaf_renumber_regs PARAMS ((rtx)); 23150503Sobrien#endif 23250503Sobrien#ifdef HAVE_cc0 23390087Sobrienstatic int alter_cond PARAMS ((rtx)); 23450503Sobrien#endif 23590087Sobrien#ifndef ADDR_VEC_ALIGN 23690087Sobrienstatic int final_addr_vec_align PARAMS ((rtx)); 23790087Sobrien#endif 23890087Sobrien#ifdef HAVE_ATTR_length 23990087Sobrienstatic int align_fuzz PARAMS ((rtx, rtx, int, unsigned)); 24090087Sobrien#endif 24118334Speter 24218334Speter/* Initialize data in final at the beginning of a compilation. */ 24318334Speter 24418334Spetervoid 24518334Speterinit_final (filename) 24690087Sobrien const char *filename ATTRIBUTE_UNUSED; 24718334Speter{ 24818334Speter app_on = 0; 24918334Speter final_sequence = 0; 25018334Speter 25118334Speter#ifdef ASSEMBLER_DIALECT 25218334Speter dialect_number = ASSEMBLER_DIALECT; 25318334Speter#endif 25418334Speter} 25518334Speter 25618334Speter/* Called at end of source file, 257117404Skan to output the arc-profiling table for this entire compilation. */ 25818334Speter 25918334Spetervoid 26018334Speterend_final (filename) 26190087Sobrien const char *filename; 26218334Speter{ 263117404Skan if (profile_arc_flag && profile_info.count_instrumented_edges) 26418334Speter { 26518334Speter char name[20]; 266117404Skan tree string_type, string_cst; 267117404Skan tree structure_decl, structure_value, structure_pointer_type; 268117404Skan tree field_decl, decl_chain, value_chain; 269117404Skan tree sizeof_field_value, domain_type; 27018334Speter 271117404Skan /* Build types. */ 272117404Skan string_type = build_pointer_type (char_type_node); 27350503Sobrien 274117404Skan /* Libgcc2 bb structure. */ 275117404Skan structure_decl = make_node (RECORD_TYPE); 276117404Skan structure_pointer_type = build_pointer_type (structure_decl); 27718334Speter 278117404Skan /* Output the main header, of 7 words: 279117404Skan 0: 1 if this file is initialized, else 0. 280117404Skan 1: address of file name (LPBX1). 281117404Skan 2: address of table of counts (LPBX2). 282117404Skan 3: number of counts in the table. 283117404Skan 4: always 0, libgcc2 uses this as a pointer to next ``struct bb'' 28490087Sobrien 285117404Skan The following are GNU extensions: 28618334Speter 287117404Skan 5: Number of bytes in this header. 288117404Skan 6: address of table of function checksums (LPBX7). */ 28918334Speter 290117404Skan /* The zero word. */ 291117404Skan decl_chain = 292117404Skan build_decl (FIELD_DECL, get_identifier ("zero_word"), 293117404Skan long_integer_type_node); 294117404Skan value_chain = build_tree_list (decl_chain, 295117404Skan convert (long_integer_type_node, 296117404Skan integer_zero_node)); 29718334Speter 298117404Skan /* Address of filename. */ 299117404Skan { 300117404Skan char *cwd, *da_filename; 301117404Skan int da_filename_len; 30218334Speter 303117404Skan field_decl = 304117404Skan build_decl (FIELD_DECL, get_identifier ("filename"), string_type); 305117404Skan TREE_CHAIN (field_decl) = decl_chain; 306117404Skan decl_chain = field_decl; 30718334Speter 308117404Skan cwd = getpwd (); 309117404Skan da_filename_len = strlen (filename) + strlen (cwd) + 4 + 1; 310117404Skan da_filename = (char *) alloca (da_filename_len); 311117404Skan strcpy (da_filename, cwd); 312117404Skan strcat (da_filename, "/"); 313117404Skan strcat (da_filename, filename); 314117404Skan strcat (da_filename, ".da"); 315117404Skan da_filename_len = strlen (da_filename); 316117404Skan string_cst = build_string (da_filename_len + 1, da_filename); 317117404Skan domain_type = build_index_type (build_int_2 (da_filename_len, 0)); 318117404Skan TREE_TYPE (string_cst) 319117404Skan = build_array_type (char_type_node, domain_type); 320117404Skan value_chain = tree_cons (field_decl, 321117404Skan build1 (ADDR_EXPR, string_type, string_cst), 322117404Skan value_chain); 323117404Skan } 32418334Speter 325117404Skan /* Table of counts. */ 326117404Skan { 327117404Skan tree gcov_type_type = make_unsigned_type (GCOV_TYPE_SIZE); 328117404Skan tree gcov_type_pointer_type = build_pointer_type (gcov_type_type); 329117404Skan tree domain_tree 330117404Skan = build_index_type (build_int_2 (profile_info. 331117404Skan count_instrumented_edges - 1, 0)); 332117404Skan tree gcov_type_array_type 333117404Skan = build_array_type (gcov_type_type, domain_tree); 334117404Skan tree gcov_type_array_pointer_type 335117404Skan = build_pointer_type (gcov_type_array_type); 336117404Skan tree counts_table; 33790087Sobrien 338117404Skan field_decl = 339117404Skan build_decl (FIELD_DECL, get_identifier ("counts"), 340117404Skan gcov_type_pointer_type); 341117404Skan TREE_CHAIN (field_decl) = decl_chain; 342117404Skan decl_chain = field_decl; 34318334Speter 344117404Skan /* No values. */ 345117404Skan counts_table 346117404Skan = build (VAR_DECL, gcov_type_array_type, NULL_TREE, NULL_TREE); 347117404Skan TREE_STATIC (counts_table) = 1; 348117404Skan ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2); 349117404Skan DECL_NAME (counts_table) = get_identifier (name); 350117404Skan assemble_variable (counts_table, 0, 0, 0); 35118334Speter 352117404Skan value_chain = tree_cons (field_decl, 353117404Skan build1 (ADDR_EXPR, 354117404Skan gcov_type_array_pointer_type, 355117404Skan counts_table), value_chain); 356117404Skan } 357117404Skan 35890087Sobrien /* Count of the # of instrumented arcs. */ 359117404Skan field_decl 360117404Skan = build_decl (FIELD_DECL, get_identifier ("ncounts"), 361117404Skan long_integer_type_node); 362117404Skan TREE_CHAIN (field_decl) = decl_chain; 363117404Skan decl_chain = field_decl; 36418334Speter 365117404Skan value_chain = tree_cons (field_decl, 366117404Skan convert (long_integer_type_node, 367117404Skan build_int_2 (profile_info. 368117404Skan count_instrumented_edges, 369117404Skan 0)), value_chain); 370117404Skan /* Pointer to the next bb. */ 371117404Skan field_decl 372117404Skan = build_decl (FIELD_DECL, get_identifier ("next"), 373117404Skan structure_pointer_type); 374117404Skan TREE_CHAIN (field_decl) = decl_chain; 375117404Skan decl_chain = field_decl; 37618334Speter 377117404Skan value_chain = tree_cons (field_decl, null_pointer_node, value_chain); 37818334Speter 379117404Skan /* sizeof(struct bb). We'll set this after entire structure 380117404Skan is laid out. */ 381117404Skan field_decl 382117404Skan = build_decl (FIELD_DECL, get_identifier ("sizeof_bb"), 383117404Skan long_integer_type_node); 384117404Skan TREE_CHAIN (field_decl) = decl_chain; 385117404Skan decl_chain = field_decl; 38618334Speter 387117404Skan sizeof_field_value = tree_cons (field_decl, NULL, value_chain); 388117404Skan value_chain = sizeof_field_value; 38918334Speter 390117404Skan /* struct bb_function []. */ 391117404Skan { 392117404Skan struct function_list *item; 393117404Skan int num_nodes; 394117404Skan tree checksum_field, arc_count_field, name_field; 395117404Skan tree domain; 396117404Skan tree array_value_chain = NULL_TREE; 397117404Skan tree bb_fn_struct_type; 398117404Skan tree bb_fn_struct_array_type; 399117404Skan tree bb_fn_struct_array_pointer_type; 400117404Skan tree bb_fn_struct_pointer_type; 401117404Skan tree field_value, field_value_chain; 40218334Speter 403117404Skan bb_fn_struct_type = make_node (RECORD_TYPE); 40450503Sobrien 405117404Skan checksum_field = build_decl (FIELD_DECL, get_identifier ("checksum"), 406117404Skan long_integer_type_node); 40718334Speter 408117404Skan arc_count_field 409117404Skan = build_decl (FIELD_DECL, get_identifier ("arc_count"), 410117404Skan integer_type_node); 411117404Skan TREE_CHAIN (checksum_field) = arc_count_field; 412117404Skan 413117404Skan name_field 414117404Skan = build_decl (FIELD_DECL, get_identifier ("name"), string_type); 415117404Skan TREE_CHAIN (arc_count_field) = name_field; 416117404Skan 417117404Skan TYPE_FIELDS (bb_fn_struct_type) = checksum_field; 418117404Skan 419117404Skan num_nodes = 0; 420117404Skan 421117404Skan for (item = functions_head; item != 0; item = item->next) 422117404Skan num_nodes++; 423117404Skan 424117404Skan /* Note that the array contains a terminator, hence no - 1. */ 425117404Skan domain = build_index_type (build_int_2 (num_nodes, 0)); 426117404Skan 427117404Skan bb_fn_struct_pointer_type = build_pointer_type (bb_fn_struct_type); 428117404Skan bb_fn_struct_array_type 429117404Skan = build_array_type (bb_fn_struct_type, domain); 430117404Skan bb_fn_struct_array_pointer_type 431117404Skan = build_pointer_type (bb_fn_struct_array_type); 432117404Skan 433117404Skan layout_type (bb_fn_struct_type); 434117404Skan layout_type (bb_fn_struct_pointer_type); 435117404Skan layout_type (bb_fn_struct_array_type); 436117404Skan layout_type (bb_fn_struct_array_pointer_type); 437117404Skan 438117404Skan for (item = functions_head; item != 0; item = item->next) 439117404Skan { 440117404Skan size_t name_len; 441117404Skan 442117404Skan /* create constructor for structure. */ 443117404Skan field_value_chain 444117404Skan = build_tree_list (checksum_field, 445117404Skan convert (long_integer_type_node, 446117404Skan build_int_2 (item->cfg_checksum, 0))); 447117404Skan field_value_chain 448117404Skan = tree_cons (arc_count_field, 449117404Skan convert (integer_type_node, 450117404Skan build_int_2 (item->count_edges, 0)), 451117404Skan field_value_chain); 452117404Skan 453117404Skan name_len = strlen (item->name); 454117404Skan string_cst = build_string (name_len + 1, item->name); 455117404Skan domain_type = build_index_type (build_int_2 (name_len, 0)); 456117404Skan TREE_TYPE (string_cst) 457117404Skan = build_array_type (char_type_node, domain_type); 458117404Skan field_value_chain = tree_cons (name_field, 459117404Skan build1 (ADDR_EXPR, string_type, 460117404Skan string_cst), 461117404Skan field_value_chain); 462117404Skan 463117404Skan /* Add to chain. */ 464117404Skan array_value_chain 465117404Skan = tree_cons (NULL_TREE, build (CONSTRUCTOR, 466117404Skan bb_fn_struct_type, NULL_TREE, 467117404Skan nreverse (field_value_chain)), 468117404Skan array_value_chain); 469117404Skan } 470117404Skan 471117404Skan /* Add terminator. */ 472117404Skan field_value = build_tree_list (arc_count_field, 473117404Skan convert (integer_type_node, 474117404Skan build_int_2 (-1, 0))); 475117404Skan 476117404Skan array_value_chain = tree_cons (NULL_TREE, 477117404Skan build (CONSTRUCTOR, bb_fn_struct_type, 478117404Skan NULL_TREE, field_value), 479117404Skan array_value_chain); 480117404Skan 481117404Skan 482117404Skan /* Create constructor for array. */ 483117404Skan field_decl 484117404Skan = build_decl (FIELD_DECL, get_identifier ("function_infos"), 485117404Skan bb_fn_struct_pointer_type); 486117404Skan value_chain = tree_cons (field_decl, 487117404Skan build1 (ADDR_EXPR, 488117404Skan bb_fn_struct_array_pointer_type, 489117404Skan build (CONSTRUCTOR, 490117404Skan bb_fn_struct_array_type, 491117404Skan NULL_TREE, 492117404Skan nreverse 493117404Skan (array_value_chain))), 494117404Skan value_chain); 495117404Skan TREE_CHAIN (field_decl) = decl_chain; 496117404Skan decl_chain = field_decl; 49718334Speter } 49818334Speter 499117404Skan /* Finish structure. */ 500117404Skan TYPE_FIELDS (structure_decl) = nreverse (decl_chain); 501117404Skan layout_type (structure_decl); 502117404Skan 503117404Skan structure_value 504117404Skan = build (VAR_DECL, structure_decl, NULL_TREE, NULL_TREE); 505117404Skan DECL_INITIAL (structure_value) 506117404Skan = build (CONSTRUCTOR, structure_decl, NULL_TREE, 507117404Skan nreverse (value_chain)); 508117404Skan TREE_STATIC (structure_value) = 1; 509117404Skan ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0); 510117404Skan DECL_NAME (structure_value) = get_identifier (name); 511117404Skan 512117404Skan /* Size of this structure. */ 513117404Skan TREE_VALUE (sizeof_field_value) 514117404Skan = convert (long_integer_type_node, 515117404Skan build_int_2 (int_size_in_bytes (structure_decl), 0)); 516117404Skan 517117404Skan /* Build structure. */ 518117404Skan assemble_variable (structure_value, 0, 0, 0); 51990087Sobrien } 52090087Sobrien} 52118334Speter 52290087Sobrien/* Default target function prologue and epilogue assembler output. 52318334Speter 52490087Sobrien If not overridden for epilogue code, then the function body itself 52590087Sobrien contains return instructions wherever needed. */ 52690087Sobrienvoid 52790087Sobriendefault_function_pro_epilogue (file, size) 52890087Sobrien FILE *file ATTRIBUTE_UNUSED; 52990087Sobrien HOST_WIDE_INT size ATTRIBUTE_UNUSED; 53090087Sobrien{ 53190087Sobrien} 53218334Speter 53390087Sobrien/* Default target hook that outputs nothing to a stream. */ 53490087Sobrienvoid 53590087Sobrienno_asm_to_stream (file) 53690087Sobrien FILE *file ATTRIBUTE_UNUSED; 53790087Sobrien{ 53818334Speter} 53918334Speter 54018334Speter/* Enable APP processing of subsequent output. 54118334Speter Used before the output from an `asm' statement. */ 54218334Speter 54318334Spetervoid 54418334Speterapp_enable () 54518334Speter{ 54618334Speter if (! app_on) 54718334Speter { 54850503Sobrien fputs (ASM_APP_ON, asm_out_file); 54918334Speter app_on = 1; 55018334Speter } 55118334Speter} 55218334Speter 55318334Speter/* Disable APP processing of subsequent output. 55418334Speter Called from varasm.c before most kinds of output. */ 55518334Speter 55618334Spetervoid 55718334Speterapp_disable () 55818334Speter{ 55918334Speter if (app_on) 56018334Speter { 56150503Sobrien fputs (ASM_APP_OFF, asm_out_file); 56218334Speter app_on = 0; 56318334Speter } 56418334Speter} 56518334Speter 56690087Sobrien/* Return the number of slots filled in the current 56718334Speter delayed branch sequence (we don't count the insn needing the 56818334Speter delay slot). Zero if not in a delayed branch sequence. */ 56918334Speter 57018334Speter#ifdef DELAY_SLOTS 57118334Speterint 57218334Speterdbr_sequence_length () 57318334Speter{ 57418334Speter if (final_sequence != 0) 57518334Speter return XVECLEN (final_sequence, 0) - 1; 57618334Speter else 57718334Speter return 0; 57818334Speter} 57918334Speter#endif 58018334Speter 58118334Speter/* The next two pages contain routines used to compute the length of an insn 58218334Speter and to shorten branches. */ 58318334Speter 58418334Speter/* Arrays for insn lengths, and addresses. The latter is referenced by 58518334Speter `insn_current_length'. */ 58618334Speter 58790087Sobrienstatic int *insn_lengths; 58818334Speter 58990087Sobrienvarray_type insn_addresses_; 59090087Sobrien 59152515Sobrien/* Max uid for which the above arrays are valid. */ 59252515Sobrienstatic int insn_lengths_max_uid; 59352515Sobrien 59418334Speter/* Address of insn being processed. Used by `insn_current_length'. */ 59518334Speterint insn_current_address; 59618334Speter 59750503Sobrien/* Address of insn being processed in previous iteration. */ 59850503Sobrienint insn_last_address; 59950503Sobrien 60090087Sobrien/* known invariant alignment of insn being processed. */ 60150503Sobrienint insn_current_align; 60250503Sobrien 60350503Sobrien/* After shorten_branches, for any insn, uid_align[INSN_UID (insn)] 60450503Sobrien gives the next following alignment insn that increases the known 60550503Sobrien alignment, or NULL_RTX if there is no such insn. 60650503Sobrien For any alignment obtained this way, we can again index uid_align with 60750503Sobrien its uid to obtain the next following align that in turn increases the 60850503Sobrien alignment, till we reach NULL_RTX; the sequence obtained this way 60950503Sobrien for each insn we'll call the alignment chain of this insn in the following 61050503Sobrien comments. */ 61150503Sobrien 61290087Sobrienstruct label_alignment 61390087Sobrien{ 61450503Sobrien short alignment; 61550503Sobrien short max_skip; 61650503Sobrien}; 61750503Sobrien 61850503Sobrienstatic rtx *uid_align; 61950503Sobrienstatic int *uid_shuid; 62050503Sobrienstatic struct label_alignment *label_align; 62150503Sobrien 62218334Speter/* Indicate that branch shortening hasn't yet been done. */ 62318334Speter 62418334Spetervoid 62518334Speterinit_insn_lengths () 62618334Speter{ 62750503Sobrien if (uid_shuid) 62850503Sobrien { 62950503Sobrien free (uid_shuid); 63050503Sobrien uid_shuid = 0; 63150503Sobrien } 63250503Sobrien if (insn_lengths) 63350503Sobrien { 63450503Sobrien free (insn_lengths); 63550503Sobrien insn_lengths = 0; 63652515Sobrien insn_lengths_max_uid = 0; 63750503Sobrien } 63890087Sobrien#ifdef HAVE_ATTR_length 63990087Sobrien INSN_ADDRESSES_FREE (); 64090087Sobrien#endif 64150503Sobrien if (uid_align) 64250503Sobrien { 64350503Sobrien free (uid_align); 64450503Sobrien uid_align = 0; 64550503Sobrien } 64618334Speter} 64718334Speter 64818334Speter/* Obtain the current length of an insn. If branch shortening has been done, 64918334Speter get its actual length. Otherwise, get its maximum length. */ 65018334Speter 65118334Speterint 65218334Speterget_attr_length (insn) 65390087Sobrien rtx insn ATTRIBUTE_UNUSED; 65418334Speter{ 65518334Speter#ifdef HAVE_ATTR_length 65618334Speter rtx body; 65718334Speter int i; 65818334Speter int length = 0; 65918334Speter 66052515Sobrien if (insn_lengths_max_uid > INSN_UID (insn)) 66118334Speter return insn_lengths[INSN_UID (insn)]; 66218334Speter else 66318334Speter switch (GET_CODE (insn)) 66418334Speter { 66518334Speter case NOTE: 66618334Speter case BARRIER: 66718334Speter case CODE_LABEL: 66818334Speter return 0; 66918334Speter 67018334Speter case CALL_INSN: 67118334Speter length = insn_default_length (insn); 67218334Speter break; 67318334Speter 67418334Speter case JUMP_INSN: 67518334Speter body = PATTERN (insn); 676117404Skan if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) 67718334Speter { 67850503Sobrien /* Alignment is machine-dependent and should be handled by 67950503Sobrien ADDR_VEC_ALIGN. */ 68018334Speter } 68118334Speter else 68218334Speter length = insn_default_length (insn); 68318334Speter break; 68418334Speter 68518334Speter case INSN: 68618334Speter body = PATTERN (insn); 68718334Speter if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER) 68818334Speter return 0; 68918334Speter 69018334Speter else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0) 69118334Speter length = asm_insn_count (body) * insn_default_length (insn); 69218334Speter else if (GET_CODE (body) == SEQUENCE) 69318334Speter for (i = 0; i < XVECLEN (body, 0); i++) 69418334Speter length += get_attr_length (XVECEXP (body, 0, i)); 69518334Speter else 69618334Speter length = insn_default_length (insn); 69750503Sobrien break; 69850503Sobrien 69950503Sobrien default: 70050503Sobrien break; 70118334Speter } 70218334Speter 70318334Speter#ifdef ADJUST_INSN_LENGTH 70418334Speter ADJUST_INSN_LENGTH (insn, length); 70518334Speter#endif 70618334Speter return length; 70718334Speter#else /* not HAVE_ATTR_length */ 70818334Speter return 0; 70918334Speter#endif /* not HAVE_ATTR_length */ 71018334Speter} 71118334Speter 71250503Sobrien/* Code to handle alignment inside shorten_branches. */ 71350503Sobrien 71450503Sobrien/* Here is an explanation how the algorithm in align_fuzz can give 71550503Sobrien proper results: 71650503Sobrien 71750503Sobrien Call a sequence of instructions beginning with alignment point X 71850503Sobrien and continuing until the next alignment point `block X'. When `X' 71990087Sobrien is used in an expression, it means the alignment value of the 72050503Sobrien alignment point. 72190087Sobrien 72250503Sobrien Call the distance between the start of the first insn of block X, and 72350503Sobrien the end of the last insn of block X `IX', for the `inner size of X'. 72450503Sobrien This is clearly the sum of the instruction lengths. 72590087Sobrien 72650503Sobrien Likewise with the next alignment-delimited block following X, which we 72750503Sobrien shall call block Y. 72890087Sobrien 72950503Sobrien Call the distance between the start of the first insn of block X, and 73050503Sobrien the start of the first insn of block Y `OX', for the `outer size of X'. 73190087Sobrien 73250503Sobrien The estimated padding is then OX - IX. 73390087Sobrien 73450503Sobrien OX can be safely estimated as 73590087Sobrien 73650503Sobrien if (X >= Y) 73750503Sobrien OX = round_up(IX, Y) 73850503Sobrien else 73950503Sobrien OX = round_up(IX, X) + Y - X 74090087Sobrien 74150503Sobrien Clearly est(IX) >= real(IX), because that only depends on the 74250503Sobrien instruction lengths, and those being overestimated is a given. 74390087Sobrien 74450503Sobrien Clearly round_up(foo, Z) >= round_up(bar, Z) if foo >= bar, so 74550503Sobrien we needn't worry about that when thinking about OX. 74690087Sobrien 74750503Sobrien When X >= Y, the alignment provided by Y adds no uncertainty factor 74850503Sobrien for branch ranges starting before X, so we can just round what we have. 74950503Sobrien But when X < Y, we don't know anything about the, so to speak, 75050503Sobrien `middle bits', so we have to assume the worst when aligning up from an 75150503Sobrien address mod X to one mod Y, which is Y - X. */ 75250503Sobrien 75350503Sobrien#ifndef LABEL_ALIGN 75490087Sobrien#define LABEL_ALIGN(LABEL) align_labels_log 75550503Sobrien#endif 75650503Sobrien 75750503Sobrien#ifndef LABEL_ALIGN_MAX_SKIP 75890087Sobrien#define LABEL_ALIGN_MAX_SKIP align_labels_max_skip 75950503Sobrien#endif 76050503Sobrien 76150503Sobrien#ifndef LOOP_ALIGN 76290087Sobrien#define LOOP_ALIGN(LABEL) align_loops_log 76350503Sobrien#endif 76450503Sobrien 76550503Sobrien#ifndef LOOP_ALIGN_MAX_SKIP 76690087Sobrien#define LOOP_ALIGN_MAX_SKIP align_loops_max_skip 76750503Sobrien#endif 76850503Sobrien 76950503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER 77050503Sobrien#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0 77150503Sobrien#endif 77250503Sobrien 77350503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 77450503Sobrien#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0 77550503Sobrien#endif 77650503Sobrien 77790087Sobrien#ifndef JUMP_ALIGN 77890087Sobrien#define JUMP_ALIGN(LABEL) align_jumps_log 77990087Sobrien#endif 78090087Sobrien 78190087Sobrien#ifndef JUMP_ALIGN_MAX_SKIP 78290087Sobrien#define JUMP_ALIGN_MAX_SKIP align_jumps_max_skip 78390087Sobrien#endif 78490087Sobrien 78550503Sobrien#ifndef ADDR_VEC_ALIGN 78690087Sobrienstatic int 78750503Sobrienfinal_addr_vec_align (addr_vec) 78850503Sobrien rtx addr_vec; 78950503Sobrien{ 79090087Sobrien int align = GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec))); 79150503Sobrien 79250503Sobrien if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT) 79350503Sobrien align = BIGGEST_ALIGNMENT / BITS_PER_UNIT; 79490087Sobrien return exact_log2 (align); 79550503Sobrien 79650503Sobrien} 79790087Sobrien 79850503Sobrien#define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC) 79950503Sobrien#endif 80050503Sobrien 80150503Sobrien#ifndef INSN_LENGTH_ALIGNMENT 80250503Sobrien#define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log 80350503Sobrien#endif 80450503Sobrien 80550503Sobrien#define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)]) 80650503Sobrien 80750503Sobrienstatic int min_labelno, max_labelno; 80850503Sobrien 80950503Sobrien#define LABEL_TO_ALIGNMENT(LABEL) \ 81050503Sobrien (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].alignment) 81150503Sobrien 81250503Sobrien#define LABEL_TO_MAX_SKIP(LABEL) \ 81350503Sobrien (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].max_skip) 81450503Sobrien 81550503Sobrien/* For the benefit of port specific code do this also as a function. */ 81690087Sobrien 81750503Sobrienint 81850503Sobrienlabel_to_alignment (label) 81950503Sobrien rtx label; 82050503Sobrien{ 82150503Sobrien return LABEL_TO_ALIGNMENT (label); 82250503Sobrien} 82350503Sobrien 82450503Sobrien#ifdef HAVE_ATTR_length 82550503Sobrien/* The differences in addresses 82650503Sobrien between a branch and its target might grow or shrink depending on 82750503Sobrien the alignment the start insn of the range (the branch for a forward 82850503Sobrien branch or the label for a backward branch) starts out on; if these 82950503Sobrien differences are used naively, they can even oscillate infinitely. 83050503Sobrien We therefore want to compute a 'worst case' address difference that 83150503Sobrien is independent of the alignment the start insn of the range end 83250503Sobrien up on, and that is at least as large as the actual difference. 83350503Sobrien The function align_fuzz calculates the amount we have to add to the 83450503Sobrien naively computed difference, by traversing the part of the alignment 83550503Sobrien chain of the start insn of the range that is in front of the end insn 83650503Sobrien of the range, and considering for each alignment the maximum amount 83750503Sobrien that it might contribute to a size increase. 83850503Sobrien 83950503Sobrien For casesi tables, we also want to know worst case minimum amounts of 84050503Sobrien address difference, in case a machine description wants to introduce 84150503Sobrien some common offset that is added to all offsets in a table. 84290087Sobrien For this purpose, align_fuzz with a growth argument of 0 computes the 84350503Sobrien appropriate adjustment. */ 84450503Sobrien 84550503Sobrien/* Compute the maximum delta by which the difference of the addresses of 84650503Sobrien START and END might grow / shrink due to a different address for start 84750503Sobrien which changes the size of alignment insns between START and END. 84850503Sobrien KNOWN_ALIGN_LOG is the alignment known for START. 84950503Sobrien GROWTH should be ~0 if the objective is to compute potential code size 85050503Sobrien increase, and 0 if the objective is to compute potential shrink. 85150503Sobrien The return value is undefined for any other value of GROWTH. */ 85290087Sobrien 85390087Sobrienstatic int 85450503Sobrienalign_fuzz (start, end, known_align_log, growth) 85550503Sobrien rtx start, end; 85650503Sobrien int known_align_log; 85750503Sobrien unsigned growth; 85850503Sobrien{ 85950503Sobrien int uid = INSN_UID (start); 86050503Sobrien rtx align_label; 86150503Sobrien int known_align = 1 << known_align_log; 86250503Sobrien int end_shuid = INSN_SHUID (end); 86350503Sobrien int fuzz = 0; 86450503Sobrien 86550503Sobrien for (align_label = uid_align[uid]; align_label; align_label = uid_align[uid]) 86650503Sobrien { 86750503Sobrien int align_addr, new_align; 86850503Sobrien 86950503Sobrien uid = INSN_UID (align_label); 87090087Sobrien align_addr = INSN_ADDRESSES (uid) - insn_lengths[uid]; 87150503Sobrien if (uid_shuid[uid] > end_shuid) 87250503Sobrien break; 87350503Sobrien known_align_log = LABEL_TO_ALIGNMENT (align_label); 87450503Sobrien new_align = 1 << known_align_log; 87550503Sobrien if (new_align < known_align) 87650503Sobrien continue; 87750503Sobrien fuzz += (-align_addr ^ growth) & (new_align - known_align); 87850503Sobrien known_align = new_align; 87950503Sobrien } 88050503Sobrien return fuzz; 88150503Sobrien} 88250503Sobrien 88350503Sobrien/* Compute a worst-case reference address of a branch so that it 88450503Sobrien can be safely used in the presence of aligned labels. Since the 88550503Sobrien size of the branch itself is unknown, the size of the branch is 88650503Sobrien not included in the range. I.e. for a forward branch, the reference 88750503Sobrien address is the end address of the branch as known from the previous 88850503Sobrien branch shortening pass, minus a value to account for possible size 88950503Sobrien increase due to alignment. For a backward branch, it is the start 89050503Sobrien address of the branch as known from the current pass, plus a value 89150503Sobrien to account for possible size increase due to alignment. 89250503Sobrien NB.: Therefore, the maximum offset allowed for backward branches needs 89350503Sobrien to exclude the branch size. */ 89490087Sobrien 89550503Sobrienint 89650503Sobrieninsn_current_reference_address (branch) 89750503Sobrien rtx branch; 89850503Sobrien{ 89990087Sobrien rtx dest, seq; 90090087Sobrien int seq_uid; 90190087Sobrien 90290087Sobrien if (! INSN_ADDRESSES_SET_P ()) 90390087Sobrien return 0; 90490087Sobrien 90590087Sobrien seq = NEXT_INSN (PREV_INSN (branch)); 90690087Sobrien seq_uid = INSN_UID (seq); 90750503Sobrien if (GET_CODE (branch) != JUMP_INSN) 90850503Sobrien /* This can happen for example on the PA; the objective is to know the 90950503Sobrien offset to address something in front of the start of the function. 91050503Sobrien Thus, we can treat it like a backward branch. 91150503Sobrien We assume here that FUNCTION_BOUNDARY / BITS_PER_UNIT is larger than 91250503Sobrien any alignment we'd encounter, so we skip the call to align_fuzz. */ 91350503Sobrien return insn_current_address; 91450503Sobrien dest = JUMP_LABEL (branch); 91590087Sobrien 91690087Sobrien /* BRANCH has no proper alignment chain set, so use SEQ. 91790087Sobrien BRANCH also has no INSN_SHUID. */ 91890087Sobrien if (INSN_SHUID (seq) < INSN_SHUID (dest)) 91950503Sobrien { 92090087Sobrien /* Forward branch. */ 92150503Sobrien return (insn_last_address + insn_lengths[seq_uid] 92250503Sobrien - align_fuzz (seq, dest, length_unit_log, ~0)); 92350503Sobrien } 92450503Sobrien else 92550503Sobrien { 92690087Sobrien /* Backward branch. */ 92750503Sobrien return (insn_current_address 92850503Sobrien + align_fuzz (dest, seq, length_unit_log, ~0)); 92950503Sobrien } 93050503Sobrien} 93150503Sobrien#endif /* HAVE_ATTR_length */ 93250503Sobrien 93390087Sobrienvoid 93490087Sobriencompute_alignments () 93590087Sobrien{ 93690087Sobrien int log, max_skip, max_log; 937117404Skan basic_block bb; 93890087Sobrien 93990087Sobrien if (label_align) 94090087Sobrien { 94190087Sobrien free (label_align); 94290087Sobrien label_align = 0; 94390087Sobrien } 94490087Sobrien 94590087Sobrien max_labelno = max_label_num (); 94690087Sobrien min_labelno = get_first_label_num (); 94790087Sobrien label_align = (struct label_alignment *) 94890087Sobrien xcalloc (max_labelno - min_labelno + 1, sizeof (struct label_alignment)); 94990087Sobrien 95090087Sobrien /* If not optimizing or optimizing for size, don't assign any alignments. */ 95190087Sobrien if (! optimize || optimize_size) 95290087Sobrien return; 95390087Sobrien 954117404Skan FOR_EACH_BB (bb) 95590087Sobrien { 95690087Sobrien rtx label = bb->head; 95790087Sobrien int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0; 95890087Sobrien edge e; 95990087Sobrien 96090087Sobrien if (GET_CODE (label) != CODE_LABEL) 96190087Sobrien continue; 96290087Sobrien max_log = LABEL_ALIGN (label); 96390087Sobrien max_skip = LABEL_ALIGN_MAX_SKIP; 96490087Sobrien 96590087Sobrien for (e = bb->pred; e; e = e->pred_next) 96690087Sobrien { 96790087Sobrien if (e->flags & EDGE_FALLTHRU) 96890087Sobrien has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e); 96990087Sobrien else 97090087Sobrien branch_frequency += EDGE_FREQUENCY (e); 97190087Sobrien } 97290087Sobrien 97390087Sobrien /* There are two purposes to align block with no fallthru incoming edge: 97490087Sobrien 1) to avoid fetch stalls when branch destination is near cache boundary 97590087Sobrien 2) to improve cache efficiency in case the previous block is not executed 97690087Sobrien (so it does not need to be in the cache). 97790087Sobrien 97890087Sobrien We to catch first case, we align frequently executed blocks. 97990087Sobrien To catch the second, we align blocks that are executed more frequently 98090087Sobrien than the predecessor and the predecessor is likely to not be executed 98190087Sobrien when function is called. */ 98290087Sobrien 98390087Sobrien if (!has_fallthru 98490087Sobrien && (branch_frequency > BB_FREQ_MAX / 10 985117404Skan || (bb->frequency > bb->prev_bb->frequency * 10 986117404Skan && (bb->prev_bb->frequency 98790087Sobrien <= ENTRY_BLOCK_PTR->frequency / 2)))) 98890087Sobrien { 98990087Sobrien log = JUMP_ALIGN (label); 99090087Sobrien if (max_log < log) 99190087Sobrien { 99290087Sobrien max_log = log; 99390087Sobrien max_skip = JUMP_ALIGN_MAX_SKIP; 99490087Sobrien } 99590087Sobrien } 99690087Sobrien /* In case block is frequent and reached mostly by non-fallthru edge, 997117404Skan align it. It is most likely a first block of loop. */ 99890087Sobrien if (has_fallthru 99990087Sobrien && branch_frequency + fallthru_frequency > BB_FREQ_MAX / 10 1000117404Skan && branch_frequency > fallthru_frequency * 2) 100190087Sobrien { 100290087Sobrien log = LOOP_ALIGN (label); 100390087Sobrien if (max_log < log) 100490087Sobrien { 100590087Sobrien max_log = log; 100690087Sobrien max_skip = LOOP_ALIGN_MAX_SKIP; 100790087Sobrien } 100890087Sobrien } 100990087Sobrien LABEL_TO_ALIGNMENT (label) = max_log; 101090087Sobrien LABEL_TO_MAX_SKIP (label) = max_skip; 101190087Sobrien } 101290087Sobrien} 101390087Sobrien 101418334Speter/* Make a pass over all insns and compute their actual lengths by shortening 101518334Speter any branches of variable length if possible. */ 101618334Speter 101718334Speter/* Give a default value for the lowest address in a function. */ 101818334Speter 101918334Speter#ifndef FIRST_INSN_ADDRESS 102018334Speter#define FIRST_INSN_ADDRESS 0 102118334Speter#endif 102218334Speter 102350503Sobrien/* shorten_branches might be called multiple times: for example, the SH 102450503Sobrien port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG. 102550503Sobrien In order to do this, it needs proper length information, which it obtains 102650503Sobrien by calling shorten_branches. This cannot be collapsed with 102790087Sobrien shorten_branches itself into a single pass unless we also want to integrate 102850503Sobrien reorg.c, since the branch splitting exposes new instructions with delay 102950503Sobrien slots. */ 103050503Sobrien 103118334Spetervoid 103218334Spetershorten_branches (first) 103390087Sobrien rtx first ATTRIBUTE_UNUSED; 103418334Speter{ 103550503Sobrien rtx insn; 103650503Sobrien int max_uid; 103750503Sobrien int i; 103850503Sobrien int max_log; 103950503Sobrien int max_skip; 104018334Speter#ifdef HAVE_ATTR_length 104150503Sobrien#define MAX_CODE_ALIGN 16 104250503Sobrien rtx seq; 104318334Speter int something_changed = 1; 104418334Speter char *varying_length; 104518334Speter rtx body; 104618334Speter int uid; 104750503Sobrien rtx align_tab[MAX_CODE_ALIGN]; 104818334Speter 104950503Sobrien#endif 105018334Speter 105150503Sobrien /* Compute maximum UID and allocate label_align / uid_shuid. */ 105250503Sobrien max_uid = get_max_uid (); 105350503Sobrien 105450503Sobrien uid_shuid = (int *) xmalloc (max_uid * sizeof *uid_shuid); 105550503Sobrien 105690087Sobrien if (max_labelno != max_label_num ()) 105790087Sobrien { 105890087Sobrien int old = max_labelno; 105990087Sobrien int n_labels; 106090087Sobrien int n_old_labels; 106190087Sobrien 106290087Sobrien max_labelno = max_label_num (); 106390087Sobrien 106490087Sobrien n_labels = max_labelno - min_labelno + 1; 106590087Sobrien n_old_labels = old - min_labelno + 1; 106690087Sobrien 106790087Sobrien label_align = (struct label_alignment *) xrealloc 106890087Sobrien (label_align, n_labels * sizeof (struct label_alignment)); 106990087Sobrien 107090087Sobrien /* Range of labels grows monotonically in the function. Abort here 107190087Sobrien means that the initialization of array got lost. */ 107290087Sobrien if (n_old_labels > n_labels) 107390087Sobrien abort (); 107490087Sobrien 107590087Sobrien memset (label_align + n_old_labels, 0, 107690087Sobrien (n_labels - n_old_labels) * sizeof (struct label_alignment)); 107790087Sobrien } 107890087Sobrien 107950503Sobrien /* Initialize label_align and set up uid_shuid to be strictly 108050503Sobrien monotonically rising with insn order. */ 108150503Sobrien /* We use max_log here to keep track of the maximum alignment we want to 108250503Sobrien impose on the next CODE_LABEL (or the current one if we are processing 108350503Sobrien the CODE_LABEL itself). */ 108490087Sobrien 108550503Sobrien max_log = 0; 108650503Sobrien max_skip = 0; 108750503Sobrien 108850503Sobrien for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn)) 108950503Sobrien { 109050503Sobrien int log; 109150503Sobrien 109250503Sobrien INSN_SHUID (insn) = i++; 109390087Sobrien if (INSN_P (insn)) 109450503Sobrien { 109550503Sobrien /* reorg might make the first insn of a loop being run once only, 109650503Sobrien and delete the label in front of it. Then we want to apply 109750503Sobrien the loop alignment to the new label created by reorg, which 109850503Sobrien is separated by the former loop start insn from the 109950503Sobrien NOTE_INSN_LOOP_BEG. */ 110050503Sobrien } 110150503Sobrien else if (GET_CODE (insn) == CODE_LABEL) 110250503Sobrien { 110350503Sobrien rtx next; 110450503Sobrien 110590087Sobrien /* Merge in alignments computed by compute_alignments. */ 110690087Sobrien log = LABEL_TO_ALIGNMENT (insn); 110790087Sobrien if (max_log < log) 110890087Sobrien { 110990087Sobrien max_log = log; 111090087Sobrien max_skip = LABEL_TO_MAX_SKIP (insn); 111190087Sobrien } 111290087Sobrien 111350503Sobrien log = LABEL_ALIGN (insn); 111450503Sobrien if (max_log < log) 111550503Sobrien { 111650503Sobrien max_log = log; 111750503Sobrien max_skip = LABEL_ALIGN_MAX_SKIP; 111850503Sobrien } 111950503Sobrien next = NEXT_INSN (insn); 112050503Sobrien /* ADDR_VECs only take room if read-only data goes into the text 112150503Sobrien section. */ 1122117404Skan if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION) 112350503Sobrien if (next && GET_CODE (next) == JUMP_INSN) 112450503Sobrien { 112550503Sobrien rtx nextbody = PATTERN (next); 112650503Sobrien if (GET_CODE (nextbody) == ADDR_VEC 112750503Sobrien || GET_CODE (nextbody) == ADDR_DIFF_VEC) 112850503Sobrien { 112950503Sobrien log = ADDR_VEC_ALIGN (next); 113050503Sobrien if (max_log < log) 113150503Sobrien { 113250503Sobrien max_log = log; 113350503Sobrien max_skip = LABEL_ALIGN_MAX_SKIP; 113450503Sobrien } 113550503Sobrien } 113650503Sobrien } 113750503Sobrien LABEL_TO_ALIGNMENT (insn) = max_log; 113850503Sobrien LABEL_TO_MAX_SKIP (insn) = max_skip; 113950503Sobrien max_log = 0; 114050503Sobrien max_skip = 0; 114150503Sobrien } 114250503Sobrien else if (GET_CODE (insn) == BARRIER) 114350503Sobrien { 114450503Sobrien rtx label; 114550503Sobrien 114690087Sobrien for (label = insn; label && ! INSN_P (label); 114750503Sobrien label = NEXT_INSN (label)) 114850503Sobrien if (GET_CODE (label) == CODE_LABEL) 114950503Sobrien { 115050503Sobrien log = LABEL_ALIGN_AFTER_BARRIER (insn); 115150503Sobrien if (max_log < log) 115250503Sobrien { 115350503Sobrien max_log = log; 115450503Sobrien max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP; 115550503Sobrien } 115650503Sobrien break; 115750503Sobrien } 115850503Sobrien } 115950503Sobrien } 116050503Sobrien#ifdef HAVE_ATTR_length 116150503Sobrien 116250503Sobrien /* Allocate the rest of the arrays. */ 116390087Sobrien insn_lengths = (int *) xmalloc (max_uid * sizeof (*insn_lengths)); 116452515Sobrien insn_lengths_max_uid = max_uid; 116550503Sobrien /* Syntax errors can lead to labels being outside of the main insn stream. 116650503Sobrien Initialize insn_addresses, so that we get reproducible results. */ 116790087Sobrien INSN_ADDRESSES_ALLOC (max_uid); 116850503Sobrien 116990087Sobrien varying_length = (char *) xcalloc (max_uid, sizeof (char)); 117050503Sobrien 117150503Sobrien /* Initialize uid_align. We scan instructions 117250503Sobrien from end to start, and keep in align_tab[n] the last seen insn 117350503Sobrien that does an alignment of at least n+1, i.e. the successor 117450503Sobrien in the alignment chain for an insn that does / has a known 117550503Sobrien alignment of n. */ 117690087Sobrien uid_align = (rtx *) xcalloc (max_uid, sizeof *uid_align); 117750503Sobrien 117890087Sobrien for (i = MAX_CODE_ALIGN; --i >= 0;) 117950503Sobrien align_tab[i] = NULL_RTX; 118050503Sobrien seq = get_last_insn (); 118150503Sobrien for (; seq; seq = PREV_INSN (seq)) 118250503Sobrien { 118350503Sobrien int uid = INSN_UID (seq); 118450503Sobrien int log; 118550503Sobrien log = (GET_CODE (seq) == CODE_LABEL ? LABEL_TO_ALIGNMENT (seq) : 0); 118650503Sobrien uid_align[uid] = align_tab[0]; 118750503Sobrien if (log) 118850503Sobrien { 118950503Sobrien /* Found an alignment label. */ 119050503Sobrien uid_align[uid] = align_tab[log]; 119150503Sobrien for (i = log - 1; i >= 0; i--) 119250503Sobrien align_tab[i] = seq; 119350503Sobrien } 119450503Sobrien } 119550503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE 119650503Sobrien if (optimize) 119750503Sobrien { 119850503Sobrien /* Look for ADDR_DIFF_VECs, and initialize their minimum and maximum 119950503Sobrien label fields. */ 120050503Sobrien 120150503Sobrien int min_shuid = INSN_SHUID (get_insns ()) - 1; 120250503Sobrien int max_shuid = INSN_SHUID (get_last_insn ()) + 1; 120350503Sobrien int rel; 120450503Sobrien 120550503Sobrien for (insn = first; insn != 0; insn = NEXT_INSN (insn)) 120650503Sobrien { 120750503Sobrien rtx min_lab = NULL_RTX, max_lab = NULL_RTX, pat; 120850503Sobrien int len, i, min, max, insn_shuid; 120950503Sobrien int min_align; 121050503Sobrien addr_diff_vec_flags flags; 121150503Sobrien 121250503Sobrien if (GET_CODE (insn) != JUMP_INSN 121350503Sobrien || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC) 121450503Sobrien continue; 121550503Sobrien pat = PATTERN (insn); 121650503Sobrien len = XVECLEN (pat, 1); 121750503Sobrien if (len <= 0) 121850503Sobrien abort (); 121950503Sobrien min_align = MAX_CODE_ALIGN; 122050503Sobrien for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--) 122150503Sobrien { 122250503Sobrien rtx lab = XEXP (XVECEXP (pat, 1, i), 0); 122350503Sobrien int shuid = INSN_SHUID (lab); 122450503Sobrien if (shuid < min) 122550503Sobrien { 122650503Sobrien min = shuid; 122750503Sobrien min_lab = lab; 122850503Sobrien } 122950503Sobrien if (shuid > max) 123050503Sobrien { 123150503Sobrien max = shuid; 123250503Sobrien max_lab = lab; 123350503Sobrien } 123450503Sobrien if (min_align > LABEL_TO_ALIGNMENT (lab)) 123550503Sobrien min_align = LABEL_TO_ALIGNMENT (lab); 123650503Sobrien } 123750503Sobrien XEXP (pat, 2) = gen_rtx_LABEL_REF (VOIDmode, min_lab); 123850503Sobrien XEXP (pat, 3) = gen_rtx_LABEL_REF (VOIDmode, max_lab); 123950503Sobrien insn_shuid = INSN_SHUID (insn); 124050503Sobrien rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0)); 124150503Sobrien flags.min_align = min_align; 124250503Sobrien flags.base_after_vec = rel > insn_shuid; 124350503Sobrien flags.min_after_vec = min > insn_shuid; 124450503Sobrien flags.max_after_vec = max > insn_shuid; 124550503Sobrien flags.min_after_base = min > rel; 124650503Sobrien flags.max_after_base = max > rel; 124750503Sobrien ADDR_DIFF_VEC_FLAGS (pat) = flags; 124850503Sobrien } 124950503Sobrien } 125050503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */ 125150503Sobrien 125218334Speter /* Compute initial lengths, addresses, and varying flags for each insn. */ 125318334Speter for (insn_current_address = FIRST_INSN_ADDRESS, insn = first; 125418334Speter insn != 0; 125518334Speter insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn)) 125618334Speter { 125718334Speter uid = INSN_UID (insn); 125850503Sobrien 125950503Sobrien insn_lengths[uid] = 0; 126050503Sobrien 126150503Sobrien if (GET_CODE (insn) == CODE_LABEL) 126250503Sobrien { 126350503Sobrien int log = LABEL_TO_ALIGNMENT (insn); 126450503Sobrien if (log) 126550503Sobrien { 126650503Sobrien int align = 1 << log; 126750503Sobrien int new_address = (insn_current_address + align - 1) & -align; 126850503Sobrien insn_lengths[uid] = new_address - insn_current_address; 126950503Sobrien } 127050503Sobrien } 127150503Sobrien 1272117404Skan INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid]; 127390087Sobrien 127418334Speter if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER 127518334Speter || GET_CODE (insn) == CODE_LABEL) 127618334Speter continue; 127750503Sobrien if (INSN_DELETED_P (insn)) 127850503Sobrien continue; 127918334Speter 128018334Speter body = PATTERN (insn); 128118334Speter if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) 128218334Speter { 128318334Speter /* This only takes room if read-only data goes into the text 128418334Speter section. */ 1285117404Skan if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION) 128650503Sobrien insn_lengths[uid] = (XVECLEN (body, 128750503Sobrien GET_CODE (body) == ADDR_DIFF_VEC) 128850503Sobrien * GET_MODE_SIZE (GET_MODE (body))); 128950503Sobrien /* Alignment is handled by ADDR_VEC_ALIGN. */ 129018334Speter } 129190087Sobrien else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0) 129218334Speter insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn); 129318334Speter else if (GET_CODE (body) == SEQUENCE) 129418334Speter { 129518334Speter int i; 129618334Speter int const_delay_slots; 129718334Speter#ifdef DELAY_SLOTS 129818334Speter const_delay_slots = const_num_delay_slots (XVECEXP (body, 0, 0)); 129918334Speter#else 130018334Speter const_delay_slots = 0; 130118334Speter#endif 130218334Speter /* Inside a delay slot sequence, we do not do any branch shortening 130318334Speter if the shortening could change the number of delay slots 130450503Sobrien of the branch. */ 130518334Speter for (i = 0; i < XVECLEN (body, 0); i++) 130618334Speter { 130718334Speter rtx inner_insn = XVECEXP (body, 0, i); 130818334Speter int inner_uid = INSN_UID (inner_insn); 130918334Speter int inner_length; 131018334Speter 131190087Sobrien if (GET_CODE (body) == ASM_INPUT 131290087Sobrien || asm_noperands (PATTERN (XVECEXP (body, 0, i))) >= 0) 131318334Speter inner_length = (asm_insn_count (PATTERN (inner_insn)) 131418334Speter * insn_default_length (inner_insn)); 131518334Speter else 131618334Speter inner_length = insn_default_length (inner_insn); 131790087Sobrien 131818334Speter insn_lengths[inner_uid] = inner_length; 131918334Speter if (const_delay_slots) 132018334Speter { 132118334Speter if ((varying_length[inner_uid] 132218334Speter = insn_variable_length_p (inner_insn)) != 0) 132318334Speter varying_length[uid] = 1; 132490087Sobrien INSN_ADDRESSES (inner_uid) = (insn_current_address 132590087Sobrien + insn_lengths[uid]); 132618334Speter } 132718334Speter else 132818334Speter varying_length[inner_uid] = 0; 132918334Speter insn_lengths[uid] += inner_length; 133018334Speter } 133118334Speter } 133218334Speter else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER) 133318334Speter { 133418334Speter insn_lengths[uid] = insn_default_length (insn); 133518334Speter varying_length[uid] = insn_variable_length_p (insn); 133618334Speter } 133718334Speter 133818334Speter /* If needed, do any adjustment. */ 133918334Speter#ifdef ADJUST_INSN_LENGTH 134018334Speter ADJUST_INSN_LENGTH (insn, insn_lengths[uid]); 134152515Sobrien if (insn_lengths[uid] < 0) 134290087Sobrien fatal_insn ("negative insn length", insn); 134318334Speter#endif 134418334Speter } 134518334Speter 134618334Speter /* Now loop over all the insns finding varying length insns. For each, 134718334Speter get the current insn length. If it has changed, reflect the change. 134818334Speter When nothing changes for a full pass, we are done. */ 134918334Speter 135018334Speter while (something_changed) 135118334Speter { 135218334Speter something_changed = 0; 135350503Sobrien insn_current_align = MAX_CODE_ALIGN - 1; 135418334Speter for (insn_current_address = FIRST_INSN_ADDRESS, insn = first; 135518334Speter insn != 0; 135618334Speter insn = NEXT_INSN (insn)) 135718334Speter { 135818334Speter int new_length; 135950503Sobrien#ifdef ADJUST_INSN_LENGTH 136018334Speter int tmp_length; 136150503Sobrien#endif 136250503Sobrien int length_align; 136318334Speter 136418334Speter uid = INSN_UID (insn); 136550503Sobrien 136650503Sobrien if (GET_CODE (insn) == CODE_LABEL) 136750503Sobrien { 136850503Sobrien int log = LABEL_TO_ALIGNMENT (insn); 136950503Sobrien if (log > insn_current_align) 137050503Sobrien { 137150503Sobrien int align = 1 << log; 137250503Sobrien int new_address= (insn_current_address + align - 1) & -align; 137350503Sobrien insn_lengths[uid] = new_address - insn_current_address; 137450503Sobrien insn_current_align = log; 137550503Sobrien insn_current_address = new_address; 137650503Sobrien } 137750503Sobrien else 137850503Sobrien insn_lengths[uid] = 0; 137990087Sobrien INSN_ADDRESSES (uid) = insn_current_address; 138050503Sobrien continue; 138150503Sobrien } 138250503Sobrien 138350503Sobrien length_align = INSN_LENGTH_ALIGNMENT (insn); 138450503Sobrien if (length_align < insn_current_align) 138550503Sobrien insn_current_align = length_align; 138650503Sobrien 138790087Sobrien insn_last_address = INSN_ADDRESSES (uid); 138890087Sobrien INSN_ADDRESSES (uid) = insn_current_address; 138950503Sobrien 139050503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE 139150503Sobrien if (optimize && GET_CODE (insn) == JUMP_INSN 139250503Sobrien && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC) 139318334Speter { 139450503Sobrien rtx body = PATTERN (insn); 139550503Sobrien int old_length = insn_lengths[uid]; 139650503Sobrien rtx rel_lab = XEXP (XEXP (body, 0), 0); 139750503Sobrien rtx min_lab = XEXP (XEXP (body, 2), 0); 139850503Sobrien rtx max_lab = XEXP (XEXP (body, 3), 0); 139990087Sobrien int rel_addr = INSN_ADDRESSES (INSN_UID (rel_lab)); 140090087Sobrien int min_addr = INSN_ADDRESSES (INSN_UID (min_lab)); 140190087Sobrien int max_addr = INSN_ADDRESSES (INSN_UID (max_lab)); 140250503Sobrien rtx prev; 140350503Sobrien int rel_align = 0; 140490087Sobrien addr_diff_vec_flags flags; 140550503Sobrien 140690087Sobrien /* Avoid automatic aggregate initialization. */ 140790087Sobrien flags = ADDR_DIFF_VEC_FLAGS (body); 140890087Sobrien 140950503Sobrien /* Try to find a known alignment for rel_lab. */ 141050503Sobrien for (prev = rel_lab; 141150503Sobrien prev 141250503Sobrien && ! insn_lengths[INSN_UID (prev)] 141350503Sobrien && ! (varying_length[INSN_UID (prev)] & 1); 141450503Sobrien prev = PREV_INSN (prev)) 141550503Sobrien if (varying_length[INSN_UID (prev)] & 2) 141650503Sobrien { 141750503Sobrien rel_align = LABEL_TO_ALIGNMENT (prev); 141850503Sobrien break; 141950503Sobrien } 142050503Sobrien 142150503Sobrien /* See the comment on addr_diff_vec_flags in rtl.h for the 142250503Sobrien meaning of the flags values. base: REL_LAB vec: INSN */ 142350503Sobrien /* Anything after INSN has still addresses from the last 142450503Sobrien pass; adjust these so that they reflect our current 142550503Sobrien estimate for this pass. */ 142650503Sobrien if (flags.base_after_vec) 142750503Sobrien rel_addr += insn_current_address - insn_last_address; 142850503Sobrien if (flags.min_after_vec) 142950503Sobrien min_addr += insn_current_address - insn_last_address; 143050503Sobrien if (flags.max_after_vec) 143150503Sobrien max_addr += insn_current_address - insn_last_address; 143250503Sobrien /* We want to know the worst case, i.e. lowest possible value 143350503Sobrien for the offset of MIN_LAB. If MIN_LAB is after REL_LAB, 143450503Sobrien its offset is positive, and we have to be wary of code shrink; 143550503Sobrien otherwise, it is negative, and we have to be vary of code 143650503Sobrien size increase. */ 143750503Sobrien if (flags.min_after_base) 143850503Sobrien { 143950503Sobrien /* If INSN is between REL_LAB and MIN_LAB, the size 144050503Sobrien changes we are about to make can change the alignment 144150503Sobrien within the observed offset, therefore we have to break 144250503Sobrien it up into two parts that are independent. */ 144350503Sobrien if (! flags.base_after_vec && flags.min_after_vec) 144450503Sobrien { 144550503Sobrien min_addr -= align_fuzz (rel_lab, insn, rel_align, 0); 144650503Sobrien min_addr -= align_fuzz (insn, min_lab, 0, 0); 144750503Sobrien } 144850503Sobrien else 144950503Sobrien min_addr -= align_fuzz (rel_lab, min_lab, rel_align, 0); 145050503Sobrien } 145150503Sobrien else 145250503Sobrien { 145350503Sobrien if (flags.base_after_vec && ! flags.min_after_vec) 145450503Sobrien { 145550503Sobrien min_addr -= align_fuzz (min_lab, insn, 0, ~0); 145650503Sobrien min_addr -= align_fuzz (insn, rel_lab, 0, ~0); 145750503Sobrien } 145850503Sobrien else 145950503Sobrien min_addr -= align_fuzz (min_lab, rel_lab, 0, ~0); 146050503Sobrien } 146150503Sobrien /* Likewise, determine the highest lowest possible value 146250503Sobrien for the offset of MAX_LAB. */ 146350503Sobrien if (flags.max_after_base) 146450503Sobrien { 146550503Sobrien if (! flags.base_after_vec && flags.max_after_vec) 146650503Sobrien { 146750503Sobrien max_addr += align_fuzz (rel_lab, insn, rel_align, ~0); 146850503Sobrien max_addr += align_fuzz (insn, max_lab, 0, ~0); 146950503Sobrien } 147050503Sobrien else 147150503Sobrien max_addr += align_fuzz (rel_lab, max_lab, rel_align, ~0); 147250503Sobrien } 147350503Sobrien else 147450503Sobrien { 147550503Sobrien if (flags.base_after_vec && ! flags.max_after_vec) 147650503Sobrien { 147750503Sobrien max_addr += align_fuzz (max_lab, insn, 0, 0); 147850503Sobrien max_addr += align_fuzz (insn, rel_lab, 0, 0); 147950503Sobrien } 148050503Sobrien else 148150503Sobrien max_addr += align_fuzz (max_lab, rel_lab, 0, 0); 148250503Sobrien } 148350503Sobrien PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr, 148450503Sobrien max_addr - rel_addr, 148550503Sobrien body)); 1486117404Skan if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION) 148750503Sobrien { 148850503Sobrien insn_lengths[uid] 148950503Sobrien = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body))); 149050503Sobrien insn_current_address += insn_lengths[uid]; 149150503Sobrien if (insn_lengths[uid] != old_length) 149250503Sobrien something_changed = 1; 149350503Sobrien } 149450503Sobrien 149550503Sobrien continue; 149650503Sobrien } 149750503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */ 149850503Sobrien 149950503Sobrien if (! (varying_length[uid])) 150050503Sobrien { 150190087Sobrien if (GET_CODE (insn) == INSN 150290087Sobrien && GET_CODE (PATTERN (insn)) == SEQUENCE) 150390087Sobrien { 150490087Sobrien int i; 150590087Sobrien 150690087Sobrien body = PATTERN (insn); 150790087Sobrien for (i = 0; i < XVECLEN (body, 0); i++) 150890087Sobrien { 150990087Sobrien rtx inner_insn = XVECEXP (body, 0, i); 151090087Sobrien int inner_uid = INSN_UID (inner_insn); 151190087Sobrien 151290087Sobrien INSN_ADDRESSES (inner_uid) = insn_current_address; 151390087Sobrien 151490087Sobrien insn_current_address += insn_lengths[inner_uid]; 151590087Sobrien } 1516117404Skan } 151790087Sobrien else 151890087Sobrien insn_current_address += insn_lengths[uid]; 151990087Sobrien 152018334Speter continue; 152118334Speter } 152290087Sobrien 152318334Speter if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) 152418334Speter { 152518334Speter int i; 152690087Sobrien 152718334Speter body = PATTERN (insn); 152818334Speter new_length = 0; 152918334Speter for (i = 0; i < XVECLEN (body, 0); i++) 153018334Speter { 153118334Speter rtx inner_insn = XVECEXP (body, 0, i); 153218334Speter int inner_uid = INSN_UID (inner_insn); 153318334Speter int inner_length; 153418334Speter 153590087Sobrien INSN_ADDRESSES (inner_uid) = insn_current_address; 153618334Speter 153718334Speter /* insn_current_length returns 0 for insns with a 153818334Speter non-varying length. */ 153918334Speter if (! varying_length[inner_uid]) 154018334Speter inner_length = insn_lengths[inner_uid]; 154118334Speter else 154218334Speter inner_length = insn_current_length (inner_insn); 154318334Speter 154418334Speter if (inner_length != insn_lengths[inner_uid]) 154518334Speter { 154618334Speter insn_lengths[inner_uid] = inner_length; 154718334Speter something_changed = 1; 154818334Speter } 154918334Speter insn_current_address += insn_lengths[inner_uid]; 155018334Speter new_length += inner_length; 155118334Speter } 155218334Speter } 155318334Speter else 155418334Speter { 155518334Speter new_length = insn_current_length (insn); 155618334Speter insn_current_address += new_length; 155718334Speter } 155818334Speter 155918334Speter#ifdef ADJUST_INSN_LENGTH 156018334Speter /* If needed, do any adjustment. */ 156118334Speter tmp_length = new_length; 156218334Speter ADJUST_INSN_LENGTH (insn, new_length); 156318334Speter insn_current_address += (new_length - tmp_length); 156418334Speter#endif 156518334Speter 156618334Speter if (new_length != insn_lengths[uid]) 156718334Speter { 156818334Speter insn_lengths[uid] = new_length; 156918334Speter something_changed = 1; 157018334Speter } 157118334Speter } 157218334Speter /* For a non-optimizing compile, do only a single pass. */ 157318334Speter if (!optimize) 157418334Speter break; 157518334Speter } 157650503Sobrien 157750503Sobrien free (varying_length); 157850503Sobrien 157918334Speter#endif /* HAVE_ATTR_length */ 158018334Speter} 158118334Speter 158218334Speter#ifdef HAVE_ATTR_length 158318334Speter/* Given the body of an INSN known to be generated by an ASM statement, return 158418334Speter the number of machine instructions likely to be generated for this insn. 158518334Speter This is used to compute its length. */ 158618334Speter 158718334Speterstatic int 158818334Speterasm_insn_count (body) 158918334Speter rtx body; 159018334Speter{ 159190087Sobrien const char *template; 159218334Speter int count = 1; 159318334Speter 159418334Speter if (GET_CODE (body) == ASM_INPUT) 159518334Speter template = XSTR (body, 0); 159618334Speter else 159790087Sobrien template = decode_asm_operands (body, NULL, NULL, NULL, NULL); 159818334Speter 159990087Sobrien for (; *template; template++) 160090087Sobrien if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n') 160118334Speter count++; 160218334Speter 160318334Speter return count; 160418334Speter} 160518334Speter#endif 160618334Speter 160718334Speter/* Output assembler code for the start of a function, 160818334Speter and initialize some of the variables in this file 160918334Speter for the new function. The label for the function and associated 161018334Speter assembler pseudo-ops have already been output in `assemble_start_function'. 161118334Speter 161218334Speter FIRST is the first insn of the rtl for the function being compiled. 161318334Speter FILE is the file to write assembler code to. 161418334Speter OPTIMIZE is nonzero if we should eliminate redundant 161518334Speter test and compare insns. */ 161618334Speter 161718334Spetervoid 161818334Speterfinal_start_function (first, file, optimize) 161918334Speter rtx first; 162018334Speter FILE *file; 162190087Sobrien int optimize ATTRIBUTE_UNUSED; 162218334Speter{ 162318334Speter block_depth = 0; 162418334Speter 162518334Speter this_is_asm_operands = 0; 162618334Speter 162718334Speter#ifdef NON_SAVING_SETJMP 162818334Speter /* A function that calls setjmp should save and restore all the 162918334Speter call-saved registers on a system where longjmp clobbers them. */ 163018334Speter if (NON_SAVING_SETJMP && current_function_calls_setjmp) 163118334Speter { 163218334Speter int i; 163318334Speter 163418334Speter for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 163552515Sobrien if (!call_used_regs[i]) 163618334Speter regs_ever_live[i] = 1; 163718334Speter } 163818334Speter#endif 163990087Sobrien 164018334Speter if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED) 164190087Sobrien notice_source_line (first); 164290087Sobrien high_block_linenum = high_function_linenum = last_linenum; 164318334Speter 164490087Sobrien (*debug_hooks->begin_prologue) (last_linenum, last_filename); 164550503Sobrien 164690087Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (IA64_UNWIND_INFO) 164790087Sobrien if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG) 164890087Sobrien dwarf2out_begin_prologue (0, NULL); 164918334Speter#endif 165018334Speter 165118334Speter#ifdef LEAF_REG_REMAP 165252515Sobrien if (current_function_uses_only_leaf_regs) 165318334Speter leaf_renumber_regs (first); 165418334Speter#endif 165518334Speter 165618334Speter /* The Sun386i and perhaps other machines don't work right 165718334Speter if the profiling code comes after the prologue. */ 165818334Speter#ifdef PROFILE_BEFORE_PROLOGUE 165990087Sobrien if (current_function_profile) 166018334Speter profile_function (file); 166118334Speter#endif /* PROFILE_BEFORE_PROLOGUE */ 166218334Speter 166350503Sobrien#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue) 166450503Sobrien if (dwarf2out_do_frame ()) 166550503Sobrien dwarf2out_frame_debug (NULL_RTX); 166650503Sobrien#endif 166750503Sobrien 166890087Sobrien /* If debugging, assign block numbers to all of the blocks in this 166990087Sobrien function. */ 167090087Sobrien if (write_symbols) 167190087Sobrien { 167290087Sobrien remove_unnecessary_notes (); 1673117404Skan scope_to_insns_finalize (); 167490087Sobrien number_blocks (current_function_decl); 167590087Sobrien /* We never actually put out begin/end notes for the top-level 167690087Sobrien block in the function. But, conceptually, that block is 167790087Sobrien always needed. */ 167890087Sobrien TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1; 167990087Sobrien } 168090087Sobrien 168118334Speter /* First output the function prologue: code to set up the stack frame. */ 168290087Sobrien (*targetm.asm_out.function_prologue) (file, get_frame_size ()); 168318334Speter 168418334Speter /* If the machine represents the prologue as RTL, the profiling code must 168518334Speter be emitted when NOTE_INSN_PROLOGUE_END is scanned. */ 168618334Speter#ifdef HAVE_prologue 168718334Speter if (! HAVE_prologue) 168818334Speter#endif 168918334Speter profile_after_prologue (file); 169018334Speter} 169118334Speter 169218334Speterstatic void 169318334Speterprofile_after_prologue (file) 169490087Sobrien FILE *file ATTRIBUTE_UNUSED; 169518334Speter{ 169618334Speter#ifndef PROFILE_BEFORE_PROLOGUE 169790087Sobrien if (current_function_profile) 169818334Speter profile_function (file); 169918334Speter#endif /* not PROFILE_BEFORE_PROLOGUE */ 170018334Speter} 170118334Speter 170218334Speterstatic void 170318334Speterprofile_function (file) 170490087Sobrien FILE *file ATTRIBUTE_UNUSED; 170518334Speter{ 170674478Sobrien#ifndef NO_PROFILE_COUNTERS 170750503Sobrien int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE); 170874478Sobrien#endif 170950503Sobrien#if defined(ASM_OUTPUT_REG_PUSH) 171050503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) || defined(STRUCT_VALUE_REGNUM) 171118334Speter int sval = current_function_returns_struct; 171250503Sobrien#endif 171350503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM) 171418334Speter int cxt = current_function_needs_context; 171550503Sobrien#endif 171650503Sobrien#endif /* ASM_OUTPUT_REG_PUSH */ 171718334Speter 171874478Sobrien#ifndef NO_PROFILE_COUNTERS 171918334Speter data_section (); 172018334Speter ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT)); 1721117404Skan ASM_OUTPUT_INTERNAL_LABEL (file, "LP", current_function_funcdef_no); 172290087Sobrien assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1); 172374478Sobrien#endif 172418334Speter 172550503Sobrien function_section (current_function_decl); 172618334Speter 172750503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 172818334Speter if (sval) 172918334Speter ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_INCOMING_REGNUM); 173018334Speter#else 173150503Sobrien#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 173218334Speter if (sval) 173350503Sobrien { 173450503Sobrien ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_REGNUM); 173550503Sobrien } 173618334Speter#endif 173718334Speter#endif 173818334Speter 173950503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 174018334Speter if (cxt) 174118334Speter ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM); 174218334Speter#else 174350503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 174418334Speter if (cxt) 174550503Sobrien { 174650503Sobrien ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM); 174750503Sobrien } 174818334Speter#endif 174918334Speter#endif 175018334Speter 1751117404Skan FUNCTION_PROFILER (file, current_function_funcdef_no); 175218334Speter 175350503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 175418334Speter if (cxt) 175518334Speter ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM); 175618334Speter#else 175750503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 175818334Speter if (cxt) 175950503Sobrien { 176050503Sobrien ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM); 176150503Sobrien } 176218334Speter#endif 176318334Speter#endif 176418334Speter 176550503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 176618334Speter if (sval) 176718334Speter ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_INCOMING_REGNUM); 176818334Speter#else 176950503Sobrien#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH) 177018334Speter if (sval) 177150503Sobrien { 177250503Sobrien ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_REGNUM); 177350503Sobrien } 177418334Speter#endif 177518334Speter#endif 177618334Speter} 177718334Speter 177818334Speter/* Output assembler code for the end of a function. 177918334Speter For clarity, args are same as those of `final_start_function' 178018334Speter even though not all of them are needed. */ 178118334Speter 178218334Spetervoid 178390087Sobrienfinal_end_function () 178418334Speter{ 178590087Sobrien app_disable (); 178618334Speter 178790087Sobrien (*debug_hooks->end_function) (high_function_linenum); 178818334Speter 178918334Speter /* Finally, output the function epilogue: 179018334Speter code to restore the stack frame and return to the caller. */ 179190087Sobrien (*targetm.asm_out.function_epilogue) (asm_out_file, get_frame_size ()); 179218334Speter 179390087Sobrien /* And debug output. */ 1794117404Skan (*debug_hooks->end_epilogue) (last_linenum, last_filename); 179590087Sobrien 179690087Sobrien#if defined (DWARF2_UNWIND_INFO) 179790087Sobrien if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG 179890087Sobrien && dwarf2out_do_frame ()) 1799117404Skan dwarf2out_end_epilogue (last_linenum, last_filename); 180050503Sobrien#endif 180118334Speter} 180218334Speter 180318334Speter/* Output assembler code for some insns: all or part of a function. 180418334Speter For description of args, see `final_start_function', above. 180518334Speter 180618334Speter PRESCAN is 1 if we are not really outputting, 180718334Speter just scanning as if we were outputting. 180818334Speter Prescanning deletes and rearranges insns just like ordinary output. 180918334Speter PRESCAN is -2 if we are outputting after having prescanned. 181018334Speter In this case, don't try to delete or rearrange insns 181118334Speter because that has already been done. 181218334Speter Prescanning is done only on certain machines. */ 181318334Speter 181418334Spetervoid 181518334Speterfinal (first, file, optimize, prescan) 181618334Speter rtx first; 181718334Speter FILE *file; 181818334Speter int optimize; 181918334Speter int prescan; 182018334Speter{ 182190087Sobrien rtx insn; 182218334Speter int max_line = 0; 182350503Sobrien int max_uid = 0; 182418334Speter 182518334Speter last_ignored_compare = 0; 182618334Speter new_block = 1; 182718334Speter 182818334Speter /* Make a map indicating which line numbers appear in this function. 182918334Speter When producing SDB debugging info, delete troublesome line number 183018334Speter notes from inlined functions in other files as well as duplicate 183118334Speter line number notes. */ 183218334Speter#ifdef SDB_DEBUGGING_INFO 183318334Speter if (write_symbols == SDB_DEBUG) 183418334Speter { 183518334Speter rtx last = 0; 183618334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 183718334Speter if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) 183818334Speter { 183918334Speter if ((RTX_INTEGRATED_P (insn) 184018334Speter && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0) 184118334Speter || (last != 0 184218334Speter && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last) 184318334Speter && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last))) 184418334Speter { 184590087Sobrien delete_insn (insn); /* Use delete_note. */ 184618334Speter continue; 184718334Speter } 184818334Speter last = insn; 184918334Speter if (NOTE_LINE_NUMBER (insn) > max_line) 185018334Speter max_line = NOTE_LINE_NUMBER (insn); 185118334Speter } 185218334Speter } 185318334Speter else 185418334Speter#endif 185518334Speter { 185618334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 185718334Speter if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > max_line) 185818334Speter max_line = NOTE_LINE_NUMBER (insn); 185918334Speter } 186018334Speter 186190087Sobrien line_note_exists = (char *) xcalloc (max_line + 1, sizeof (char)); 186218334Speter 186318334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 186450503Sobrien { 186550503Sobrien if (INSN_UID (insn) > max_uid) /* find largest UID */ 186690087Sobrien max_uid = INSN_UID (insn); 186750503Sobrien if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) 186890087Sobrien line_note_exists[NOTE_LINE_NUMBER (insn)] = 1; 186952515Sobrien#ifdef HAVE_cc0 187052515Sobrien /* If CC tracking across branches is enabled, record the insn which 187152515Sobrien jumps to each branch only reached from one place. */ 187252515Sobrien if (optimize && GET_CODE (insn) == JUMP_INSN) 187352515Sobrien { 187452515Sobrien rtx lab = JUMP_LABEL (insn); 187552515Sobrien if (lab && LABEL_NUSES (lab) == 1) 187652515Sobrien { 187752515Sobrien LABEL_REFS (lab) = insn; 187852515Sobrien } 187952515Sobrien } 188052515Sobrien#endif 188150503Sobrien } 188218334Speter 188318334Speter init_recog (); 188418334Speter 188518334Speter CC_STATUS_INIT; 188618334Speter 188718334Speter /* Output the insns. */ 188818334Speter for (insn = NEXT_INSN (first); insn;) 188950503Sobrien { 189050503Sobrien#ifdef HAVE_ATTR_length 189190087Sobrien if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ()) 189290087Sobrien { 189390087Sobrien /* This can be triggered by bugs elsewhere in the compiler if 189490087Sobrien new insns are created after init_insn_lengths is called. */ 1895117404Skan if (GET_CODE (insn) == NOTE) 1896117404Skan insn_current_address = -1; 1897117404Skan else 1898117404Skan abort (); 189990087Sobrien } 190090087Sobrien else 190190087Sobrien insn_current_address = INSN_ADDRESSES (INSN_UID (insn)); 190290087Sobrien#endif /* HAVE_ATTR_length */ 190390087Sobrien 190450503Sobrien insn = final_scan_insn (insn, file, optimize, prescan, 0); 190550503Sobrien } 190618334Speter 1907117404Skan /* Store function names for edge-profiling. */ 1908117404Skan /* ??? Probably should re-use the existing struct function. */ 1909117404Skan 1910117404Skan if (cfun->arc_profile) 1911117404Skan { 1912117404Skan struct function_list *new_item = xmalloc (sizeof (struct function_list)); 1913117404Skan 1914117404Skan *functions_tail = new_item; 1915117404Skan functions_tail = &new_item->next; 1916117404Skan 1917117404Skan new_item->next = 0; 1918117404Skan new_item->name = xstrdup (IDENTIFIER_POINTER 1919117404Skan (DECL_ASSEMBLER_NAME (current_function_decl))); 1920117404Skan new_item->cfg_checksum = profile_info.current_function_cfg_checksum; 1921117404Skan new_item->count_edges = profile_info.count_edges_instrumented_now; 1922117404Skan } 1923117404Skan 192490087Sobrien free (line_note_exists); 192590087Sobrien line_note_exists = NULL; 192690087Sobrien} 192790087Sobrien 192890087Sobrienconst char * 192990087Sobrienget_insn_template (code, insn) 193090087Sobrien int code; 193190087Sobrien rtx insn; 193290087Sobrien{ 193390087Sobrien const void *output = insn_data[code].output; 193490087Sobrien switch (insn_data[code].output_format) 193590087Sobrien { 193690087Sobrien case INSN_OUTPUT_FORMAT_SINGLE: 193790087Sobrien return (const char *) output; 193890087Sobrien case INSN_OUTPUT_FORMAT_MULTI: 193990087Sobrien return ((const char *const *) output)[which_alternative]; 194090087Sobrien case INSN_OUTPUT_FORMAT_FUNCTION: 194190087Sobrien if (insn == NULL) 194290087Sobrien abort (); 194390087Sobrien return (*(insn_output_fn) output) (recog_data.operand, insn); 194450503Sobrien 194590087Sobrien default: 194690087Sobrien abort (); 194790087Sobrien } 194818334Speter} 194990087Sobrien 1950117404Skan/* Emit the appropriate declaration for an alternate-entry-point 1951117404Skan symbol represented by INSN, to FILE. INSN is a CODE_LABEL with 1952117404Skan LABEL_KIND != LABEL_NORMAL. 1953117404Skan 1954117404Skan The case fall-through in this function is intentional. */ 1955117404Skanstatic void 1956117404Skanoutput_alternate_entry_point (file, insn) 1957117404Skan FILE *file; 1958117404Skan rtx insn; 1959117404Skan{ 1960117404Skan const char *name = LABEL_NAME (insn); 1961117404Skan 1962117404Skan switch (LABEL_KIND (insn)) 1963117404Skan { 1964117404Skan case LABEL_WEAK_ENTRY: 1965117404Skan#ifdef ASM_WEAKEN_LABEL 1966117404Skan ASM_WEAKEN_LABEL (file, name); 1967117404Skan#endif 1968117404Skan case LABEL_GLOBAL_ENTRY: 1969117404Skan (*targetm.asm_out.globalize_label) (file, name); 1970117404Skan case LABEL_STATIC_ENTRY: 1971117404Skan#ifdef ASM_OUTPUT_TYPE_DIRECTIVE 1972117404Skan ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function"); 1973117404Skan#endif 1974117404Skan ASM_OUTPUT_LABEL (file, name); 1975117404Skan break; 1976117404Skan 1977117404Skan case LABEL_NORMAL: 1978117404Skan default: 1979117404Skan abort (); 1980117404Skan } 1981117404Skan} 1982117404Skan 198318334Speter/* The final scan for one insn, INSN. 198418334Speter Args are same as in `final', except that INSN 198518334Speter is the insn being scanned. 198618334Speter Value returned is the next insn to be scanned. 198718334Speter 198818334Speter NOPEEPHOLES is the flag to disallow peephole processing (currently 198918334Speter used for within delayed branch sequence output). */ 199018334Speter 199118334Speterrtx 199218334Speterfinal_scan_insn (insn, file, optimize, prescan, nopeepholes) 199318334Speter rtx insn; 199418334Speter FILE *file; 199590087Sobrien int optimize ATTRIBUTE_UNUSED; 199618334Speter int prescan; 199790087Sobrien int nopeepholes ATTRIBUTE_UNUSED; 199818334Speter{ 199950503Sobrien#ifdef HAVE_cc0 200050503Sobrien rtx set; 200150503Sobrien#endif 200250503Sobrien 200318334Speter insn_counter++; 200418334Speter 200518334Speter /* Ignore deleted insns. These can occur when we split insns (due to a 200618334Speter template of "#") while not optimizing. */ 200718334Speter if (INSN_DELETED_P (insn)) 200818334Speter return NEXT_INSN (insn); 200918334Speter 201018334Speter switch (GET_CODE (insn)) 201118334Speter { 201218334Speter case NOTE: 201318334Speter if (prescan > 0) 201418334Speter break; 201518334Speter 201690087Sobrien switch (NOTE_LINE_NUMBER (insn)) 201718334Speter { 201890087Sobrien case NOTE_INSN_DELETED: 201990087Sobrien case NOTE_INSN_LOOP_BEG: 202090087Sobrien case NOTE_INSN_LOOP_END: 202196281Sobrien case NOTE_INSN_LOOP_END_TOP_COND: 202290087Sobrien case NOTE_INSN_LOOP_CONT: 202390087Sobrien case NOTE_INSN_LOOP_VTOP: 202490087Sobrien case NOTE_INSN_FUNCTION_END: 202590087Sobrien case NOTE_INSN_REPEATED_LINE_NUMBER: 202690087Sobrien case NOTE_INSN_EXPECTED_VALUE: 202718334Speter break; 202818334Speter 202990087Sobrien case NOTE_INSN_BASIC_BLOCK: 203090087Sobrien#ifdef IA64_UNWIND_INFO 203190087Sobrien IA64_UNWIND_EMIT (asm_out_file, insn); 203250503Sobrien#endif 203390087Sobrien if (flag_debug_asm) 203490087Sobrien fprintf (asm_out_file, "\t%s basic block %d\n", 203590087Sobrien ASM_COMMENT_START, NOTE_BASIC_BLOCK (insn)->index); 203650503Sobrien break; 203750503Sobrien 203890087Sobrien case NOTE_INSN_EH_REGION_BEG: 203990087Sobrien ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHB", 204090087Sobrien NOTE_EH_HANDLER (insn)); 204190087Sobrien break; 204290087Sobrien 204390087Sobrien case NOTE_INSN_EH_REGION_END: 204490087Sobrien ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHE", 204590087Sobrien NOTE_EH_HANDLER (insn)); 204690087Sobrien break; 204790087Sobrien 204890087Sobrien case NOTE_INSN_PROLOGUE_END: 204990087Sobrien (*targetm.asm_out.function_end_prologue) (file); 205018334Speter profile_after_prologue (file); 205118334Speter break; 205218334Speter 205390087Sobrien case NOTE_INSN_EPILOGUE_BEG: 205490087Sobrien (*targetm.asm_out.function_begin_epilogue) (file); 205518334Speter break; 205618334Speter 205790087Sobrien case NOTE_INSN_FUNCTION_BEG: 205890087Sobrien app_disable (); 2059117404Skan (*debug_hooks->end_prologue) (last_linenum, last_filename); 206018334Speter break; 206190087Sobrien 206290087Sobrien case NOTE_INSN_BLOCK_BEG: 206390087Sobrien if (debug_info_level == DINFO_LEVEL_NORMAL 206418334Speter || debug_info_level == DINFO_LEVEL_VERBOSE 206518334Speter || write_symbols == DWARF_DEBUG 206690087Sobrien || write_symbols == DWARF2_DEBUG 206790087Sobrien || write_symbols == VMS_AND_DWARF2_DEBUG 206890087Sobrien || write_symbols == VMS_DEBUG) 206990087Sobrien { 207090087Sobrien int n = BLOCK_NUMBER (NOTE_BLOCK (insn)); 207118334Speter 207290087Sobrien app_disable (); 207390087Sobrien ++block_depth; 207490087Sobrien high_block_linenum = last_linenum; 207590087Sobrien 207690087Sobrien /* Output debugging info about the symbol-block beginning. */ 207790087Sobrien (*debug_hooks->begin_block) (last_linenum, n); 207890087Sobrien 207990087Sobrien /* Mark this block as output. */ 208090087Sobrien TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1; 208118334Speter } 208290087Sobrien break; 208318334Speter 208490087Sobrien case NOTE_INSN_BLOCK_END: 208590087Sobrien if (debug_info_level == DINFO_LEVEL_NORMAL 208690087Sobrien || debug_info_level == DINFO_LEVEL_VERBOSE 208790087Sobrien || write_symbols == DWARF_DEBUG 208890087Sobrien || write_symbols == DWARF2_DEBUG 208990087Sobrien || write_symbols == VMS_AND_DWARF2_DEBUG 209090087Sobrien || write_symbols == VMS_DEBUG) 209190087Sobrien { 209290087Sobrien int n = BLOCK_NUMBER (NOTE_BLOCK (insn)); 209318334Speter 209490087Sobrien app_disable (); 209518334Speter 209690087Sobrien /* End of a symbol-block. */ 209790087Sobrien --block_depth; 209890087Sobrien if (block_depth < 0) 209990087Sobrien abort (); 210018334Speter 210190087Sobrien (*debug_hooks->end_block) (high_block_linenum, n); 210290087Sobrien } 210390087Sobrien break; 210418334Speter 210590087Sobrien case NOTE_INSN_DELETED_LABEL: 210690087Sobrien /* Emit the label. We may have deleted the CODE_LABEL because 210790087Sobrien the label could be proved to be unreachable, though still 210890087Sobrien referenced (in the form of having its address taken. */ 210990087Sobrien ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); 211090087Sobrien break; 211118334Speter 211290087Sobrien case 0: 211390087Sobrien break; 211418334Speter 211590087Sobrien default: 211690087Sobrien if (NOTE_LINE_NUMBER (insn) <= 0) 211790087Sobrien abort (); 211818334Speter 211990087Sobrien /* This note is a line-number. */ 212090087Sobrien { 212190087Sobrien rtx note; 212290087Sobrien int note_after = 0; 212318334Speter 212490087Sobrien /* If there is anything real after this note, output it. 212590087Sobrien If another line note follows, omit this one. */ 212690087Sobrien for (note = NEXT_INSN (insn); note; note = NEXT_INSN (note)) 212790087Sobrien { 212890087Sobrien if (GET_CODE (note) != NOTE && GET_CODE (note) != CODE_LABEL) 212918334Speter break; 213018334Speter 213190087Sobrien /* These types of notes can be significant 213290087Sobrien so make sure the preceding line number stays. */ 213390087Sobrien else if (GET_CODE (note) == NOTE 213490087Sobrien && (NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_BEG 213590087Sobrien || NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_END 213690087Sobrien || NOTE_LINE_NUMBER (note) == NOTE_INSN_FUNCTION_BEG)) 213790087Sobrien break; 213890087Sobrien else if (GET_CODE (note) == NOTE && NOTE_LINE_NUMBER (note) > 0) 213990087Sobrien { 214090087Sobrien /* Another line note follows; we can delete this note 214190087Sobrien if no intervening line numbers have notes elsewhere. */ 214290087Sobrien int num; 214390087Sobrien for (num = NOTE_LINE_NUMBER (insn) + 1; 214490087Sobrien num < NOTE_LINE_NUMBER (note); 214590087Sobrien num++) 214690087Sobrien if (line_note_exists[num]) 214790087Sobrien break; 214890087Sobrien 214990087Sobrien if (num >= NOTE_LINE_NUMBER (note)) 215090087Sobrien note_after = 1; 215190087Sobrien break; 215290087Sobrien } 215390087Sobrien } 215490087Sobrien 215590087Sobrien /* Output this line note if it is the first or the last line 215690087Sobrien note in a row. */ 215790087Sobrien if (!note_after) 215890087Sobrien { 215990087Sobrien notice_source_line (insn); 216090087Sobrien (*debug_hooks->source_line) (last_linenum, last_filename); 216190087Sobrien } 216290087Sobrien } 216390087Sobrien break; 216418334Speter } 216518334Speter break; 216618334Speter 216718334Speter case BARRIER: 216890087Sobrien#if defined (DWARF2_UNWIND_INFO) 216990087Sobrien if (dwarf2out_do_frame ()) 217090087Sobrien dwarf2out_frame_debug (insn); 217118334Speter#endif 217218334Speter break; 217318334Speter 217418334Speter case CODE_LABEL: 217550503Sobrien /* The target port might emit labels in the output function for 217650503Sobrien some insn, e.g. sh.c output_branchy_insn. */ 217750503Sobrien if (CODE_LABEL_NUMBER (insn) <= max_labelno) 217850503Sobrien { 217950503Sobrien int align = LABEL_TO_ALIGNMENT (insn); 218050503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN 218150503Sobrien int max_skip = LABEL_TO_MAX_SKIP (insn); 218250503Sobrien#endif 218350503Sobrien 218450503Sobrien if (align && NEXT_INSN (insn)) 218590087Sobrien { 218650503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN 218790087Sobrien ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip); 218850503Sobrien#else 2189117404Skan#ifdef ASM_OUTPUT_ALIGN_WITH_NOP 2190117404Skan ASM_OUTPUT_ALIGN_WITH_NOP (file, align); 2191117404Skan#else 219290087Sobrien ASM_OUTPUT_ALIGN (file, align); 219350503Sobrien#endif 2194117404Skan#endif 219590087Sobrien } 219650503Sobrien } 219752515Sobrien#ifdef HAVE_cc0 219818334Speter CC_STATUS_INIT; 219952515Sobrien /* If this label is reached from only one place, set the condition 220052515Sobrien codes from the instruction just before the branch. */ 220152515Sobrien 220252515Sobrien /* Disabled because some insns set cc_status in the C output code 220352515Sobrien and NOTICE_UPDATE_CC alone can set incorrect status. */ 220452515Sobrien if (0 /* optimize && LABEL_NUSES (insn) == 1*/) 220552515Sobrien { 220652515Sobrien rtx jump = LABEL_REFS (insn); 220752515Sobrien rtx barrier = prev_nonnote_insn (insn); 220852515Sobrien rtx prev; 220952515Sobrien /* If the LABEL_REFS field of this label has been set to point 221052515Sobrien at a branch, the predecessor of the branch is a regular 221152515Sobrien insn, and that branch is the only way to reach this label, 221252515Sobrien set the condition codes based on the branch and its 221352515Sobrien predecessor. */ 221452515Sobrien if (barrier && GET_CODE (barrier) == BARRIER 221552515Sobrien && jump && GET_CODE (jump) == JUMP_INSN 221652515Sobrien && (prev = prev_nonnote_insn (jump)) 221752515Sobrien && GET_CODE (prev) == INSN) 221852515Sobrien { 221952515Sobrien NOTICE_UPDATE_CC (PATTERN (prev), prev); 222052515Sobrien NOTICE_UPDATE_CC (PATTERN (jump), jump); 222152515Sobrien } 222252515Sobrien } 222352515Sobrien#endif 222418334Speter if (prescan > 0) 222518334Speter break; 222618334Speter new_block = 1; 222750503Sobrien 222850503Sobrien#ifdef FINAL_PRESCAN_LABEL 222990087Sobrien FINAL_PRESCAN_INSN (insn, NULL, 0); 223050503Sobrien#endif 223150503Sobrien 223290087Sobrien if (LABEL_NAME (insn)) 223390087Sobrien (*debug_hooks->label) (insn); 223490087Sobrien 223518334Speter if (app_on) 223618334Speter { 223750503Sobrien fputs (ASM_APP_OFF, file); 223818334Speter app_on = 0; 223918334Speter } 224018334Speter if (NEXT_INSN (insn) != 0 224118334Speter && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN) 224218334Speter { 224318334Speter rtx nextbody = PATTERN (NEXT_INSN (insn)); 224418334Speter 224518334Speter /* If this label is followed by a jump-table, 224618334Speter make sure we put the label in the read-only section. Also 224718334Speter possibly write the label and jump table together. */ 224818334Speter 224918334Speter if (GET_CODE (nextbody) == ADDR_VEC 225018334Speter || GET_CODE (nextbody) == ADDR_DIFF_VEC) 225118334Speter { 225252515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC) 225352515Sobrien /* In this case, the case vector is being moved by the 225452515Sobrien target, so don't output the label at all. Leave that 225552515Sobrien to the back end macros. */ 225652515Sobrien#else 225750503Sobrien if (! JUMP_TABLES_IN_TEXT_SECTION) 225850503Sobrien { 225990087Sobrien int log_align; 226090087Sobrien 226150503Sobrien readonly_data_section (); 226290087Sobrien 226390087Sobrien#ifdef ADDR_VEC_ALIGN 226490087Sobrien log_align = ADDR_VEC_ALIGN (NEXT_INSN (insn)); 226590087Sobrien#else 226690087Sobrien log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT); 226790087Sobrien#endif 226890087Sobrien ASM_OUTPUT_ALIGN (file, log_align); 226950503Sobrien } 227050503Sobrien else 227150503Sobrien function_section (current_function_decl); 227250503Sobrien 227318334Speter#ifdef ASM_OUTPUT_CASE_LABEL 227418334Speter ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), 227518334Speter NEXT_INSN (insn)); 227618334Speter#else 2277117404Skan ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); 227818334Speter#endif 227952515Sobrien#endif 228018334Speter break; 228118334Speter } 228218334Speter } 2283117404Skan if (LABEL_ALT_ENTRY_P (insn)) 2284117404Skan output_alternate_entry_point (file, insn); 228590087Sobrien else 228690087Sobrien ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); 228718334Speter break; 228818334Speter 228918334Speter default: 229018334Speter { 229190087Sobrien rtx body = PATTERN (insn); 229218334Speter int insn_code_number; 229352515Sobrien const char *template; 229418334Speter rtx note; 229518334Speter 229618334Speter /* An INSN, JUMP_INSN or CALL_INSN. 229718334Speter First check for special kinds that recog doesn't recognize. */ 229818334Speter 229918334Speter if (GET_CODE (body) == USE /* These are just declarations */ 230018334Speter || GET_CODE (body) == CLOBBER) 230118334Speter break; 230218334Speter 230318334Speter#ifdef HAVE_cc0 230418334Speter /* If there is a REG_CC_SETTER note on this insn, it means that 230518334Speter the setting of the condition code was done in the delay slot 230618334Speter of the insn that branched here. So recover the cc status 230718334Speter from the insn that set it. */ 230818334Speter 230918334Speter note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX); 231018334Speter if (note) 231118334Speter { 231218334Speter NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0)); 231318334Speter cc_prev_status = cc_status; 231418334Speter } 231518334Speter#endif 231618334Speter 231718334Speter /* Detect insns that are really jump-tables 231818334Speter and output them as such. */ 231918334Speter 232018334Speter if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) 232118334Speter { 232252515Sobrien#if !(defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)) 232390087Sobrien int vlen, idx; 232452515Sobrien#endif 232518334Speter 232618334Speter if (prescan > 0) 232718334Speter break; 232818334Speter 232918334Speter if (app_on) 233018334Speter { 233150503Sobrien fputs (ASM_APP_OFF, file); 233218334Speter app_on = 0; 233318334Speter } 233418334Speter 233552515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC) 233652515Sobrien if (GET_CODE (body) == ADDR_VEC) 233752515Sobrien { 233852515Sobrien#ifdef ASM_OUTPUT_ADDR_VEC 233952515Sobrien ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body); 234052515Sobrien#else 234190087Sobrien abort (); 234252515Sobrien#endif 234352515Sobrien } 234452515Sobrien else 234552515Sobrien { 234652515Sobrien#ifdef ASM_OUTPUT_ADDR_DIFF_VEC 234752515Sobrien ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body); 234852515Sobrien#else 234990087Sobrien abort (); 235052515Sobrien#endif 235152515Sobrien } 235252515Sobrien#else 235318334Speter vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC); 235418334Speter for (idx = 0; idx < vlen; idx++) 235518334Speter { 235618334Speter if (GET_CODE (body) == ADDR_VEC) 235718334Speter { 235818334Speter#ifdef ASM_OUTPUT_ADDR_VEC_ELT 235918334Speter ASM_OUTPUT_ADDR_VEC_ELT 236018334Speter (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0))); 236118334Speter#else 236218334Speter abort (); 236318334Speter#endif 236418334Speter } 236518334Speter else 236618334Speter { 236718334Speter#ifdef ASM_OUTPUT_ADDR_DIFF_ELT 236818334Speter ASM_OUTPUT_ADDR_DIFF_ELT 236918334Speter (file, 237050503Sobrien body, 237118334Speter CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)), 237218334Speter CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0))); 237318334Speter#else 237418334Speter abort (); 237518334Speter#endif 237618334Speter } 237718334Speter } 237818334Speter#ifdef ASM_OUTPUT_CASE_END 237918334Speter ASM_OUTPUT_CASE_END (file, 238018334Speter CODE_LABEL_NUMBER (PREV_INSN (insn)), 238118334Speter insn); 238218334Speter#endif 238352515Sobrien#endif 238418334Speter 238518334Speter function_section (current_function_decl); 238618334Speter 238718334Speter break; 238818334Speter } 238918334Speter 239018334Speter if (GET_CODE (body) == ASM_INPUT) 239118334Speter { 239290087Sobrien const char *string = XSTR (body, 0); 239390087Sobrien 239418334Speter /* There's no telling what that did to the condition codes. */ 239518334Speter CC_STATUS_INIT; 239618334Speter if (prescan > 0) 239718334Speter break; 239890087Sobrien 239990087Sobrien if (string[0]) 240018334Speter { 240190087Sobrien if (! app_on) 240290087Sobrien { 240390087Sobrien fputs (ASM_APP_ON, file); 240490087Sobrien app_on = 1; 240590087Sobrien } 240690087Sobrien fprintf (asm_out_file, "\t%s\n", string); 240718334Speter } 240818334Speter break; 240918334Speter } 241018334Speter 241118334Speter /* Detect `asm' construct with operands. */ 241218334Speter if (asm_noperands (body) >= 0) 241318334Speter { 241450503Sobrien unsigned int noperands = asm_noperands (body); 241518334Speter rtx *ops = (rtx *) alloca (noperands * sizeof (rtx)); 241690087Sobrien const char *string; 241718334Speter 241818334Speter /* There's no telling what that did to the condition codes. */ 241918334Speter CC_STATUS_INIT; 242018334Speter if (prescan > 0) 242118334Speter break; 242218334Speter 242318334Speter /* Get out the operand values. */ 242490087Sobrien string = decode_asm_operands (body, ops, NULL, NULL, NULL); 242518334Speter /* Inhibit aborts on what would otherwise be compiler bugs. */ 242618334Speter insn_noperands = noperands; 242718334Speter this_is_asm_operands = insn; 242818334Speter 242918334Speter /* Output the insn using them. */ 243090087Sobrien if (string[0]) 243190087Sobrien { 243290087Sobrien if (! app_on) 243390087Sobrien { 243490087Sobrien fputs (ASM_APP_ON, file); 243590087Sobrien app_on = 1; 243690087Sobrien } 243790087Sobrien output_asm_insn (string, ops); 243890087Sobrien } 243990087Sobrien 244018334Speter this_is_asm_operands = 0; 244118334Speter break; 244218334Speter } 244318334Speter 244418334Speter if (prescan <= 0 && app_on) 244518334Speter { 244650503Sobrien fputs (ASM_APP_OFF, file); 244718334Speter app_on = 0; 244818334Speter } 244918334Speter 245018334Speter if (GET_CODE (body) == SEQUENCE) 245118334Speter { 245218334Speter /* A delayed-branch sequence */ 245390087Sobrien int i; 245418334Speter rtx next; 245518334Speter 245618334Speter if (prescan > 0) 245718334Speter break; 245818334Speter final_sequence = body; 245918334Speter 246018334Speter /* The first insn in this SEQUENCE might be a JUMP_INSN that will 246118334Speter force the restoration of a comparison that was previously 246218334Speter thought unnecessary. If that happens, cancel this sequence 246318334Speter and cause that insn to be restored. */ 246418334Speter 246518334Speter next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1); 246618334Speter if (next != XVECEXP (body, 0, 1)) 246718334Speter { 246818334Speter final_sequence = 0; 246918334Speter return next; 247018334Speter } 247118334Speter 247218334Speter for (i = 1; i < XVECLEN (body, 0); i++) 247318334Speter { 247418334Speter rtx insn = XVECEXP (body, 0, i); 247518334Speter rtx next = NEXT_INSN (insn); 247618334Speter /* We loop in case any instruction in a delay slot gets 247718334Speter split. */ 247818334Speter do 247918334Speter insn = final_scan_insn (insn, file, 0, prescan, 1); 248018334Speter while (insn != next); 248118334Speter } 248218334Speter#ifdef DBR_OUTPUT_SEQEND 248318334Speter DBR_OUTPUT_SEQEND (file); 248418334Speter#endif 248518334Speter final_sequence = 0; 248618334Speter 248718334Speter /* If the insn requiring the delay slot was a CALL_INSN, the 248818334Speter insns in the delay slot are actually executed before the 248918334Speter called function. Hence we don't preserve any CC-setting 249018334Speter actions in these insns and the CC must be marked as being 249118334Speter clobbered by the function. */ 249218334Speter if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN) 249350503Sobrien { 249450503Sobrien CC_STATUS_INIT; 249550503Sobrien } 249618334Speter break; 249718334Speter } 249818334Speter 249918334Speter /* We have a real machine instruction as rtl. */ 250018334Speter 250118334Speter body = PATTERN (insn); 250218334Speter 250318334Speter#ifdef HAVE_cc0 250490087Sobrien set = single_set (insn); 250550503Sobrien 250618334Speter /* Check for redundant test and compare instructions 250718334Speter (when the condition codes are already set up as desired). 250818334Speter This is done only when optimizing; if not optimizing, 250918334Speter it should be possible for the user to alter a variable 251018334Speter with the debugger in between statements 251118334Speter and the next statement should reexamine the variable 251218334Speter to compute the condition codes. */ 251318334Speter 251450503Sobrien if (optimize) 251518334Speter { 251650503Sobrien#if 0 251790087Sobrien rtx set = single_set (insn); 251850503Sobrien#endif 251950503Sobrien 252050503Sobrien if (set 252150503Sobrien && GET_CODE (SET_DEST (set)) == CC0 252250503Sobrien && insn != last_ignored_compare) 252318334Speter { 252450503Sobrien if (GET_CODE (SET_SRC (set)) == SUBREG) 252590087Sobrien SET_SRC (set) = alter_subreg (&SET_SRC (set)); 252650503Sobrien else if (GET_CODE (SET_SRC (set)) == COMPARE) 252718334Speter { 252850503Sobrien if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG) 252950503Sobrien XEXP (SET_SRC (set), 0) 253090087Sobrien = alter_subreg (&XEXP (SET_SRC (set), 0)); 253150503Sobrien if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG) 253250503Sobrien XEXP (SET_SRC (set), 1) 253390087Sobrien = alter_subreg (&XEXP (SET_SRC (set), 1)); 253418334Speter } 253550503Sobrien if ((cc_status.value1 != 0 253650503Sobrien && rtx_equal_p (SET_SRC (set), cc_status.value1)) 253750503Sobrien || (cc_status.value2 != 0 253850503Sobrien && rtx_equal_p (SET_SRC (set), cc_status.value2))) 253950503Sobrien { 254050503Sobrien /* Don't delete insn if it has an addressing side-effect. */ 254190087Sobrien if (! FIND_REG_INC_NOTE (insn, NULL_RTX) 254250503Sobrien /* or if anything in it is volatile. */ 254350503Sobrien && ! volatile_refs_p (PATTERN (insn))) 254450503Sobrien { 254550503Sobrien /* We don't really delete the insn; just ignore it. */ 254650503Sobrien last_ignored_compare = insn; 254750503Sobrien break; 254850503Sobrien } 254950503Sobrien } 255018334Speter } 255118334Speter } 255218334Speter#endif 255318334Speter 255418334Speter#ifndef STACK_REGS 255518334Speter /* Don't bother outputting obvious no-ops, even without -O. 255618334Speter This optimization is fast and doesn't interfere with debugging. 255718334Speter Don't do this if the insn is in a delay slot, since this 255818334Speter will cause an improper number of delay insns to be written. */ 255918334Speter if (final_sequence == 0 256018334Speter && prescan >= 0 256118334Speter && GET_CODE (insn) == INSN && GET_CODE (body) == SET 256218334Speter && GET_CODE (SET_SRC (body)) == REG 256318334Speter && GET_CODE (SET_DEST (body)) == REG 256418334Speter && REGNO (SET_SRC (body)) == REGNO (SET_DEST (body))) 256518334Speter break; 256618334Speter#endif 256718334Speter 256818334Speter#ifdef HAVE_cc0 256918334Speter /* If this is a conditional branch, maybe modify it 257018334Speter if the cc's are in a nonstandard state 257118334Speter so that it accomplishes the same thing that it would 257218334Speter do straightforwardly if the cc's were set up normally. */ 257318334Speter 257418334Speter if (cc_status.flags != 0 257518334Speter && GET_CODE (insn) == JUMP_INSN 257618334Speter && GET_CODE (body) == SET 257718334Speter && SET_DEST (body) == pc_rtx 257818334Speter && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE 257918334Speter && GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (body), 0))) == '<' 258018334Speter && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx 258118334Speter /* This is done during prescan; it is not done again 258218334Speter in final scan when prescan has been done. */ 258318334Speter && prescan >= 0) 258418334Speter { 258518334Speter /* This function may alter the contents of its argument 258618334Speter and clear some of the cc_status.flags bits. 258718334Speter It may also return 1 meaning condition now always true 258818334Speter or -1 meaning condition now always false 258918334Speter or 2 meaning condition nontrivial but altered. */ 259090087Sobrien int result = alter_cond (XEXP (SET_SRC (body), 0)); 259118334Speter /* If condition now has fixed value, replace the IF_THEN_ELSE 259218334Speter with its then-operand or its else-operand. */ 259318334Speter if (result == 1) 259418334Speter SET_SRC (body) = XEXP (SET_SRC (body), 1); 259518334Speter if (result == -1) 259618334Speter SET_SRC (body) = XEXP (SET_SRC (body), 2); 259718334Speter 259818334Speter /* The jump is now either unconditional or a no-op. 259918334Speter If it has become a no-op, don't try to output it. 260018334Speter (It would not be recognized.) */ 260118334Speter if (SET_SRC (body) == pc_rtx) 260218334Speter { 260390087Sobrien delete_insn (insn); 260418334Speter break; 260518334Speter } 260618334Speter else if (GET_CODE (SET_SRC (body)) == RETURN) 260718334Speter /* Replace (set (pc) (return)) with (return). */ 260818334Speter PATTERN (insn) = body = SET_SRC (body); 260918334Speter 261018334Speter /* Rerecognize the instruction if it has changed. */ 261118334Speter if (result != 0) 261218334Speter INSN_CODE (insn) = -1; 261318334Speter } 261418334Speter 261518334Speter /* Make same adjustments to instructions that examine the 261650503Sobrien condition codes without jumping and instructions that 261750503Sobrien handle conditional moves (if this machine has either one). */ 261818334Speter 261918334Speter if (cc_status.flags != 0 262050503Sobrien && set != 0) 262118334Speter { 262250503Sobrien rtx cond_rtx, then_rtx, else_rtx; 262390087Sobrien 262450503Sobrien if (GET_CODE (insn) != JUMP_INSN 262550503Sobrien && GET_CODE (SET_SRC (set)) == IF_THEN_ELSE) 262618334Speter { 262750503Sobrien cond_rtx = XEXP (SET_SRC (set), 0); 262850503Sobrien then_rtx = XEXP (SET_SRC (set), 1); 262950503Sobrien else_rtx = XEXP (SET_SRC (set), 2); 263050503Sobrien } 263150503Sobrien else 263250503Sobrien { 263350503Sobrien cond_rtx = SET_SRC (set); 263450503Sobrien then_rtx = const_true_rtx; 263550503Sobrien else_rtx = const0_rtx; 263650503Sobrien } 263790087Sobrien 263850503Sobrien switch (GET_CODE (cond_rtx)) 263950503Sobrien { 264018334Speter case GTU: 264118334Speter case GT: 264218334Speter case LTU: 264318334Speter case LT: 264418334Speter case GEU: 264518334Speter case GE: 264618334Speter case LEU: 264718334Speter case LE: 264818334Speter case EQ: 264918334Speter case NE: 265018334Speter { 265190087Sobrien int result; 265250503Sobrien if (XEXP (cond_rtx, 0) != cc0_rtx) 265318334Speter break; 265450503Sobrien result = alter_cond (cond_rtx); 265518334Speter if (result == 1) 265650503Sobrien validate_change (insn, &SET_SRC (set), then_rtx, 0); 265718334Speter else if (result == -1) 265850503Sobrien validate_change (insn, &SET_SRC (set), else_rtx, 0); 265918334Speter else if (result == 2) 266018334Speter INSN_CODE (insn) = -1; 266150503Sobrien if (SET_DEST (set) == SET_SRC (set)) 266290087Sobrien delete_insn (insn); 266318334Speter } 266450503Sobrien break; 266550503Sobrien 266650503Sobrien default: 266750503Sobrien break; 266818334Speter } 266918334Speter } 267050503Sobrien 267118334Speter#endif 267218334Speter 267390087Sobrien#ifdef HAVE_peephole 267418334Speter /* Do machine-specific peephole optimizations if desired. */ 267518334Speter 267618334Speter if (optimize && !flag_no_peephole && !nopeepholes) 267718334Speter { 267818334Speter rtx next = peephole (insn); 267918334Speter /* When peepholing, if there were notes within the peephole, 268018334Speter emit them before the peephole. */ 268118334Speter if (next != 0 && next != NEXT_INSN (insn)) 268218334Speter { 268318334Speter rtx prev = PREV_INSN (insn); 268418334Speter 268518334Speter for (note = NEXT_INSN (insn); note != next; 268618334Speter note = NEXT_INSN (note)) 268718334Speter final_scan_insn (note, file, optimize, prescan, nopeepholes); 268818334Speter 268918334Speter /* In case this is prescan, put the notes 269018334Speter in proper position for later rescan. */ 269118334Speter note = NEXT_INSN (insn); 269218334Speter PREV_INSN (note) = prev; 269318334Speter NEXT_INSN (prev) = note; 269418334Speter NEXT_INSN (PREV_INSN (next)) = insn; 269518334Speter PREV_INSN (insn) = PREV_INSN (next); 269618334Speter NEXT_INSN (insn) = next; 269718334Speter PREV_INSN (next) = insn; 269818334Speter } 269918334Speter 270018334Speter /* PEEPHOLE might have changed this. */ 270118334Speter body = PATTERN (insn); 270218334Speter } 270390087Sobrien#endif 270418334Speter 270518334Speter /* Try to recognize the instruction. 270618334Speter If successful, verify that the operands satisfy the 270718334Speter constraints for the instruction. Crash if they don't, 270818334Speter since `reload' should have changed them so that they do. */ 270918334Speter 271018334Speter insn_code_number = recog_memoized (insn); 271152515Sobrien cleanup_subreg_operands (insn); 271218334Speter 2713117404Skan /* Dump the insn in the assembly for debugging. */ 2714117404Skan if (flag_dump_rtl_in_asm) 2715117404Skan { 2716117404Skan print_rtx_head = ASM_COMMENT_START; 2717117404Skan print_rtl_single (asm_out_file, insn); 2718117404Skan print_rtx_head = ""; 2719117404Skan } 272090087Sobrien 272190087Sobrien if (! constrain_operands_cached (1)) 272218334Speter fatal_insn_not_found (insn); 272318334Speter 272418334Speter /* Some target machines need to prescan each insn before 272518334Speter it is output. */ 272618334Speter 272718334Speter#ifdef FINAL_PRESCAN_INSN 272890087Sobrien FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands); 272918334Speter#endif 273018334Speter 273190087Sobrien#ifdef HAVE_conditional_execution 273290087Sobrien if (GET_CODE (PATTERN (insn)) == COND_EXEC) 273390087Sobrien current_insn_predicate = COND_EXEC_TEST (PATTERN (insn)); 273490087Sobrien else 273590087Sobrien current_insn_predicate = NULL_RTX; 273690087Sobrien#endif 273790087Sobrien 273818334Speter#ifdef HAVE_cc0 273918334Speter cc_prev_status = cc_status; 274018334Speter 274118334Speter /* Update `cc_status' for this instruction. 274218334Speter The instruction's output routine may change it further. 274318334Speter If the output routine for a jump insn needs to depend 274418334Speter on the cc status, it should look at cc_prev_status. */ 274518334Speter 274618334Speter NOTICE_UPDATE_CC (body, insn); 274718334Speter#endif 274818334Speter 274990087Sobrien current_output_insn = debug_insn = insn; 275018334Speter 275190087Sobrien#if defined (DWARF2_UNWIND_INFO) 275250503Sobrien if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ()) 275350503Sobrien dwarf2out_frame_debug (insn); 275450503Sobrien#endif 275550503Sobrien 275690087Sobrien /* Find the proper template for this insn. */ 275790087Sobrien template = get_insn_template (insn_code_number, insn); 275818334Speter 275990087Sobrien /* If the C code returns 0, it means that it is a jump insn 276090087Sobrien which follows a deleted test insn, and that test insn 276190087Sobrien needs to be reinserted. */ 276218334Speter if (template == 0) 276318334Speter { 276490087Sobrien rtx prev; 276518334Speter 276690087Sobrien if (prev_nonnote_insn (insn) != last_ignored_compare) 276790087Sobrien abort (); 276890087Sobrien new_block = 0; 276990087Sobrien 277090087Sobrien /* We have already processed the notes between the setter and 277190087Sobrien the user. Make sure we don't process them again, this is 277290087Sobrien particularly important if one of the notes is a block 277390087Sobrien scope note or an EH note. */ 277490087Sobrien for (prev = insn; 277590087Sobrien prev != last_ignored_compare; 277690087Sobrien prev = PREV_INSN (prev)) 277718334Speter { 277890087Sobrien if (GET_CODE (prev) == NOTE) 277990087Sobrien delete_insn (prev); /* Use delete_note. */ 278018334Speter } 278190087Sobrien 278290087Sobrien return prev; 278318334Speter } 278418334Speter 278518334Speter /* If the template is the string "#", it means that this insn must 278618334Speter be split. */ 278718334Speter if (template[0] == '#' && template[1] == '\0') 278818334Speter { 278918334Speter rtx new = try_split (body, insn, 0); 279018334Speter 279118334Speter /* If we didn't split the insn, go away. */ 279218334Speter if (new == insn && PATTERN (new) == body) 279390087Sobrien fatal_insn ("could not split insn", insn); 279490087Sobrien 279550503Sobrien#ifdef HAVE_ATTR_length 279650503Sobrien /* This instruction should have been split in shorten_branches, 279750503Sobrien to ensure that we would have valid length info for the 279850503Sobrien splitees. */ 279950503Sobrien abort (); 280050503Sobrien#endif 280150503Sobrien 280218334Speter new_block = 0; 280318334Speter return new; 280418334Speter } 280590087Sobrien 280618334Speter if (prescan > 0) 280718334Speter break; 280818334Speter 280990087Sobrien#ifdef IA64_UNWIND_INFO 281090087Sobrien IA64_UNWIND_EMIT (asm_out_file, insn); 281190087Sobrien#endif 281218334Speter /* Output assembler code from the template. */ 281318334Speter 281490087Sobrien output_asm_insn (template, recog_data.operand); 281518334Speter 281650503Sobrien#if defined (DWARF2_UNWIND_INFO) 281790087Sobrien#if defined (HAVE_prologue) 281850503Sobrien if (GET_CODE (insn) == INSN && dwarf2out_do_frame ()) 281950503Sobrien dwarf2out_frame_debug (insn); 282050503Sobrien#else 282190087Sobrien if (!ACCUMULATE_OUTGOING_ARGS 282290087Sobrien && GET_CODE (insn) == INSN 282390087Sobrien && dwarf2out_do_frame ()) 282450503Sobrien dwarf2out_frame_debug (insn); 282550503Sobrien#endif 282650503Sobrien#endif 282750503Sobrien 282818334Speter#if 0 282918334Speter /* It's not at all clear why we did this and doing so interferes 283018334Speter with tests we'd like to do to use REG_WAS_0 notes, so let's try 283118334Speter with this out. */ 283218334Speter 283318334Speter /* Mark this insn as having been output. */ 283418334Speter INSN_DELETED_P (insn) = 1; 283518334Speter#endif 283618334Speter 283790087Sobrien /* Emit information for vtable gc. */ 283890087Sobrien note = find_reg_note (insn, REG_VTABLE_REF, NULL_RTX); 283990087Sobrien if (note) 284090087Sobrien assemble_vtable_entry (XEXP (XEXP (note, 0), 0), 284190087Sobrien INTVAL (XEXP (XEXP (note, 0), 1))); 284290087Sobrien 284390087Sobrien current_output_insn = debug_insn = 0; 284418334Speter } 284518334Speter } 284618334Speter return NEXT_INSN (insn); 284718334Speter} 284818334Speter 284918334Speter/* Output debugging info to the assembler file FILE 285018334Speter based on the NOTE-insn INSN, assumed to be a line number. */ 285118334Speter 285218334Speterstatic void 285390087Sobriennotice_source_line (insn) 285418334Speter rtx insn; 285518334Speter{ 285690087Sobrien const char *filename = NOTE_SOURCE_FILE (insn); 285718334Speter 285818334Speter last_filename = filename; 285918334Speter last_linenum = NOTE_LINE_NUMBER (insn); 286018334Speter high_block_linenum = MAX (last_linenum, high_block_linenum); 286118334Speter high_function_linenum = MAX (last_linenum, high_function_linenum); 286218334Speter} 286318334Speter 286452515Sobrien/* For each operand in INSN, simplify (subreg (reg)) so that it refers 286552515Sobrien directly to the desired hard register. */ 286690087Sobrien 286752515Sobrienvoid 286852515Sobriencleanup_subreg_operands (insn) 286952515Sobrien rtx insn; 287052515Sobrien{ 287152515Sobrien int i; 287290087Sobrien extract_insn_cached (insn); 287390087Sobrien for (i = 0; i < recog_data.n_operands; i++) 287452515Sobrien { 287590087Sobrien /* The following test cannot use recog_data.operand when tesing 287690087Sobrien for a SUBREG: the underlying object might have been changed 287790087Sobrien already if we are inside a match_operator expression that 287890087Sobrien matches the else clause. Instead we test the underlying 287990087Sobrien expression directly. */ 288090087Sobrien if (GET_CODE (*recog_data.operand_loc[i]) == SUBREG) 288190087Sobrien recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]); 288290087Sobrien else if (GET_CODE (recog_data.operand[i]) == PLUS 288390087Sobrien || GET_CODE (recog_data.operand[i]) == MULT 288490087Sobrien || GET_CODE (recog_data.operand[i]) == MEM) 288590087Sobrien recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i]); 288652515Sobrien } 288752515Sobrien 288890087Sobrien for (i = 0; i < recog_data.n_dups; i++) 288952515Sobrien { 289090087Sobrien if (GET_CODE (*recog_data.dup_loc[i]) == SUBREG) 289190087Sobrien *recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]); 289290087Sobrien else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS 289390087Sobrien || GET_CODE (*recog_data.dup_loc[i]) == MULT 289490087Sobrien || GET_CODE (*recog_data.dup_loc[i]) == MEM) 289590087Sobrien *recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]); 289652515Sobrien } 289752515Sobrien} 289852515Sobrien 289918334Speter/* If X is a SUBREG, replace it with a REG or a MEM, 290018334Speter based on the thing it is a subreg of. */ 290118334Speter 290218334Speterrtx 290390087Sobrienalter_subreg (xp) 290490087Sobrien rtx *xp; 290518334Speter{ 290690087Sobrien rtx x = *xp; 290790087Sobrien rtx y = SUBREG_REG (x); 290850503Sobrien 290990087Sobrien /* simplify_subreg does not remove subreg from volatile references. 291090087Sobrien We are required to. */ 291190087Sobrien if (GET_CODE (y) == MEM) 291290087Sobrien *xp = adjust_address (y, GET_MODE (x), SUBREG_BYTE (x)); 291390087Sobrien else 291418334Speter { 291590087Sobrien rtx new = simplify_subreg (GET_MODE (x), y, GET_MODE (y), 291690087Sobrien SUBREG_BYTE (x)); 291750503Sobrien 291890087Sobrien if (new != 0) 291990087Sobrien *xp = new; 292090087Sobrien /* Simplify_subreg can't handle some REG cases, but we have to. */ 292190087Sobrien else if (GET_CODE (y) == REG) 292290087Sobrien { 292390087Sobrien unsigned int regno = subreg_hard_regno (x, 1); 292490087Sobrien PUT_CODE (x, REG); 292590087Sobrien REGNO (x) = regno; 292690087Sobrien ORIGINAL_REGNO (x) = ORIGINAL_REGNO (y); 292790087Sobrien /* This field has a different meaning for REGs and SUBREGs. Make 292890087Sobrien sure to clear it! */ 2929117404Skan RTX_FLAG (x, used) = 0; 293090087Sobrien } 293190087Sobrien else 293290087Sobrien abort (); 293318334Speter } 293418334Speter 293590087Sobrien return *xp; 293618334Speter} 293718334Speter 293818334Speter/* Do alter_subreg on all the SUBREGs contained in X. */ 293918334Speter 294018334Speterstatic rtx 294190087Sobrienwalk_alter_subreg (xp) 294290087Sobrien rtx *xp; 294318334Speter{ 294490087Sobrien rtx x = *xp; 294518334Speter switch (GET_CODE (x)) 294618334Speter { 294718334Speter case PLUS: 294818334Speter case MULT: 294990087Sobrien XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0)); 295090087Sobrien XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1)); 295118334Speter break; 295218334Speter 295318334Speter case MEM: 295490087Sobrien XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0)); 295518334Speter break; 295618334Speter 295718334Speter case SUBREG: 295890087Sobrien return alter_subreg (xp); 295990087Sobrien 296050503Sobrien default: 296150503Sobrien break; 296218334Speter } 296318334Speter 296490087Sobrien return *xp; 296518334Speter} 296618334Speter 296718334Speter#ifdef HAVE_cc0 296818334Speter 296918334Speter/* Given BODY, the body of a jump instruction, alter the jump condition 297018334Speter as required by the bits that are set in cc_status.flags. 297118334Speter Not all of the bits there can be handled at this level in all cases. 297218334Speter 297318334Speter The value is normally 0. 297418334Speter 1 means that the condition has become always true. 297518334Speter -1 means that the condition has become always false. 297618334Speter 2 means that COND has been altered. */ 297718334Speter 297818334Speterstatic int 297918334Speteralter_cond (cond) 298090087Sobrien rtx cond; 298118334Speter{ 298218334Speter int value = 0; 298318334Speter 298418334Speter if (cc_status.flags & CC_REVERSED) 298518334Speter { 298618334Speter value = 2; 298718334Speter PUT_CODE (cond, swap_condition (GET_CODE (cond))); 298818334Speter } 298918334Speter 299018334Speter if (cc_status.flags & CC_INVERTED) 299118334Speter { 299218334Speter value = 2; 299318334Speter PUT_CODE (cond, reverse_condition (GET_CODE (cond))); 299418334Speter } 299518334Speter 299618334Speter if (cc_status.flags & CC_NOT_POSITIVE) 299718334Speter switch (GET_CODE (cond)) 299818334Speter { 299918334Speter case LE: 300018334Speter case LEU: 300118334Speter case GEU: 300218334Speter /* Jump becomes unconditional. */ 300318334Speter return 1; 300418334Speter 300518334Speter case GT: 300618334Speter case GTU: 300718334Speter case LTU: 300818334Speter /* Jump becomes no-op. */ 300918334Speter return -1; 301018334Speter 301118334Speter case GE: 301218334Speter PUT_CODE (cond, EQ); 301318334Speter value = 2; 301418334Speter break; 301518334Speter 301618334Speter case LT: 301718334Speter PUT_CODE (cond, NE); 301818334Speter value = 2; 301918334Speter break; 302090087Sobrien 302150503Sobrien default: 302250503Sobrien break; 302318334Speter } 302418334Speter 302518334Speter if (cc_status.flags & CC_NOT_NEGATIVE) 302618334Speter switch (GET_CODE (cond)) 302718334Speter { 302818334Speter case GE: 302918334Speter case GEU: 303018334Speter /* Jump becomes unconditional. */ 303118334Speter return 1; 303218334Speter 303318334Speter case LT: 303418334Speter case LTU: 303518334Speter /* Jump becomes no-op. */ 303618334Speter return -1; 303718334Speter 303818334Speter case LE: 303918334Speter case LEU: 304018334Speter PUT_CODE (cond, EQ); 304118334Speter value = 2; 304218334Speter break; 304318334Speter 304418334Speter case GT: 304518334Speter case GTU: 304618334Speter PUT_CODE (cond, NE); 304718334Speter value = 2; 304818334Speter break; 304990087Sobrien 305050503Sobrien default: 305150503Sobrien break; 305218334Speter } 305318334Speter 305418334Speter if (cc_status.flags & CC_NO_OVERFLOW) 305518334Speter switch (GET_CODE (cond)) 305618334Speter { 305718334Speter case GEU: 305818334Speter /* Jump becomes unconditional. */ 305918334Speter return 1; 306018334Speter 306118334Speter case LEU: 306218334Speter PUT_CODE (cond, EQ); 306318334Speter value = 2; 306418334Speter break; 306518334Speter 306618334Speter case GTU: 306718334Speter PUT_CODE (cond, NE); 306818334Speter value = 2; 306918334Speter break; 307018334Speter 307118334Speter case LTU: 307218334Speter /* Jump becomes no-op. */ 307318334Speter return -1; 307490087Sobrien 307550503Sobrien default: 307650503Sobrien break; 307718334Speter } 307818334Speter 307918334Speter if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N)) 308018334Speter switch (GET_CODE (cond)) 308118334Speter { 308250503Sobrien default: 308318334Speter abort (); 308418334Speter 308518334Speter case NE: 308618334Speter PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT); 308718334Speter value = 2; 308818334Speter break; 308918334Speter 309018334Speter case EQ: 309118334Speter PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE); 309218334Speter value = 2; 309318334Speter break; 309418334Speter } 309518334Speter 309618334Speter if (cc_status.flags & CC_NOT_SIGNED) 309718334Speter /* The flags are valid if signed condition operators are converted 309818334Speter to unsigned. */ 309918334Speter switch (GET_CODE (cond)) 310018334Speter { 310118334Speter case LE: 310218334Speter PUT_CODE (cond, LEU); 310318334Speter value = 2; 310418334Speter break; 310518334Speter 310618334Speter case LT: 310718334Speter PUT_CODE (cond, LTU); 310818334Speter value = 2; 310918334Speter break; 311018334Speter 311118334Speter case GT: 311218334Speter PUT_CODE (cond, GTU); 311318334Speter value = 2; 311418334Speter break; 311518334Speter 311618334Speter case GE: 311718334Speter PUT_CODE (cond, GEU); 311818334Speter value = 2; 311918334Speter break; 312050503Sobrien 312150503Sobrien default: 312250503Sobrien break; 312318334Speter } 312418334Speter 312518334Speter return value; 312618334Speter} 312718334Speter#endif 312818334Speter 312918334Speter/* Report inconsistency between the assembler template and the operands. 313018334Speter In an `asm', it's the user's fault; otherwise, the compiler's fault. */ 313118334Speter 313218334Spetervoid 313396281Sobrienoutput_operand_lossage VPARAMS ((const char *msgid, ...)) 313418334Speter{ 313596281Sobrien char *fmt_string; 313696281Sobrien char *new_message; 313796281Sobrien const char *pfx_str; 313896281Sobrien VA_OPEN (ap, msgid); 313996281Sobrien VA_FIXEDARG (ap, const char *, msgid); 314096281Sobrien 314196281Sobrien pfx_str = this_is_asm_operands ? _("invalid `asm': ") : "output_operand: "; 314296281Sobrien asprintf (&fmt_string, "%s%s", pfx_str, _(msgid)); 314396281Sobrien vasprintf (&new_message, fmt_string, ap); 3144117404Skan 314518334Speter if (this_is_asm_operands) 314696281Sobrien error_for_asm (this_is_asm_operands, "%s", new_message); 314718334Speter else 314896281Sobrien internal_error ("%s", new_message); 314996281Sobrien 315096281Sobrien free (fmt_string); 315196281Sobrien free (new_message); 315296281Sobrien VA_CLOSE (ap); 315318334Speter} 315418334Speter 315518334Speter/* Output of assembler code from a template, and its subroutines. */ 315618334Speter 315790087Sobrien/* Annotate the assembly with a comment describing the pattern and 315890087Sobrien alternative used. */ 315990087Sobrien 316090087Sobrienstatic void 316190087Sobrienoutput_asm_name () 316290087Sobrien{ 316390087Sobrien if (debug_insn) 316490087Sobrien { 316590087Sobrien int num = INSN_CODE (debug_insn); 316690087Sobrien fprintf (asm_out_file, "\t%s %d\t%s", 316790087Sobrien ASM_COMMENT_START, INSN_UID (debug_insn), 316890087Sobrien insn_data[num].name); 316990087Sobrien if (insn_data[num].n_alternatives > 1) 317090087Sobrien fprintf (asm_out_file, "/%d", which_alternative + 1); 317190087Sobrien#ifdef HAVE_ATTR_length 317290087Sobrien fprintf (asm_out_file, "\t[length = %d]", 317390087Sobrien get_attr_length (debug_insn)); 317490087Sobrien#endif 317590087Sobrien /* Clear this so only the first assembler insn 317690087Sobrien of any rtl insn will get the special comment for -dp. */ 317790087Sobrien debug_insn = 0; 317890087Sobrien } 317990087Sobrien} 318090087Sobrien 318190087Sobrien/* If OP is a REG or MEM and we can find a MEM_EXPR corresponding to it 318290087Sobrien or its address, return that expr . Set *PADDRESSP to 1 if the expr 318390087Sobrien corresponds to the address of the object and 0 if to the object. */ 318490087Sobrien 318590087Sobrienstatic tree 318690087Sobrienget_mem_expr_from_op (op, paddressp) 318790087Sobrien rtx op; 318890087Sobrien int *paddressp; 318990087Sobrien{ 319090087Sobrien tree expr; 319190087Sobrien int inner_addressp; 319290087Sobrien 319390087Sobrien *paddressp = 0; 319490087Sobrien 3195102798Skan if (op == NULL) 3196102798Skan return 0; 3197102798Skan 319890087Sobrien if (GET_CODE (op) == REG && ORIGINAL_REGNO (op) >= FIRST_PSEUDO_REGISTER) 319990087Sobrien return REGNO_DECL (ORIGINAL_REGNO (op)); 320090087Sobrien else if (GET_CODE (op) != MEM) 320190087Sobrien return 0; 320290087Sobrien 320390087Sobrien if (MEM_EXPR (op) != 0) 320490087Sobrien return MEM_EXPR (op); 320590087Sobrien 320690087Sobrien /* Otherwise we have an address, so indicate it and look at the address. */ 320790087Sobrien *paddressp = 1; 320890087Sobrien op = XEXP (op, 0); 320990087Sobrien 321090087Sobrien /* First check if we have a decl for the address, then look at the right side 321190087Sobrien if it is a PLUS. Otherwise, strip off arithmetic and keep looking. 321290087Sobrien But don't allow the address to itself be indirect. */ 321390087Sobrien if ((expr = get_mem_expr_from_op (op, &inner_addressp)) && ! inner_addressp) 321490087Sobrien return expr; 321590087Sobrien else if (GET_CODE (op) == PLUS 321690087Sobrien && (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp))) 321790087Sobrien return expr; 321890087Sobrien 321990087Sobrien while (GET_RTX_CLASS (GET_CODE (op)) == '1' 322090087Sobrien || GET_RTX_CLASS (GET_CODE (op)) == '2') 322190087Sobrien op = XEXP (op, 0); 322290087Sobrien 322390087Sobrien expr = get_mem_expr_from_op (op, &inner_addressp); 322490087Sobrien return inner_addressp ? 0 : expr; 322590087Sobrien} 322690087Sobrien 322790087Sobrien/* Output operand names for assembler instructions. OPERANDS is the 322890087Sobrien operand vector, OPORDER is the order to write the operands, and NOPS 322990087Sobrien is the number of operands to write. */ 323090087Sobrien 323190087Sobrienstatic void 323290087Sobrienoutput_asm_operand_names (operands, oporder, nops) 323390087Sobrien rtx *operands; 323490087Sobrien int *oporder; 323590087Sobrien int nops; 323690087Sobrien{ 323790087Sobrien int wrote = 0; 323890087Sobrien int i; 323990087Sobrien 324090087Sobrien for (i = 0; i < nops; i++) 324190087Sobrien { 324290087Sobrien int addressp; 324390087Sobrien tree expr = get_mem_expr_from_op (operands[oporder[i]], &addressp); 324490087Sobrien 324590087Sobrien if (expr) 324690087Sobrien { 324790087Sobrien fprintf (asm_out_file, "%c%s %s", 324890087Sobrien wrote ? ',' : '\t', wrote ? "" : ASM_COMMENT_START, 324990087Sobrien addressp ? "*" : ""); 325090087Sobrien print_mem_expr (asm_out_file, expr); 325190087Sobrien wrote = 1; 325290087Sobrien } 325390087Sobrien } 325490087Sobrien} 325590087Sobrien 325618334Speter/* Output text from TEMPLATE to the assembler output file, 325718334Speter obeying %-directions to substitute operands taken from 325818334Speter the vector OPERANDS. 325918334Speter 326018334Speter %N (for N a digit) means print operand N in usual manner. 326118334Speter %lN means require operand N to be a CODE_LABEL or LABEL_REF 326218334Speter and print the label name with no punctuation. 326318334Speter %cN means require operand N to be a constant 326418334Speter and print the constant expression with no punctuation. 326518334Speter %aN means expect operand N to be a memory address 326618334Speter (not a memory reference!) and print a reference 326718334Speter to that address. 326818334Speter %nN means expect operand N to be a constant 326918334Speter and print a constant expression for minus the value 327018334Speter of the operand, with no other punctuation. */ 327118334Speter 327218334Spetervoid 327318334Speteroutput_asm_insn (template, operands) 327452515Sobrien const char *template; 327518334Speter rtx *operands; 327618334Speter{ 327790087Sobrien const char *p; 327890087Sobrien int c; 327990087Sobrien#ifdef ASSEMBLER_DIALECT 328090087Sobrien int dialect = 0; 328190087Sobrien#endif 328290087Sobrien int oporder[MAX_RECOG_OPERANDS]; 328390087Sobrien char opoutput[MAX_RECOG_OPERANDS]; 328490087Sobrien int ops = 0; 328518334Speter 328618334Speter /* An insn may return a null string template 328718334Speter in a case where no assembler code is needed. */ 328818334Speter if (*template == 0) 328918334Speter return; 329018334Speter 329190087Sobrien memset (opoutput, 0, sizeof opoutput); 329218334Speter p = template; 329318334Speter putc ('\t', asm_out_file); 329418334Speter 329518334Speter#ifdef ASM_OUTPUT_OPCODE 329618334Speter ASM_OUTPUT_OPCODE (asm_out_file, p); 329718334Speter#endif 329818334Speter 329950503Sobrien while ((c = *p++)) 330018334Speter switch (c) 330118334Speter { 330218334Speter case '\n': 330390087Sobrien if (flag_verbose_asm) 330490087Sobrien output_asm_operand_names (operands, oporder, ops); 330590087Sobrien if (flag_print_asm_name) 330690087Sobrien output_asm_name (); 330790087Sobrien 330890087Sobrien ops = 0; 330990087Sobrien memset (opoutput, 0, sizeof opoutput); 331090087Sobrien 331118334Speter putc (c, asm_out_file); 331218334Speter#ifdef ASM_OUTPUT_OPCODE 331318334Speter while ((c = *p) == '\t') 331418334Speter { 331518334Speter putc (c, asm_out_file); 331618334Speter p++; 331718334Speter } 331818334Speter ASM_OUTPUT_OPCODE (asm_out_file, p); 331918334Speter#endif 332018334Speter break; 332118334Speter 332218334Speter#ifdef ASSEMBLER_DIALECT 332318334Speter case '{': 332450503Sobrien { 332590087Sobrien int i; 332690087Sobrien 332790087Sobrien if (dialect) 332890087Sobrien output_operand_lossage ("nested assembly dialect alternatives"); 332990087Sobrien else 333090087Sobrien dialect = 1; 333190087Sobrien 333250503Sobrien /* If we want the first dialect, do nothing. Otherwise, skip 333350503Sobrien DIALECT_NUMBER of strings ending with '|'. */ 333450503Sobrien for (i = 0; i < dialect_number; i++) 333550503Sobrien { 333690087Sobrien while (*p && *p != '}' && *p++ != '|') 333750503Sobrien ; 333890087Sobrien if (*p == '}') 333990087Sobrien break; 334050503Sobrien if (*p == '|') 334150503Sobrien p++; 334250503Sobrien } 334390087Sobrien 334490087Sobrien if (*p == '\0') 334590087Sobrien output_operand_lossage ("unterminated assembly dialect alternative"); 334650503Sobrien } 334718334Speter break; 334818334Speter 334918334Speter case '|': 335090087Sobrien if (dialect) 335190087Sobrien { 335290087Sobrien /* Skip to close brace. */ 335390087Sobrien do 335490087Sobrien { 335590087Sobrien if (*p == '\0') 335690087Sobrien { 335790087Sobrien output_operand_lossage ("unterminated assembly dialect alternative"); 335890087Sobrien break; 335990087Sobrien } 336090087Sobrien } 336190087Sobrien while (*p++ != '}'); 336290087Sobrien dialect = 0; 336390087Sobrien } 336490087Sobrien else 336590087Sobrien putc (c, asm_out_file); 336618334Speter break; 336718334Speter 336818334Speter case '}': 336990087Sobrien if (! dialect) 337090087Sobrien putc (c, asm_out_file); 337190087Sobrien dialect = 0; 337218334Speter break; 337318334Speter#endif 337418334Speter 337518334Speter case '%': 337618334Speter /* %% outputs a single %. */ 337718334Speter if (*p == '%') 337818334Speter { 337918334Speter p++; 338018334Speter putc (c, asm_out_file); 338118334Speter } 338218334Speter /* %= outputs a number which is unique to each insn in the entire 338318334Speter compilation. This is useful for making local labels that are 338418334Speter referred to more than once in a given insn. */ 338518334Speter else if (*p == '=') 338618334Speter { 338718334Speter p++; 338818334Speter fprintf (asm_out_file, "%d", insn_counter); 338918334Speter } 339018334Speter /* % followed by a letter and some digits 339118334Speter outputs an operand in a special way depending on the letter. 339218334Speter Letters `acln' are implemented directly. 339318334Speter Other letters are passed to `output_operand' so that 339418334Speter the PRINT_OPERAND macro can define them. */ 339590087Sobrien else if (ISALPHA (*p)) 339618334Speter { 339718334Speter int letter = *p++; 339818334Speter c = atoi (p); 339918334Speter 340090087Sobrien if (! ISDIGIT (*p)) 340196281Sobrien output_operand_lossage ("operand number missing after %%-letter"); 340290087Sobrien else if (this_is_asm_operands 340390087Sobrien && (c < 0 || (unsigned int) c >= insn_noperands)) 340418334Speter output_operand_lossage ("operand number out of range"); 340518334Speter else if (letter == 'l') 340618334Speter output_asm_label (operands[c]); 340718334Speter else if (letter == 'a') 340818334Speter output_address (operands[c]); 340918334Speter else if (letter == 'c') 341018334Speter { 341118334Speter if (CONSTANT_ADDRESS_P (operands[c])) 341218334Speter output_addr_const (asm_out_file, operands[c]); 341318334Speter else 341418334Speter output_operand (operands[c], 'c'); 341518334Speter } 341618334Speter else if (letter == 'n') 341718334Speter { 341818334Speter if (GET_CODE (operands[c]) == CONST_INT) 341950503Sobrien fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, 342018334Speter - INTVAL (operands[c])); 342118334Speter else 342218334Speter { 342318334Speter putc ('-', asm_out_file); 342418334Speter output_addr_const (asm_out_file, operands[c]); 342518334Speter } 342618334Speter } 342718334Speter else 342818334Speter output_operand (operands[c], letter); 342990087Sobrien 343090087Sobrien if (!opoutput[c]) 343190087Sobrien oporder[ops++] = c; 343290087Sobrien opoutput[c] = 1; 343390087Sobrien 343490087Sobrien while (ISDIGIT (c = *p)) 343590087Sobrien p++; 343618334Speter } 343718334Speter /* % followed by a digit outputs an operand the default way. */ 343890087Sobrien else if (ISDIGIT (*p)) 343918334Speter { 344018334Speter c = atoi (p); 344190087Sobrien if (this_is_asm_operands 344290087Sobrien && (c < 0 || (unsigned int) c >= insn_noperands)) 344318334Speter output_operand_lossage ("operand number out of range"); 344418334Speter else 344518334Speter output_operand (operands[c], 0); 344690087Sobrien 344790087Sobrien if (!opoutput[c]) 344890087Sobrien oporder[ops++] = c; 344990087Sobrien opoutput[c] = 1; 345090087Sobrien 345190087Sobrien while (ISDIGIT (c = *p)) 345290087Sobrien p++; 345318334Speter } 345418334Speter /* % followed by punctuation: output something for that 345518334Speter punctuation character alone, with no operand. 345618334Speter The PRINT_OPERAND macro decides what is actually done. */ 345718334Speter#ifdef PRINT_OPERAND_PUNCT_VALID_P 345890087Sobrien else if (PRINT_OPERAND_PUNCT_VALID_P ((unsigned char) *p)) 345918334Speter output_operand (NULL_RTX, *p++); 346018334Speter#endif 346118334Speter else 346218334Speter output_operand_lossage ("invalid %%-code"); 346318334Speter break; 346418334Speter 346518334Speter default: 346618334Speter putc (c, asm_out_file); 346718334Speter } 346818334Speter 346990087Sobrien /* Write out the variable names for operands, if we know them. */ 347090087Sobrien if (flag_verbose_asm) 347190087Sobrien output_asm_operand_names (operands, oporder, ops); 347290087Sobrien if (flag_print_asm_name) 347390087Sobrien output_asm_name (); 347418334Speter 347518334Speter putc ('\n', asm_out_file); 347618334Speter} 347718334Speter 347818334Speter/* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol. */ 347918334Speter 348018334Spetervoid 348118334Speteroutput_asm_label (x) 348218334Speter rtx x; 348318334Speter{ 348418334Speter char buf[256]; 348518334Speter 348618334Speter if (GET_CODE (x) == LABEL_REF) 348790087Sobrien x = XEXP (x, 0); 348890087Sobrien if (GET_CODE (x) == CODE_LABEL 348990087Sobrien || (GET_CODE (x) == NOTE 349090087Sobrien && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL)) 349118334Speter ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); 349218334Speter else 349396281Sobrien output_operand_lossage ("`%%l' operand isn't a label"); 349418334Speter 349518334Speter assemble_name (asm_out_file, buf); 349618334Speter} 349718334Speter 349818334Speter/* Print operand X using machine-dependent assembler syntax. 349918334Speter The macro PRINT_OPERAND is defined just to control this function. 350018334Speter CODE is a non-digit that preceded the operand-number in the % spec, 350118334Speter such as 'z' if the spec was `%z3'. CODE is 0 if there was no char 350218334Speter between the % and the digits. 350318334Speter When CODE is a non-letter, X is 0. 350418334Speter 350518334Speter The meanings of the letters are machine-dependent and controlled 350618334Speter by PRINT_OPERAND. */ 350718334Speter 350818334Speterstatic void 350918334Speteroutput_operand (x, code) 351018334Speter rtx x; 351190087Sobrien int code ATTRIBUTE_UNUSED; 351218334Speter{ 351318334Speter if (x && GET_CODE (x) == SUBREG) 351490087Sobrien x = alter_subreg (&x); 351518334Speter 351618334Speter /* If X is a pseudo-register, abort now rather than writing trash to the 351718334Speter assembler file. */ 351818334Speter 351918334Speter if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER) 352018334Speter abort (); 352118334Speter 352218334Speter PRINT_OPERAND (asm_out_file, x, code); 352318334Speter} 352418334Speter 352518334Speter/* Print a memory reference operand for address X 352618334Speter using machine-dependent assembler syntax. 352718334Speter The macro PRINT_OPERAND_ADDRESS exists just to control this function. */ 352818334Speter 352918334Spetervoid 353018334Speteroutput_address (x) 353118334Speter rtx x; 353218334Speter{ 353390087Sobrien walk_alter_subreg (&x); 353418334Speter PRINT_OPERAND_ADDRESS (asm_out_file, x); 353518334Speter} 353618334Speter 353718334Speter/* Print an integer constant expression in assembler syntax. 353818334Speter Addition and subtraction are the only arithmetic 353918334Speter that may appear in these expressions. */ 354018334Speter 354118334Spetervoid 354218334Speteroutput_addr_const (file, x) 354318334Speter FILE *file; 354418334Speter rtx x; 354518334Speter{ 354618334Speter char buf[256]; 354718334Speter 354818334Speter restart: 354918334Speter switch (GET_CODE (x)) 355018334Speter { 355118334Speter case PC: 355290087Sobrien putc ('.', file); 355318334Speter break; 355418334Speter 355518334Speter case SYMBOL_REF: 355690087Sobrien#ifdef ASM_OUTPUT_SYMBOL_REF 355790087Sobrien ASM_OUTPUT_SYMBOL_REF (file, x); 355890087Sobrien#else 355918334Speter assemble_name (file, XSTR (x, 0)); 356090087Sobrien#endif 356118334Speter break; 356218334Speter 356318334Speter case LABEL_REF: 356490087Sobrien x = XEXP (x, 0); 356590087Sobrien /* Fall through. */ 356618334Speter case CODE_LABEL: 356718334Speter ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); 356890087Sobrien#ifdef ASM_OUTPUT_LABEL_REF 356990087Sobrien ASM_OUTPUT_LABEL_REF (file, buf); 357090087Sobrien#else 357118334Speter assemble_name (file, buf); 357290087Sobrien#endif 357318334Speter break; 357418334Speter 357518334Speter case CONST_INT: 357650503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); 357718334Speter break; 357818334Speter 357918334Speter case CONST: 358018334Speter /* This used to output parentheses around the expression, 358118334Speter but that does not work on the 386 (either ATT or BSD assembler). */ 358218334Speter output_addr_const (file, XEXP (x, 0)); 358318334Speter break; 358418334Speter 358518334Speter case CONST_DOUBLE: 358618334Speter if (GET_MODE (x) == VOIDmode) 358718334Speter { 358818334Speter /* We can use %d if the number is one word and positive. */ 358918334Speter if (CONST_DOUBLE_HIGH (x)) 359050503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX, 359118334Speter CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x)); 359290087Sobrien else if (CONST_DOUBLE_LOW (x) < 0) 359350503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x)); 359418334Speter else 359550503Sobrien fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x)); 359618334Speter } 359718334Speter else 359818334Speter /* We can't handle floating point constants; 359918334Speter PRINT_OPERAND must handle them. */ 360018334Speter output_operand_lossage ("floating constant misused"); 360118334Speter break; 360218334Speter 360318334Speter case PLUS: 360418334Speter /* Some assemblers need integer constants to appear last (eg masm). */ 360518334Speter if (GET_CODE (XEXP (x, 0)) == CONST_INT) 360618334Speter { 360718334Speter output_addr_const (file, XEXP (x, 1)); 360818334Speter if (INTVAL (XEXP (x, 0)) >= 0) 360918334Speter fprintf (file, "+"); 361018334Speter output_addr_const (file, XEXP (x, 0)); 361118334Speter } 361218334Speter else 361318334Speter { 361418334Speter output_addr_const (file, XEXP (x, 0)); 361590087Sobrien if (GET_CODE (XEXP (x, 1)) != CONST_INT 361690087Sobrien || INTVAL (XEXP (x, 1)) >= 0) 361718334Speter fprintf (file, "+"); 361818334Speter output_addr_const (file, XEXP (x, 1)); 361918334Speter } 362018334Speter break; 362118334Speter 362218334Speter case MINUS: 362318334Speter /* Avoid outputting things like x-x or x+5-x, 362418334Speter since some assemblers can't handle that. */ 362518334Speter x = simplify_subtraction (x); 362618334Speter if (GET_CODE (x) != MINUS) 362718334Speter goto restart; 362818334Speter 362918334Speter output_addr_const (file, XEXP (x, 0)); 363018334Speter fprintf (file, "-"); 363190087Sobrien if ((GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0) 363290087Sobrien || GET_CODE (XEXP (x, 1)) == PC 363390087Sobrien || GET_CODE (XEXP (x, 1)) == SYMBOL_REF) 363490087Sobrien output_addr_const (file, XEXP (x, 1)); 363590087Sobrien else 363618334Speter { 363790087Sobrien fputs (targetm.asm_out.open_paren, file); 363818334Speter output_addr_const (file, XEXP (x, 1)); 363990087Sobrien fputs (targetm.asm_out.close_paren, file); 364018334Speter } 364118334Speter break; 364218334Speter 364318334Speter case ZERO_EXTEND: 364418334Speter case SIGN_EXTEND: 364596281Sobrien case SUBREG: 364618334Speter output_addr_const (file, XEXP (x, 0)); 364718334Speter break; 364818334Speter 364918334Speter default: 365090087Sobrien#ifdef OUTPUT_ADDR_CONST_EXTRA 365190087Sobrien OUTPUT_ADDR_CONST_EXTRA (file, x, fail); 365290087Sobrien break; 365390087Sobrien 365490087Sobrien fail: 365590087Sobrien#endif 365618334Speter output_operand_lossage ("invalid expression as operand"); 365718334Speter } 365818334Speter} 365918334Speter 366018334Speter/* A poor man's fprintf, with the added features of %I, %R, %L, and %U. 366118334Speter %R prints the value of REGISTER_PREFIX. 366218334Speter %L prints the value of LOCAL_LABEL_PREFIX. 366318334Speter %U prints the value of USER_LABEL_PREFIX. 366418334Speter %I prints the value of IMMEDIATE_PREFIX. 366518334Speter %O runs ASM_OUTPUT_OPCODE to transform what follows in the string. 366618334Speter Also supported are %d, %x, %s, %e, %f, %g and %%. 366718334Speter 366818334Speter We handle alternate assembler dialects here, just like output_asm_insn. */ 366918334Speter 367018334Spetervoid 367190087Sobrienasm_fprintf VPARAMS ((FILE *file, const char *p, ...)) 367218334Speter{ 367318334Speter char buf[10]; 367418334Speter char *q, c; 367518334Speter 367690087Sobrien VA_OPEN (argptr, p); 367790087Sobrien VA_FIXEDARG (argptr, FILE *, file); 367890087Sobrien VA_FIXEDARG (argptr, const char *, p); 367918334Speter 368018334Speter buf[0] = '%'; 368118334Speter 368250503Sobrien while ((c = *p++)) 368318334Speter switch (c) 368418334Speter { 368518334Speter#ifdef ASSEMBLER_DIALECT 368618334Speter case '{': 368750503Sobrien { 368850503Sobrien int i; 368918334Speter 369050503Sobrien /* If we want the first dialect, do nothing. Otherwise, skip 369150503Sobrien DIALECT_NUMBER of strings ending with '|'. */ 369250503Sobrien for (i = 0; i < dialect_number; i++) 369350503Sobrien { 369450503Sobrien while (*p && *p++ != '|') 369550503Sobrien ; 369650503Sobrien 369750503Sobrien if (*p == '|') 369850503Sobrien p++; 369990087Sobrien } 370050503Sobrien } 370118334Speter break; 370218334Speter 370318334Speter case '|': 370418334Speter /* Skip to close brace. */ 370518334Speter while (*p && *p++ != '}') 370618334Speter ; 370718334Speter break; 370818334Speter 370918334Speter case '}': 371018334Speter break; 371118334Speter#endif 371218334Speter 371318334Speter case '%': 371418334Speter c = *p++; 371518334Speter q = &buf[1]; 371690087Sobrien while (ISDIGIT (c) || c == '.') 371718334Speter { 371818334Speter *q++ = c; 371918334Speter c = *p++; 372018334Speter } 372118334Speter switch (c) 372218334Speter { 372318334Speter case '%': 372418334Speter fprintf (file, "%%"); 372518334Speter break; 372618334Speter 372718334Speter case 'd': case 'i': case 'u': 372818334Speter case 'x': case 'p': case 'X': 372918334Speter case 'o': 373018334Speter *q++ = c; 373118334Speter *q = 0; 373218334Speter fprintf (file, buf, va_arg (argptr, int)); 373318334Speter break; 373418334Speter 373518334Speter case 'w': 373618334Speter /* This is a prefix to the 'd', 'i', 'u', 'x', 'p', and 'X' cases, 373718334Speter but we do not check for those cases. It means that the value 373818334Speter is a HOST_WIDE_INT, which may be either `int' or `long'. */ 373918334Speter 374050503Sobrien#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT 374150503Sobrien#else 374250503Sobrien#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG 374318334Speter *q++ = 'l'; 374450503Sobrien#else 374550503Sobrien *q++ = 'l'; 374650503Sobrien *q++ = 'l'; 374718334Speter#endif 374850503Sobrien#endif 374918334Speter 375018334Speter *q++ = *p++; 375118334Speter *q = 0; 375218334Speter fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT)); 375318334Speter break; 375418334Speter 375518334Speter case 'l': 375618334Speter *q++ = c; 375718334Speter *q++ = *p++; 375818334Speter *q = 0; 375918334Speter fprintf (file, buf, va_arg (argptr, long)); 376018334Speter break; 376118334Speter 376218334Speter case 'e': 376318334Speter case 'f': 376418334Speter case 'g': 376518334Speter *q++ = c; 376618334Speter *q = 0; 376718334Speter fprintf (file, buf, va_arg (argptr, double)); 376818334Speter break; 376918334Speter 377018334Speter case 's': 377118334Speter *q++ = c; 377218334Speter *q = 0; 377318334Speter fprintf (file, buf, va_arg (argptr, char *)); 377418334Speter break; 377518334Speter 377618334Speter case 'O': 377718334Speter#ifdef ASM_OUTPUT_OPCODE 377818334Speter ASM_OUTPUT_OPCODE (asm_out_file, p); 377918334Speter#endif 378018334Speter break; 378118334Speter 378218334Speter case 'R': 378318334Speter#ifdef REGISTER_PREFIX 378418334Speter fprintf (file, "%s", REGISTER_PREFIX); 378518334Speter#endif 378618334Speter break; 378718334Speter 378818334Speter case 'I': 378918334Speter#ifdef IMMEDIATE_PREFIX 379018334Speter fprintf (file, "%s", IMMEDIATE_PREFIX); 379118334Speter#endif 379218334Speter break; 379318334Speter 379418334Speter case 'L': 379518334Speter#ifdef LOCAL_LABEL_PREFIX 379618334Speter fprintf (file, "%s", LOCAL_LABEL_PREFIX); 379718334Speter#endif 379818334Speter break; 379918334Speter 380018334Speter case 'U': 380152515Sobrien fputs (user_label_prefix, file); 380218334Speter break; 380318334Speter 380490087Sobrien#ifdef ASM_FPRINTF_EXTENSIONS 380590087Sobrien /* Upper case letters are reserved for general use by asm_fprintf 380690087Sobrien and so are not available to target specific code. In order to 380790087Sobrien prevent the ASM_FPRINTF_EXTENSIONS macro from using them then, 380890087Sobrien they are defined here. As they get turned into real extensions 380990087Sobrien to asm_fprintf they should be removed from this list. */ 381090087Sobrien case 'A': case 'B': case 'C': case 'D': case 'E': 381190087Sobrien case 'F': case 'G': case 'H': case 'J': case 'K': 381290087Sobrien case 'M': case 'N': case 'P': case 'Q': case 'S': 381390087Sobrien case 'T': case 'V': case 'W': case 'Y': case 'Z': 381490087Sobrien break; 381590087Sobrien 381690087Sobrien ASM_FPRINTF_EXTENSIONS (file, argptr, p) 381790087Sobrien#endif 381818334Speter default: 381918334Speter abort (); 382018334Speter } 382118334Speter break; 382218334Speter 382318334Speter default: 382418334Speter fputc (c, file); 382518334Speter } 382690087Sobrien VA_CLOSE (argptr); 382718334Speter} 382818334Speter 382918334Speter/* Split up a CONST_DOUBLE or integer constant rtx 383018334Speter into two rtx's for single words, 383118334Speter storing in *FIRST the word that comes first in memory in the target 383218334Speter and in *SECOND the other. */ 383318334Speter 383418334Spetervoid 383518334Spetersplit_double (value, first, second) 383618334Speter rtx value; 383718334Speter rtx *first, *second; 383818334Speter{ 383918334Speter if (GET_CODE (value) == CONST_INT) 384018334Speter { 384118334Speter if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD)) 384218334Speter { 384318334Speter /* In this case the CONST_INT holds both target words. 384450503Sobrien Extract the bits from it into two word-sized pieces. 384550503Sobrien Sign extend each half to HOST_WIDE_INT. */ 384690087Sobrien unsigned HOST_WIDE_INT low, high; 384790087Sobrien unsigned HOST_WIDE_INT mask, sign_bit, sign_extend; 384818334Speter 384990087Sobrien /* Set sign_bit to the most significant bit of a word. */ 385090087Sobrien sign_bit = 1; 385190087Sobrien sign_bit <<= BITS_PER_WORD - 1; 385290087Sobrien 385390087Sobrien /* Set mask so that all bits of the word are set. We could 385490087Sobrien have used 1 << BITS_PER_WORD instead of basing the 385590087Sobrien calculation on sign_bit. However, on machines where 385690087Sobrien HOST_BITS_PER_WIDE_INT == BITS_PER_WORD, it could cause a 385790087Sobrien compiler warning, even though the code would never be 385890087Sobrien executed. */ 385990087Sobrien mask = sign_bit << 1; 386090087Sobrien mask--; 386190087Sobrien 386290087Sobrien /* Set sign_extend as any remaining bits. */ 386390087Sobrien sign_extend = ~mask; 386490087Sobrien 386590087Sobrien /* Pick the lower word and sign-extend it. */ 386690087Sobrien low = INTVAL (value); 386790087Sobrien low &= mask; 386890087Sobrien if (low & sign_bit) 386990087Sobrien low |= sign_extend; 387090087Sobrien 387190087Sobrien /* Pick the higher word, shifted to the least significant 387290087Sobrien bits, and sign-extend it. */ 387390087Sobrien high = INTVAL (value); 387490087Sobrien high >>= BITS_PER_WORD - 1; 387590087Sobrien high >>= 1; 387690087Sobrien high &= mask; 387790087Sobrien if (high & sign_bit) 387890087Sobrien high |= sign_extend; 387990087Sobrien 388090087Sobrien /* Store the words in the target machine order. */ 388118334Speter if (WORDS_BIG_ENDIAN) 388218334Speter { 388390087Sobrien *first = GEN_INT (high); 388490087Sobrien *second = GEN_INT (low); 388518334Speter } 388618334Speter else 388718334Speter { 388890087Sobrien *first = GEN_INT (low); 388990087Sobrien *second = GEN_INT (high); 389018334Speter } 389118334Speter } 389218334Speter else 389318334Speter { 389418334Speter /* The rule for using CONST_INT for a wider mode 389518334Speter is that we regard the value as signed. 389618334Speter So sign-extend it. */ 389718334Speter rtx high = (INTVAL (value) < 0 ? constm1_rtx : const0_rtx); 389818334Speter if (WORDS_BIG_ENDIAN) 389918334Speter { 390018334Speter *first = high; 390118334Speter *second = value; 390218334Speter } 390318334Speter else 390418334Speter { 390518334Speter *first = value; 390618334Speter *second = high; 390718334Speter } 390818334Speter } 390918334Speter } 391018334Speter else if (GET_CODE (value) != CONST_DOUBLE) 391118334Speter { 391218334Speter if (WORDS_BIG_ENDIAN) 391318334Speter { 391418334Speter *first = const0_rtx; 391518334Speter *second = value; 391618334Speter } 391718334Speter else 391818334Speter { 391918334Speter *first = value; 392018334Speter *second = const0_rtx; 392118334Speter } 392218334Speter } 392318334Speter else if (GET_MODE (value) == VOIDmode 392418334Speter /* This is the old way we did CONST_DOUBLE integers. */ 392518334Speter || GET_MODE_CLASS (GET_MODE (value)) == MODE_INT) 392618334Speter { 392718334Speter /* In an integer, the words are defined as most and least significant. 392818334Speter So order them by the target's convention. */ 392918334Speter if (WORDS_BIG_ENDIAN) 393018334Speter { 393118334Speter *first = GEN_INT (CONST_DOUBLE_HIGH (value)); 393218334Speter *second = GEN_INT (CONST_DOUBLE_LOW (value)); 393318334Speter } 393418334Speter else 393518334Speter { 393618334Speter *first = GEN_INT (CONST_DOUBLE_LOW (value)); 393718334Speter *second = GEN_INT (CONST_DOUBLE_HIGH (value)); 393818334Speter } 393918334Speter } 394018334Speter else 394118334Speter { 394290087Sobrien REAL_VALUE_TYPE r; 394390087Sobrien long l[2]; 394418334Speter REAL_VALUE_FROM_CONST_DOUBLE (r, value); 394518334Speter 394618334Speter /* Note, this converts the REAL_VALUE_TYPE to the target's 394718334Speter format, splits up the floating point double and outputs 394818334Speter exactly 32 bits of it into each of l[0] and l[1] -- 394950503Sobrien not necessarily BITS_PER_WORD bits. */ 395018334Speter REAL_VALUE_TO_TARGET_DOUBLE (r, l); 395118334Speter 395252515Sobrien /* If 32 bits is an entire word for the target, but not for the host, 395352515Sobrien then sign-extend on the host so that the number will look the same 395452515Sobrien way on the host that it would on the target. See for instance 395552515Sobrien simplify_unary_operation. The #if is needed to avoid compiler 395652515Sobrien warnings. */ 395752515Sobrien 395852515Sobrien#if HOST_BITS_PER_LONG > 32 395952515Sobrien if (BITS_PER_WORD < HOST_BITS_PER_LONG && BITS_PER_WORD == 32) 396052515Sobrien { 396152515Sobrien if (l[0] & ((long) 1 << 31)) 396252515Sobrien l[0] |= ((long) (-1) << 32); 396352515Sobrien if (l[1] & ((long) 1 << 31)) 396452515Sobrien l[1] |= ((long) (-1) << 32); 396552515Sobrien } 396652515Sobrien#endif 396752515Sobrien 396818334Speter *first = GEN_INT ((HOST_WIDE_INT) l[0]); 396918334Speter *second = GEN_INT ((HOST_WIDE_INT) l[1]); 397018334Speter } 397118334Speter} 397218334Speter 397318334Speter/* Return nonzero if this function has no function calls. */ 397418334Speter 397518334Speterint 397618334Speterleaf_function_p () 397718334Speter{ 397818334Speter rtx insn; 397990087Sobrien rtx link; 398018334Speter 398190087Sobrien if (current_function_profile || profile_arc_flag) 398218334Speter return 0; 398318334Speter 398418334Speter for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) 398518334Speter { 398690087Sobrien if (GET_CODE (insn) == CALL_INSN 398790087Sobrien && ! SIBLING_CALL_P (insn)) 398818334Speter return 0; 398918334Speter if (GET_CODE (insn) == INSN 399018334Speter && GET_CODE (PATTERN (insn)) == SEQUENCE 399190087Sobrien && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN 399290087Sobrien && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0))) 399318334Speter return 0; 399418334Speter } 399590087Sobrien for (link = current_function_epilogue_delay_list; 399690087Sobrien link; 399790087Sobrien link = XEXP (link, 1)) 399818334Speter { 399990087Sobrien insn = XEXP (link, 0); 400090087Sobrien 400190087Sobrien if (GET_CODE (insn) == CALL_INSN 400290087Sobrien && ! SIBLING_CALL_P (insn)) 400318334Speter return 0; 400490087Sobrien if (GET_CODE (insn) == INSN 400590087Sobrien && GET_CODE (PATTERN (insn)) == SEQUENCE 400690087Sobrien && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN 400790087Sobrien && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0))) 400818334Speter return 0; 400918334Speter } 401018334Speter 401118334Speter return 1; 401218334Speter} 401318334Speter 4014117404Skan/* Return 1 if branch is a forward branch. 401590087Sobrien Uses insn_shuid array, so it works only in the final pass. May be used by 401690087Sobrien output templates to customary add branch prediction hints. 401790087Sobrien */ 401890087Sobrienint 401990087Sobrienfinal_forward_branch_p (insn) 402090087Sobrien rtx insn; 402190087Sobrien{ 402290087Sobrien int insn_id, label_id; 402390087Sobrien if (!uid_shuid) 402490087Sobrien abort (); 402590087Sobrien insn_id = INSN_SHUID (insn); 402690087Sobrien label_id = INSN_SHUID (JUMP_LABEL (insn)); 402790087Sobrien /* We've hit some insns that does not have id information available. */ 402890087Sobrien if (!insn_id || !label_id) 402990087Sobrien abort (); 403090087Sobrien return insn_id < label_id; 403190087Sobrien} 403290087Sobrien 403318334Speter/* On some machines, a function with no call insns 403418334Speter can run faster if it doesn't create its own register window. 403518334Speter When output, the leaf function should use only the "output" 403618334Speter registers. Ordinarily, the function would be compiled to use 403718334Speter the "input" registers to find its arguments; it is a candidate 403818334Speter for leaf treatment if it uses only the "input" registers. 403918334Speter Leaf function treatment means renumbering so the function 404018334Speter uses the "output" registers instead. */ 404118334Speter 404218334Speter#ifdef LEAF_REGISTERS 404318334Speter 404418334Speter/* Return 1 if this function uses only the registers that can be 404518334Speter safely renumbered. */ 404618334Speter 404718334Speterint 404818334Speteronly_leaf_regs_used () 404918334Speter{ 405018334Speter int i; 405190087Sobrien char *permitted_reg_in_leaf_functions = LEAF_REGISTERS; 405218334Speter 405318334Speter for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 405450503Sobrien if ((regs_ever_live[i] || global_regs[i]) 405550503Sobrien && ! permitted_reg_in_leaf_functions[i]) 405650503Sobrien return 0; 405750503Sobrien 405850503Sobrien if (current_function_uses_pic_offset_table 405950503Sobrien && pic_offset_table_rtx != 0 406050503Sobrien && GET_CODE (pic_offset_table_rtx) == REG 406150503Sobrien && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)]) 406250503Sobrien return 0; 406350503Sobrien 406418334Speter return 1; 406518334Speter} 406618334Speter 406718334Speter/* Scan all instructions and renumber all registers into those 406818334Speter available in leaf functions. */ 406918334Speter 407018334Speterstatic void 407118334Speterleaf_renumber_regs (first) 407218334Speter rtx first; 407318334Speter{ 407418334Speter rtx insn; 407518334Speter 407618334Speter /* Renumber only the actual patterns. 407718334Speter The reg-notes can contain frame pointer refs, 407818334Speter and renumbering them could crash, and should not be needed. */ 407918334Speter for (insn = first; insn; insn = NEXT_INSN (insn)) 408090087Sobrien if (INSN_P (insn)) 408118334Speter leaf_renumber_regs_insn (PATTERN (insn)); 408290087Sobrien for (insn = current_function_epilogue_delay_list; 408390087Sobrien insn; 408490087Sobrien insn = XEXP (insn, 1)) 408590087Sobrien if (INSN_P (XEXP (insn, 0))) 408618334Speter leaf_renumber_regs_insn (PATTERN (XEXP (insn, 0))); 408718334Speter} 408818334Speter 408918334Speter/* Scan IN_RTX and its subexpressions, and renumber all regs into those 409018334Speter available in leaf functions. */ 409118334Speter 409218334Spetervoid 409318334Speterleaf_renumber_regs_insn (in_rtx) 409490087Sobrien rtx in_rtx; 409518334Speter{ 409690087Sobrien int i, j; 409790087Sobrien const char *format_ptr; 409818334Speter 409918334Speter if (in_rtx == 0) 410018334Speter return; 410118334Speter 410218334Speter /* Renumber all input-registers into output-registers. 410318334Speter renumbered_regs would be 1 for an output-register; 410418334Speter they */ 410518334Speter 410618334Speter if (GET_CODE (in_rtx) == REG) 410718334Speter { 410818334Speter int newreg; 410918334Speter 411018334Speter /* Don't renumber the same reg twice. */ 411118334Speter if (in_rtx->used) 411218334Speter return; 411318334Speter 411418334Speter newreg = REGNO (in_rtx); 411518334Speter /* Don't try to renumber pseudo regs. It is possible for a pseudo reg 411618334Speter to reach here as part of a REG_NOTE. */ 411718334Speter if (newreg >= FIRST_PSEUDO_REGISTER) 411818334Speter { 411918334Speter in_rtx->used = 1; 412018334Speter return; 412118334Speter } 412218334Speter newreg = LEAF_REG_REMAP (newreg); 412318334Speter if (newreg < 0) 412418334Speter abort (); 412518334Speter regs_ever_live[REGNO (in_rtx)] = 0; 412618334Speter regs_ever_live[newreg] = 1; 412718334Speter REGNO (in_rtx) = newreg; 412818334Speter in_rtx->used = 1; 412918334Speter } 413018334Speter 413190087Sobrien if (INSN_P (in_rtx)) 413218334Speter { 413318334Speter /* Inside a SEQUENCE, we find insns. 413418334Speter Renumber just the patterns of these insns, 413518334Speter just as we do for the top-level insns. */ 413618334Speter leaf_renumber_regs_insn (PATTERN (in_rtx)); 413718334Speter return; 413818334Speter } 413918334Speter 414018334Speter format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx)); 414118334Speter 414218334Speter for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++) 414318334Speter switch (*format_ptr++) 414418334Speter { 414518334Speter case 'e': 414618334Speter leaf_renumber_regs_insn (XEXP (in_rtx, i)); 414718334Speter break; 414818334Speter 414918334Speter case 'E': 415018334Speter if (NULL != XVEC (in_rtx, i)) 415118334Speter { 415218334Speter for (j = 0; j < XVECLEN (in_rtx, i); j++) 415318334Speter leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j)); 415418334Speter } 415518334Speter break; 415618334Speter 415718334Speter case 'S': 415818334Speter case 's': 415918334Speter case '0': 416018334Speter case 'i': 416118334Speter case 'w': 416218334Speter case 'n': 416318334Speter case 'u': 416418334Speter break; 416518334Speter 416618334Speter default: 416718334Speter abort (); 416818334Speter } 416918334Speter} 417018334Speter#endif 4171