X-Git-Url: https://gcc.gnu.org/git/?a=blobdiff_plain;f=gcc%2Ffinal.c;h=b82a0425574b0fc7893054b0a27f969be25b4ec7;hb=c6df88cbec5637cfc297cea1b6c90fa638949cdc;hp=6b851f20be745f3fb5a84f924d10bc054dbcba73;hpb=ce4d78eb2f91ec1b5278a4a23467055089ccc22f;p=gcc.git diff --git a/gcc/final.c b/gcc/final.c index 6b851f20be74..b82a0425574b 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -1,5 +1,5 @@ /* Convert RTL to assembler code and output it, for GNU compiler. - Copyright (C) 1987, 88, 89, 92-7, 1998 Free Software Foundation, Inc. + Copyright (C) 1987, 88, 89, 92-98, 1999 Free Software Foundation, Inc. This file is part of GNU CC. @@ -45,11 +45,6 @@ Boston, MA 02111-1307, USA. */ FUNCTION_EPILOGUE. Those instructions never exist as rtl. */ #include "config.h" -#ifdef __STDC__ -#include -#else -#include -#endif #include "system.h" #include "tree.h" @@ -67,20 +62,36 @@ Boston, MA 02111-1307, USA. */ #include "defaults.h" #include "output.h" #include "except.h" +#include "toplev.h" +#include "reload.h" /* Get N_SLINE and N_SOL from stab.h if we can expect the file to exist. */ #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO) -#if defined (USG) || defined (NO_STAB_H) +#include "dbxout.h" +#if defined (USG) || !defined (HAVE_STAB_H) #include "gstab.h" /* If doing DBX on sysV, use our own stab.h. */ #else -#include /* On BSD, use the system's stab.h. */ -#endif /* not USG */ +#include +#endif + #endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */ #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" #endif +#ifdef DWARF_DEBUGGING_INFO +#include "dwarfout.h" +#endif + +#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO) +#include "dwarf2out.h" +#endif + +#ifdef SDB_DEBUGGING_INFO +#include "sdbout.h" +#endif + /* .stabd code for line number. */ #ifndef N_SLINE #define N_SLINE 0x44 @@ -115,6 +126,10 @@ Boston, MA 02111-1307, USA. */ #define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';') #endif +#ifndef JUMP_TABLES_IN_TEXT_SECTION +#define JUMP_TABLES_IN_TEXT_SECTION 0 +#endif + /* Nonzero means this function is a leaf function, with no function calls. This variable exists to be examined in FUNCTION_PROLOGUE and FUNCTION_EPILOGUE. Always zero, unless set by some action. */ @@ -320,7 +335,7 @@ init_final (filename) void end_final (filename) - char *filename; + const char *filename; { int i; @@ -625,12 +640,54 @@ int insn_last_address; /* konwn invariant alignment of insn being processed. */ int insn_current_align; +/* After shorten_branches, for any insn, uid_align[INSN_UID (insn)] + gives the next following alignment insn that increases the known + alignment, or NULL_RTX if there is no such insn. + For any alignment obtained this way, we can again index uid_align with + its uid to obtain the next following align that in turn increases the + alignment, till we reach NULL_RTX; the sequence obtained this way + for each insn we'll call the alignment chain of this insn in the following + comments. */ + +struct label_alignment { + short alignment; + short max_skip; +}; + +static rtx *uid_align; +static int *uid_shuid; +static struct label_alignment *label_align; + /* Indicate that branch shortening hasn't yet been done. */ void init_insn_lengths () { - insn_lengths = 0; + if (label_align) + { + free (label_align); + label_align = 0; + } + if (uid_shuid) + { + free (uid_shuid); + uid_shuid = 0; + } + if (insn_lengths) + { + free (insn_lengths); + insn_lengths = 0; + } + if (insn_addresses) + { + free (insn_addresses); + insn_addresses = 0; + } + if (uid_align) + { + free (uid_align); + uid_align = 0; + } } /* Obtain the current length of an insn. If branch shortening has been done, @@ -742,14 +799,26 @@ get_attr_length (insn) #define LABEL_ALIGN(LABEL) 0 #endif +#ifndef LABEL_ALIGN_MAX_SKIP +#define LABEL_ALIGN_MAX_SKIP 0 +#endif + #ifndef LOOP_ALIGN #define LOOP_ALIGN(LABEL) 0 #endif +#ifndef LOOP_ALIGN_MAX_SKIP +#define LOOP_ALIGN_MAX_SKIP 0 +#endif + #ifndef LABEL_ALIGN_AFTER_BARRIER #define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0 #endif +#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP +#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0 +#endif + #ifndef ADDR_VEC_ALIGN int final_addr_vec_align (addr_vec) @@ -769,25 +838,15 @@ final_addr_vec_align (addr_vec) #define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log #endif -/* For any insn, uid_align[INSN_UID (insn)] gives the next following - alignment insn that increases the known alignment, or NULL_RTX if - there is no such insn. - For any alignment obtained this way, we can again index uid_align with - its uid to obtain the next following align that in turn increases the - alignment, till we reach NULL_RTX; the sequence obtained this way - for each insn we'll call the alignment chain of this insn in the following - comments. */ - -rtx *uid_align; -int *uid_shuid; -short *label_align; /* sh.c needs this to calculate constant tables. */ - #define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)]) static int min_labelno, max_labelno; #define LABEL_TO_ALIGNMENT(LABEL) \ - (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno]) + (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].alignment) + +#define LABEL_TO_MAX_SKIP(LABEL) \ + (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].max_skip) /* For the benefit of port specific code do this also as a function. */ int @@ -923,6 +982,7 @@ shorten_branches (first) int max_uid; int i; int max_log; + int max_skip; #ifdef HAVE_ATTR_length #define MAX_CODE_ALIGN 16 rtx seq; @@ -955,19 +1015,18 @@ shorten_branches (first) /* We must do some computations even when not actually shortening, in order to get the alignment information for the labels. */ + init_insn_lengths (); + /* Compute maximum UID and allocate label_align / uid_shuid. */ max_uid = get_max_uid (); max_labelno = max_label_num (); min_labelno = get_first_label_num (); - if (label_align) - free (label_align); - label_align - = (short*) xmalloc ((max_labelno - min_labelno + 1) * sizeof (short)); - bzero (label_align, (max_labelno - min_labelno + 1) * sizeof (short)); + label_align = (struct label_alignment *) xmalloc ( + (max_labelno - min_labelno + 1) * sizeof (struct label_alignment)); + bzero ((char *) label_align, + (max_labelno - min_labelno + 1) * sizeof (struct label_alignment)); - if (uid_shuid) - free (uid_shuid); uid_shuid = (int *) xmalloc (max_uid * sizeof *uid_shuid); /* Initialize label_align and set up uid_shuid to be strictly @@ -976,7 +1035,10 @@ shorten_branches (first) impose on the next CODE_LABEL (or the current one if we are processing the CODE_LABEL itself). */ - for (max_log = 0, insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn)) + max_log = 0; + max_skip = 0; + + for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn)) { int log; @@ -995,24 +1057,36 @@ shorten_branches (first) log = LABEL_ALIGN (insn); if (max_log < log) - max_log = log; - next = NEXT_INSN (insn); -/* ADDR_VECs only take room if read-only data goes into the text section. */ -#if !defined(READONLY_DATA_SECTION) || defined(JUMP_TABLES_IN_TEXT_SECTION) - if (next && GET_CODE (next) == JUMP_INSN) { - rtx nextbody = PATTERN (next); - if (GET_CODE (nextbody) == ADDR_VEC - || GET_CODE (nextbody) == ADDR_DIFF_VEC) - { - log = ADDR_VEC_ALIGN (next); - if (max_log < log) - max_log = log; - } + max_log = log; + max_skip = LABEL_ALIGN_MAX_SKIP; } + next = NEXT_INSN (insn); + /* ADDR_VECs only take room if read-only data goes into the text + section. */ + if (JUMP_TABLES_IN_TEXT_SECTION +#if !defined(READONLY_DATA_SECTION) + || 1 #endif + ) + if (next && GET_CODE (next) == JUMP_INSN) + { + rtx nextbody = PATTERN (next); + if (GET_CODE (nextbody) == ADDR_VEC + || GET_CODE (nextbody) == ADDR_DIFF_VEC) + { + log = ADDR_VEC_ALIGN (next); + if (max_log < log) + { + max_log = log; + max_skip = LABEL_ALIGN_MAX_SKIP; + } + } + } LABEL_TO_ALIGNMENT (insn) = max_log; + LABEL_TO_MAX_SKIP (insn) = max_skip; max_log = 0; + max_skip = 0; } else if (GET_CODE (insn) == BARRIER) { @@ -1024,7 +1098,10 @@ shorten_branches (first) { log = LABEL_ALIGN_AFTER_BARRIER (insn); if (max_log < log) - max_log = log; + { + max_log = log; + max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP; + } break; } } @@ -1040,7 +1117,10 @@ shorten_branches (first) { log = LOOP_ALIGN (insn); if (max_log < log) - max_log = log; + { + max_log = log; + max_skip = LOOP_ALIGN_MAX_SKIP; + } break; } } @@ -1050,17 +1130,11 @@ shorten_branches (first) #ifdef HAVE_ATTR_length /* Allocate the rest of the arrays. */ - if (insn_lengths) - free (insn_lengths); insn_lengths = (short *) xmalloc (max_uid * sizeof (short)); - if (insn_addresses) - free (insn_addresses); insn_addresses = (int *) xmalloc (max_uid * sizeof (int)); /* Syntax errors can lead to labels being outside of the main insn stream. Initialize insn_addresses, so that we get reproducible results. */ bzero ((char *)insn_addresses, max_uid * sizeof *insn_addresses); - if (uid_align) - free (uid_align); uid_align = (rtx *) xmalloc (max_uid * sizeof *uid_align); varying_length = (char *) xmalloc (max_uid * sizeof (char)); @@ -1184,11 +1258,15 @@ shorten_branches (first) { /* This only takes room if read-only data goes into the text section. */ -#if !defined(READONLY_DATA_SECTION) || defined(JUMP_TABLES_IN_TEXT_SECTION) - insn_lengths[uid] = (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC) - * GET_MODE_SIZE (GET_MODE (body))); + if (JUMP_TABLES_IN_TEXT_SECTION +#if !defined(READONLY_DATA_SECTION) + || 1 +#endif + ) + insn_lengths[uid] = (XVECLEN (body, + GET_CODE (body) == ADDR_DIFF_VEC) + * GET_MODE_SIZE (GET_MODE (body))); /* Alignment is handled by ADDR_VEC_ALIGN. */ -#endif } else if (asm_noperands (body) >= 0) insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn); @@ -1379,13 +1457,19 @@ shorten_branches (first) PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr, max_addr - rel_addr, body)); -#if !defined(READONLY_DATA_SECTION) || defined(JUMP_TABLES_IN_TEXT_SECTION) - insn_lengths[uid] - = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body))); - insn_current_address += insn_lengths[uid]; - if (insn_lengths[uid] != old_length) - something_changed = 1; + if (JUMP_TABLES_IN_TEXT_SECTION +#if !defined(READONLY_DATA_SECTION) + || 1 #endif + ) + { + insn_lengths[uid] + = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body))); + insn_current_address += insn_lengths[uid]; + if (insn_lengths[uid] != old_length) + something_changed = 1; + } + continue; } #endif /* CASE_VECTOR_SHORTEN_MODE */ @@ -1508,7 +1592,7 @@ final_start_function (first, file, optimize) int i; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (!call_used_regs[i] && !call_fixed_regs[i]) + if (!call_used_regs[i]) regs_ever_live[i] = 1; } #endif @@ -1896,6 +1980,18 @@ final (first, file, optimize, prescan) max_uid = INSN_UID (insn); if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) line_note_exists[NOTE_LINE_NUMBER (insn)] = 1; +#ifdef HAVE_cc0 + /* If CC tracking across branches is enabled, record the insn which + jumps to each branch only reached from one place. */ + if (optimize && GET_CODE (insn) == JUMP_INSN) + { + rtx lab = JUMP_LABEL (insn); + if (lab && LABEL_NUSES (lab) == 1) + { + LABEL_REFS (lab) = insn; + } + } +#endif } /* Initialize insn_eh_region table if eh is being used. */ @@ -1939,7 +2035,6 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) int prescan; int nopeepholes; { - register int i; #ifdef HAVE_cc0 rtx set; #endif @@ -1969,7 +2064,8 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) && ! exceptions_via_longjmp) { ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", NOTE_BLOCK_NUMBER (insn)); - add_eh_table_entry (NOTE_BLOCK_NUMBER (insn)); + if (! flag_new_exceptions) + add_eh_table_entry (NOTE_BLOCK_NUMBER (insn)); #ifdef ASM_OUTPUT_EH_REGION_BEG ASM_OUTPUT_EH_REGION_BEG (file, NOTE_BLOCK_NUMBER (insn)); #endif @@ -1980,6 +2076,8 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) && ! exceptions_via_longjmp) { ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", NOTE_BLOCK_NUMBER (insn)); + if (flag_new_exceptions) + add_eh_table_entry (NOTE_BLOCK_NUMBER (insn)); #ifdef ASM_OUTPUT_EH_REGION_END ASM_OUTPUT_EH_REGION_END (file, NOTE_BLOCK_NUMBER (insn)); #endif @@ -2085,28 +2183,30 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) PENDING_BLOCKS and output debugging info based on that. */ --block_depth; + if (block_depth < 0) + abort (); #ifdef XCOFF_DEBUGGING_INFO - if (write_symbols == XCOFF_DEBUG && block_depth >= 0) + if (write_symbols == XCOFF_DEBUG) xcoffout_end_block (file, high_block_linenum, pending_blocks[block_depth]); #endif #ifdef DBX_DEBUGGING_INFO - if (write_symbols == DBX_DEBUG && block_depth >= 0) + if (write_symbols == DBX_DEBUG) ASM_OUTPUT_INTERNAL_LABEL (file, "LBE", pending_blocks[block_depth]); #endif #ifdef SDB_DEBUGGING_INFO - if (write_symbols == SDB_DEBUG && block_depth >= 0) + if (write_symbols == SDB_DEBUG) sdbout_end_block (file, high_block_linenum, pending_blocks[block_depth]); #endif #ifdef DWARF_DEBUGGING_INFO - if (write_symbols == DWARF_DEBUG && block_depth >= 0) + if (write_symbols == DWARF_DEBUG) dwarfout_end_block (pending_blocks[block_depth]); #endif #ifdef DWARF2_DEBUGGING_INFO - if (write_symbols == DWARF2_DEBUG && block_depth >= 0) + if (write_symbols == DWARF2_DEBUG) dwarf2out_end_block (pending_blocks[block_depth]); #endif } @@ -2185,11 +2285,44 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) if (CODE_LABEL_NUMBER (insn) <= max_labelno) { int align = LABEL_TO_ALIGNMENT (insn); +#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN + int max_skip = LABEL_TO_MAX_SKIP (insn); +#endif if (align && NEXT_INSN (insn)) +#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN + ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip); +#else ASM_OUTPUT_ALIGN (file, align); +#endif } +#ifdef HAVE_cc0 CC_STATUS_INIT; + /* If this label is reached from only one place, set the condition + codes from the instruction just before the branch. */ + + /* Disabled because some insns set cc_status in the C output code + and NOTICE_UPDATE_CC alone can set incorrect status. */ + if (0 /* optimize && LABEL_NUSES (insn) == 1*/) + { + rtx jump = LABEL_REFS (insn); + rtx barrier = prev_nonnote_insn (insn); + rtx prev; + /* If the LABEL_REFS field of this label has been set to point + at a branch, the predecessor of the branch is a regular + insn, and that branch is the only way to reach this label, + set the condition codes based on the branch and its + predecessor. */ + if (barrier && GET_CODE (barrier) == BARRIER + && jump && GET_CODE (jump) == JUMP_INSN + && (prev = prev_nonnote_insn (jump)) + && GET_CODE (prev) == INSN) + { + NOTICE_UPDATE_CC (PATTERN (prev), prev); + NOTICE_UPDATE_CC (PATTERN (jump), jump); + } + } +#endif if (prescan > 0) break; new_block = 1; @@ -2227,21 +2360,29 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) if (GET_CODE (nextbody) == ADDR_VEC || GET_CODE (nextbody) == ADDR_DIFF_VEC) { -#ifndef JUMP_TABLES_IN_TEXT_SECTION - readonly_data_section (); +#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC) + /* In this case, the case vector is being moved by the + target, so don't output the label at all. Leave that + to the back end macros. */ +#else + if (! JUMP_TABLES_IN_TEXT_SECTION) + { + readonly_data_section (); #ifdef READONLY_DATA_SECTION - ASM_OUTPUT_ALIGN (file, - exact_log2 (BIGGEST_ALIGNMENT - / BITS_PER_UNIT)); + ASM_OUTPUT_ALIGN (file, + exact_log2 (BIGGEST_ALIGNMENT + / BITS_PER_UNIT)); #endif /* READONLY_DATA_SECTION */ -#else /* JUMP_TABLES_IN_TEXT_SECTION */ - function_section (current_function_decl); -#endif /* JUMP_TABLES_IN_TEXT_SECTION */ + } + else + function_section (current_function_decl); + #ifdef ASM_OUTPUT_CASE_LABEL ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn), NEXT_INSN (insn)); #else ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn)); +#endif #endif break; } @@ -2285,7 +2426,9 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC) { +#if !(defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)) register int vlen, idx; +#endif if (prescan > 0) break; @@ -2296,6 +2439,24 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) app_on = 0; } +#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC) + if (GET_CODE (body) == ADDR_VEC) + { +#ifdef ASM_OUTPUT_ADDR_VEC + ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body); +#else + abort(); +#endif + } + else + { +#ifdef ASM_OUTPUT_ADDR_DIFF_VEC + ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body); +#else + abort(); +#endif + } +#else vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC); for (idx = 0; idx < vlen; idx++) { @@ -2325,6 +2486,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) ASM_OUTPUT_CASE_END (file, CODE_LABEL_NUMBER (PREV_INSN (insn)), insn); +#endif #endif function_section (current_function_decl); @@ -2682,27 +2844,11 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) since `reload' should have changed them so that they do. */ insn_code_number = recog_memoized (insn); - insn_extract (insn); - for (i = 0; i < insn_n_operands[insn_code_number]; i++) - { - if (GET_CODE (recog_operand[i]) == SUBREG) - recog_operand[i] = alter_subreg (recog_operand[i]); - else if (GET_CODE (recog_operand[i]) == PLUS - || GET_CODE (recog_operand[i]) == MULT) - recog_operand[i] = walk_alter_subreg (recog_operand[i]); - } - - for (i = 0; i < insn_n_dups[insn_code_number]; i++) - { - if (GET_CODE (*recog_dup_loc[i]) == SUBREG) - *recog_dup_loc[i] = alter_subreg (*recog_dup_loc[i]); - else if (GET_CODE (*recog_dup_loc[i]) == PLUS - || GET_CODE (*recog_dup_loc[i]) == MULT) - *recog_dup_loc[i] = walk_alter_subreg (*recog_dup_loc[i]); - } + extract_insn (insn); + cleanup_subreg_operands (insn); #ifdef REGISTER_CONSTRAINTS - if (! constrain_operands (insn_code_number, 1)) + if (! constrain_operands (1)) fatal_insn_not_found (insn); #endif @@ -2710,8 +2856,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) it is output. */ #ifdef FINAL_PRESCAN_INSN - FINAL_PRESCAN_INSN (insn, recog_operand, - insn_n_operands[insn_code_number]); + FINAL_PRESCAN_INSN (insn, recog_operand, recog_n_operands); #endif #ifdef HAVE_cc0 @@ -2761,7 +2906,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) /* If we didn't split the insn, go away. */ if (new == insn && PATTERN (new) == body) - abort (); + fatal_insn ("Could not split insn", insn); #ifdef HAVE_ATTR_length /* This instruction should have been split in shorten_branches, @@ -2878,6 +3023,35 @@ output_source_line (file, insn) } } + +/* For each operand in INSN, simplify (subreg (reg)) so that it refers + directly to the desired hard register. */ +void +cleanup_subreg_operands (insn) + rtx insn; +{ + int i; + + extract_insn (insn); + for (i = 0; i < recog_n_operands; i++) + { + if (GET_CODE (recog_operand[i]) == SUBREG) + recog_operand[i] = alter_subreg (recog_operand[i]); + else if (GET_CODE (recog_operand[i]) == PLUS + || GET_CODE (recog_operand[i]) == MULT) + recog_operand[i] = walk_alter_subreg (recog_operand[i]); + } + + for (i = 0; i < recog_n_dups; i++) + { + if (GET_CODE (*recog_dup_loc[i]) == SUBREG) + *recog_dup_loc[i] = alter_subreg (*recog_dup_loc[i]); + else if (GET_CODE (*recog_dup_loc[i]) == PLUS + || GET_CODE (*recog_dup_loc[i]) == MULT) + *recog_dup_loc[i] = walk_alter_subreg (*recog_dup_loc[i]); + } +} + /* If X is a SUBREG, replace it with a REG or a MEM, based on the thing it is a subreg of. */ @@ -2886,9 +3060,15 @@ alter_subreg (x) register rtx x; { register rtx y = SUBREG_REG (x); + if (GET_CODE (y) == SUBREG) y = alter_subreg (y); + /* If reload is operating, we may be replacing inside this SUBREG. + Check for that and make a new one if so. */ + if (reload_in_progress && find_replacement (&SUBREG_REG (x)) != 0) + x = copy_rtx (x); + if (GET_CODE (y) == REG) { /* If the word size is larger than the size of this register, @@ -2905,6 +3085,9 @@ alter_subreg (x) #else REGNO (x) = REGNO (y) + SUBREG_WORD (x); #endif + /* This field has a different meaning for REGs and SUBREGs. Make sure + to clear it! */ + x->used = 0; } else if (GET_CODE (y) == MEM) { @@ -2913,7 +3096,8 @@ alter_subreg (x) offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))) - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y)))); PUT_CODE (x, MEM); - MEM_VOLATILE_P (x) = MEM_VOLATILE_P (y); + MEM_COPY_ATTRIBUTES (x, y); + MEM_ALIAS_SET (x) = MEM_ALIAS_SET (y); XEXP (x, 0) = plus_constant (XEXP (y, 0), offset); } @@ -3115,12 +3299,12 @@ alter_cond (cond) void output_operand_lossage (str) - char *str; + const char *str; { if (this_is_asm_operands) error_for_asm (this_is_asm_operands, "invalid `asm': %s", str); else - abort (); + fatal ("Internal compiler error, output_operand_lossage `%s'", str); } /* Output of assembler code from a template, and its subroutines. */ @@ -3151,11 +3335,13 @@ output_asm_name () if (debug_insn) { register int num = INSN_CODE (debug_insn); - fprintf (asm_out_file, " %s %d %s", + fprintf (asm_out_file, "\t%s %d\t%s", ASM_COMMENT_START, INSN_UID (debug_insn), insn_name[num]); if (insn_n_alternatives[num] > 1) fprintf (asm_out_file, "/%d", which_alternative + 1); - +#ifdef HAVE_ATTR_length + fprintf (asm_out_file, "\t[length = %d]", get_attr_length (debug_insn)); +#endif /* Clear this so only the first assembler insn of any rtl insn will get the special comment for -dp. */ debug_insn = 0; @@ -3298,7 +3484,7 @@ output_asm_insn (template, operands) punctuation character alone, with no operand. The PRINT_OPERAND macro decides what is actually done. */ #ifdef PRINT_OPERAND_PUNCT_VALID_P - else if (PRINT_OPERAND_PUNCT_VALID_P (*p)) + else if (PRINT_OPERAND_PUNCT_VALID_P ((unsigned char)*p)) output_operand (NULL_RTX, *p++); #endif else @@ -3493,11 +3679,11 @@ output_addr_const (file, x) We handle alternate assembler dialects here, just like output_asm_insn. */ void -asm_fprintf VPROTO((FILE *file, char *p, ...)) +asm_fprintf VPROTO((FILE *file, const char *p, ...)) { -#ifndef __STDC__ +#ifndef ANSI_PROTOTYPES FILE *file; - char *p; + const char *p; #endif va_list argptr; char buf[10]; @@ -3505,9 +3691,9 @@ asm_fprintf VPROTO((FILE *file, char *p, ...)) VA_START (argptr, p); -#ifndef __STDC__ +#ifndef ANSI_PROTOTYPES file = va_arg (argptr, FILE *); - p = va_arg (argptr, char *); + p = va_arg (argptr, const char *); #endif buf[0] = '%'; @@ -3631,9 +3817,7 @@ asm_fprintf VPROTO((FILE *file, char *p, ...)) break; case 'U': -#ifdef USER_LABEL_PREFIX - fprintf (file, "%s", USER_LABEL_PREFIX); -#endif + fputs (user_label_prefix, file); break; default: @@ -3661,16 +3845,18 @@ split_double (value, first, second) if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD)) { /* In this case the CONST_INT holds both target words. - Extract the bits from it into two word-sized pieces. */ + Extract the bits from it into two word-sized pieces. + Sign extend each half to HOST_WIDE_INT. */ rtx low, high; - HOST_WIDE_INT word_mask; - /* Avoid warnings for shift count >= BITS_PER_WORD. */ - int shift_count = BITS_PER_WORD - 1; - - word_mask = (HOST_WIDE_INT) 1 << shift_count; - word_mask |= word_mask - 1; - low = GEN_INT (INTVAL (value) & word_mask); - high = GEN_INT ((INTVAL (value) >> (shift_count + 1)) & word_mask); + /* On machines where HOST_BITS_PER_WIDE_INT == BITS_PER_WORD + the shift below will cause a compiler warning, even though + this code won't be executed. So put the shift amounts in + variables to avoid the warning. */ + int rshift = HOST_BITS_PER_WIDE_INT - BITS_PER_WORD; + int lshift = HOST_BITS_PER_WIDE_INT - 2 * BITS_PER_WORD; + + low = GEN_INT ((INTVAL (value) << rshift) >> rshift); + high = GEN_INT ((INTVAL (value) << lshift) >> rshift); if (WORDS_BIG_ENDIAN) { *first = high; @@ -3825,11 +4011,16 @@ only_leaf_regs_used () int i; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - { - if ((regs_ever_live[i] || global_regs[i]) - && ! permitted_reg_in_leaf_functions[i]) - return 0; - } + if ((regs_ever_live[i] || global_regs[i]) + && ! permitted_reg_in_leaf_functions[i]) + return 0; + + if (current_function_uses_pic_offset_table + && pic_offset_table_rtx != 0 + && GET_CODE (pic_offset_table_rtx) == REG + && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)]) + return 0; + return 1; }