From a42a5f59d0f51034f35d3fe2fed40b8dd3540c37 Mon Sep 17 00:00:00 2001 From: Zack Weinberg Date: Sat, 20 Jan 2001 09:12:08 +0000 Subject: [PATCH] [multiple changes] 2001-01-20 Jakub Jelinek * function.c (fixup_var_refs): Move CALL_PLACEHOLDER handling... (fixup_var_refs_insns): ...here. * gcc.c-torture/compile/20010118-1.c: New test. 2001-01-20 Zack Weinberg * function.c (fixup_var_refs_insns): Break up into fixup_var_refs_insn [body of loop], fixup_var_refs_insns [loop over entire insn list], and fixup_var_refs_insns_with_hash [loop over hash table entries]. (fixup_var_refs): Adjust calls to fixup_var_refs_insns and/or fixup_var_refs_insns_with_hash, to match above changes. From-SVN: r39151 --- gcc/ChangeLog | 146 +++--- gcc/function.c | 487 ++++++++++-------- .../gcc.c-torture/compile/20010118-1.c | 21 + 3 files changed, 361 insertions(+), 293 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/compile/20010118-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 79444c1a472..46627c84cf5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2001-01-20 Jakub Jelinek + + * function.c (fixup_var_refs): Move CALL_PLACEHOLDER handling... + (fixup_var_refs_insns): ...here. + + * gcc.c-torture/compile/20010118-1.c: New test. + +2001-01-20 Zack Weinberg + + * function.c (fixup_var_refs_insns): Break up into + fixup_var_refs_insn [body of loop], fixup_var_refs_insns + [loop over entire insn list], and fixup_var_refs_insns_with_hash + [loop over hash table entries]. + (fixup_var_refs): Adjust calls to fixup_var_refs_insns and/or + fixup_var_refs_insns_with_hash, to match above changes. + 2001-01-19 John David Anglin * Makefile.in (ORDINARY_FLAGS_TO_PASS): Add MAKEOVERRIDES variable. @@ -12,7 +28,7 @@ 2001-01-19 Neil Booth - * cppinternals.texi: Update. + * cppinternals.texi: Update. 2001-01-19 Richard Earnshaw @@ -71,8 +87,8 @@ Thu Jan 18 06:43:04 2001 Richard Kenner 2001-01-18 Neil Booth - * cpplib.c (_cpp_handle_directive): Use buffer->was_skipping, - not pfile->skipping (== 0). + * cpplib.c (_cpp_handle_directive): Use buffer->was_skipping, + not pfile->skipping (== 0). 2001-01-17 Nick Clifton @@ -90,7 +106,7 @@ Thu Jan 18 06:43:04 2001 Richard Kenner 2001-01-17 Aldy Hernandez - * invoke.texi (-fno-guess-branch-probability): New option. + * invoke.texi (-fno-guess-branch-probability): New option. Wed Jan 17 13:26:34 2001 Richard Kenner @@ -152,7 +168,7 @@ Tue Jan 16 17:20:43 2001 Richard Kenner (movqi_internal, movhi_internal, movsi_internal, movdi_internal, movsf_internal, movdf_internal, movtf_internal, cmovdi_internal, cmovsi_internal): Delete ! TARGET_A_STEP check. - + 2001-01-16 Gerald Pfeifer * gcc.texi (Bug Lists): Do not mention newsgroups nor the @@ -165,7 +181,7 @@ Tue Jan 16 17:20:43 2001 Richard Kenner 2001-01-16 Alan Modra - * cppmain.c (general_init): Don't use ANSI prototype. + * cppmain.c (general_init): Don't use ANSI prototype. 2001-01-16 Tom Tromey @@ -268,7 +284,7 @@ Tue Jan 16 17:20:43 2001 Richard Kenner (emit_multi_reg_push): Don't record dwarf information for the pc. * arm.md (eh_epilogue): The function type may have changed, so it needs to be recalculated. - * arm/netbsd.h (DWARF2_UNWIND_INFO): Delete. Can now use dwarf2 + * arm/netbsd.h (DWARF2_UNWIND_INFO): Delete. Can now use dwarf2 unwind tables on arm/netbsd. 2001-01-15 Richard Earnshaw @@ -288,7 +304,7 @@ Tue Jan 16 17:20:43 2001 Richard Kenner 2001-01-15 Andreas Jaeger - * config/i386/i386.c (ix86_init_builtins): Make i size_t to remove + * config/i386/i386.c (ix86_init_builtins): Make i size_t to remove warnings. (ix86_expand_builtin): Likewise. @@ -301,8 +317,8 @@ Tue Jan 16 17:20:43 2001 Richard Kenner 2001-01-14 Ralf Baechle - * config/mips/linux.h (SUBTARGET_CPP_SPEC): Default ABI is 32; change - SUBTARGET_CPP_SPEC apropriatly. + * config/mips/linux.h (SUBTARGET_CPP_SPEC): Default ABI is 32; change + SUBTARGET_CPP_SPEC apropriatly. 2001-01-12 Mark Mitchell @@ -322,12 +338,12 @@ Sun Jan 14 22:31:30 2001 J"orn Rennecke 2001-01-14 Neil Booth - * c-parse.in (finish_parse): Add comment about cpp_destroy. - * cp/lex.c (finish_parse): Similarly. - * cppinit.c (cpp_cleanup): Rename cpp_destroy for clarity. - Return the number of errors encountered. - * cpplib.h (cpp_cleanup): Rename cpp_destroy, return int. - * cppmain.c (main): Don't call cpp_destroy. + * c-parse.in (finish_parse): Add comment about cpp_destroy. + * cp/lex.c (finish_parse): Similarly. + * cppinit.c (cpp_cleanup): Rename cpp_destroy for clarity. + Return the number of errors encountered. + * cpplib.h (cpp_cleanup): Rename cpp_destroy, return int. + * cppmain.c (main): Don't call cpp_destroy. 2001-01-14 Joseph S. Myers @@ -351,12 +367,12 @@ Sun Jan 14 22:31:30 2001 J"orn Rennecke 2001-01-14 Neil Booth - * cppmain.c (do_preprocessing): New function; most of the old - main. - (main): Call it to do most of the work. - (cb): Move from global scope to set_callbacks (). - (setup_callbacks): Get the callback pointer. - (general_init, printer_init): Clean up code and comments. + * cppmain.c (do_preprocessing): New function; most of the old + main. + (main): Call it to do most of the work. + (cb): Move from global scope to set_callbacks (). + (setup_callbacks): Get the callback pointer. + (general_init, printer_init): Clean up code and comments. 2001-01-14 Richard Earnshaw @@ -491,11 +507,11 @@ Sun Jan 14 00:23:15 2001 Denis Chertykov 2001-01-13 Neil Booth - * cppfiles.c (_cpp_fake_include): New function. - * cpphash.h (_cpp_fake_include): New. - * cpplib.c (do_line): Call _cpp_fake_include when entering - header files in preprocessed input. - * cppmain.c (cb_pragma_implementation): Remove handling. + * cppfiles.c (_cpp_fake_include): New function. + * cpphash.h (_cpp_fake_include): New. + * cpplib.c (do_line): Call _cpp_fake_include when entering + header files in preprocessed input. + * cppmain.c (cb_pragma_implementation): Remove handling. (setup_callbacks): Don't register pragmas. 2001-01-13 Neil Booth @@ -510,35 +526,35 @@ Sun Jan 14 00:23:15 2001 Denis Chertykov 2001-01-13 Neil Booth - * cpplib.h (cpp_pool, mi_state, mi_ind, struct cpp_macro, - struct cpp_chunk, struct htab, struct toklist, - struct cpp_context, CPP_STACK_MAX, struct lexer_state, - struct spec_nodes, struct cpp_reader, CPP_OPTION, CPP_BUFFER, - CPP_BUF_LINE, CPP_BUF_COL, CPP_BUF_COLUMN, U, ustrcmp, ustrncmp, - ustrlen, uxstrdup, ustrchr, ufputs): Move to cpphash.h. - (struct macro_args): Delete. - * cpphash.h: See above. + * cpplib.h (cpp_pool, mi_state, mi_ind, struct cpp_macro, + struct cpp_chunk, struct htab, struct toklist, + struct cpp_context, CPP_STACK_MAX, struct lexer_state, + struct spec_nodes, struct cpp_reader, CPP_OPTION, CPP_BUFFER, + CPP_BUF_LINE, CPP_BUF_COL, CPP_BUF_COLUMN, U, ustrcmp, ustrncmp, + ustrlen, uxstrdup, ustrchr, ufputs): Move to cpphash.h. + (struct macro_args): Delete. + * cpphash.h: See above. 2001-01-13 Neil Booth - * cppmain.c (struct printer): Remove no_line_dirs. - (options, cb): New. - (main, setup_callbacks, scan_buffer, printer_init, cb_define) - : Use options rather than CPP_OPTION. - (setup_callbacks): Use cb rather than pfile->cb. - (main): No need to check for a buffer. Use cpp_errors. - (printer_init): Don't set no_line_dirs. - (maybe_print_line): Use options not no_line_dirs. - (cb_file_change): Don't call print_line if -P. + * cppmain.c (struct printer): Remove no_line_dirs. + (options, cb): New. + (main, setup_callbacks, scan_buffer, printer_init, cb_define) + : Use options rather than CPP_OPTION. + (setup_callbacks): Use cb rather than pfile->cb. + (main): No need to check for a buffer. Use cpp_errors. + (printer_init): Don't set no_line_dirs. + (maybe_print_line): Use options not no_line_dirs. + (cb_file_change): Don't call print_line if -P. 2001-01-13 Neil Booth - * c-lex.c (init_c_lex): Use cpp_get_callbacks to set - callbacks. - * c-parse.in (finish_parse): Use cpp_errors. - (__yylex): Use return value of cpp_pop_buffer. - * cp/lex.c (finish_parse): Use cpp_errors. - * cp/spew.c (read_token): Use return value of cpp_pop_buffer. + * c-lex.c (init_c_lex): Use cpp_get_callbacks to set + callbacks. + * c-parse.in (finish_parse): Use cpp_errors. + (__yylex): Use return value of cpp_pop_buffer. + * cp/lex.c (finish_parse): Use cpp_errors. + * cp/spew.c (read_token): Use return value of cpp_pop_buffer. Sat Jan 13 16:57:40 2001 Denis Chertykov @@ -592,24 +608,24 @@ Sat Jan 13 09:53:32 MET 2001 Jan Hubicka 2001-01-13 Neil Booth - * fix-header.c (read_scan_file): Use cpp_get_callbacks and - cpp_get_options rather than dereferencing pfile and using - CPP_OPTION. - * scan-decls.c (scan_decls): Use return value of - cpp_pop_buffer rather than CPP_BUFFER. + * fix-header.c (read_scan_file): Use cpp_get_callbacks and + cpp_get_options rather than dereferencing pfile and using + CPP_OPTION. + * scan-decls.c (scan_decls): Use return value of + cpp_pop_buffer rather than CPP_BUFFER. 2001-01-13 Neil Booth - * cppinit.c (cpp_handle_option): help_only is now part of the - cpp_options structure. - * cpplib.c (cpp_errors, cpp_get_options, cpp_get_callbacks, - cpp_set_callbacks): New functions. - * cpplib.h (cpp_callbacks): Break out as a named structure. - (cpp_options): Move help_only here from cpp_reader. - (CPP_FATAL_ERRORS): Update to use cpp_errors. - (cpp_errors, cpp_get_options, cpp_get_callbacks, - cpp_set_callbacks): New prototypes. - * cppmain.c (main): Update for help_only. + * cppinit.c (cpp_handle_option): help_only is now part of the + cpp_options structure. + * cpplib.c (cpp_errors, cpp_get_options, cpp_get_callbacks, + cpp_set_callbacks): New functions. + * cpplib.h (cpp_callbacks): Break out as a named structure. + (cpp_options): Move help_only here from cpp_reader. + (CPP_FATAL_ERRORS): Update to use cpp_errors. + (cpp_errors, cpp_get_options, cpp_get_callbacks, + cpp_set_callbacks): New prototypes. + * cppmain.c (main): Update for help_only. 2001-01-13 Joseph S. Myers diff --git a/gcc/function.c b/gcc/function.c index 22a5a74dea0..8e7eeae372b 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -253,8 +253,13 @@ static void fixup_var_refs PARAMS ((rtx, enum machine_mode, int, struct hash_table *)); static struct fixup_replacement *find_fixup_replacement PARAMS ((struct fixup_replacement **, rtx)); -static void fixup_var_refs_insns PARAMS ((rtx, enum machine_mode, int, - rtx, int, struct hash_table *)); +static void fixup_var_refs_insns PARAMS ((rtx, rtx, enum machine_mode, + int, int)); +static void fixup_var_refs_insns_with_hash + PARAMS ((struct hash_table *, rtx, + enum machine_mode, int)); +static void fixup_var_refs_insn PARAMS ((rtx, rtx, enum machine_mode, + int, int)); static void fixup_var_refs_1 PARAMS ((rtx, enum machine_mode, rtx *, rtx, struct fixup_replacement **)); static rtx fixup_memory_subreg PARAMS ((rtx, rtx, int)); @@ -1542,21 +1547,25 @@ fixup_var_refs (var, promoted_mode, unsignedp, ht) rtx first_insn = get_insns (); struct sequence_stack *stack = seq_stack; tree rtl_exps = rtl_expr_chain; - rtx insn; - /* Must scan all insns for stack-refs that exceed the limit. */ - fixup_var_refs_insns (var, promoted_mode, unsignedp, first_insn, - stack == 0, ht); /* If there's a hash table, it must record all uses of VAR. */ if (ht) - return; + { + if (stack != 0) + abort (); + fixup_var_refs_insns_with_hash (ht, var, promoted_mode, unsignedp); + return; + } + + fixup_var_refs_insns (first_insn, var, promoted_mode, unsignedp, + stack == 0); /* Scan all pending sequences too. */ for (; stack; stack = stack->next) { push_to_full_sequence (stack->first, stack->last); - fixup_var_refs_insns (var, promoted_mode, unsignedp, - stack->first, stack->next != 0, 0); + fixup_var_refs_insns (stack->first, var, promoted_mode, unsignedp, + stack->next != 0); /* Update remembered end of sequence in case we added an insn at the end. */ stack->last = get_last_insn (); @@ -1570,40 +1579,15 @@ fixup_var_refs (var, promoted_mode, unsignedp, ht) if (seq != const0_rtx && seq != 0) { push_to_sequence (seq); - fixup_var_refs_insns (var, promoted_mode, unsignedp, seq, 0, 0); + fixup_var_refs_insns (seq, var, promoted_mode, unsignedp, 0); end_sequence (); } } /* Scan the catch clauses for exception handling too. */ push_to_full_sequence (catch_clauses, catch_clauses_last); - fixup_var_refs_insns (var, promoted_mode, unsignedp, catch_clauses, 0, 0); + fixup_var_refs_insns (catch_clauses, var, promoted_mode, unsignedp, 0); end_full_sequence (&catch_clauses, &catch_clauses_last); - - /* Scan sequences saved in CALL_PLACEHOLDERS too. */ - for (insn = first_insn; insn; insn = NEXT_INSN (insn)) - { - if (GET_CODE (insn) == CALL_INSN - && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) - { - int i; - - /* Look at the Normal call, sibling call and tail recursion - sequences attached to the CALL_PLACEHOLDER. */ - for (i = 0; i < 3; i++) - { - rtx seq = XEXP (PATTERN (insn), i); - if (seq) - { - push_to_sequence (seq); - fixup_var_refs_insns (var, promoted_mode, unsignedp, - seq, 0, 0); - XEXP (PATTERN (insn), i) = get_insns (); - end_sequence (); - } - } - } - } } /* REPLACEMENTS is a pointer to a list of the struct fixup_replacement and X is @@ -1638,218 +1622,265 @@ find_fixup_replacement (replacements, x) main chain of insns for the current function. */ static void -fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel, ht) +fixup_var_refs_insns (insn, var, promoted_mode, unsignedp, toplevel) + rtx insn; rtx var; enum machine_mode promoted_mode; int unsignedp; - rtx insn; int toplevel; - struct hash_table *ht; { - rtx call_dest = 0; - rtx insn_list = NULL_RTX; - - /* If we already know which INSNs reference VAR there's no need - to walk the entire instruction chain. */ - if (ht) - { - insn_list = ((struct insns_for_mem_entry *) - hash_lookup (ht, var, /*create=*/0, /*copy=*/0))->insns; - insn = insn_list ? XEXP (insn_list, 0) : NULL_RTX; - insn_list = XEXP (insn_list, 1); - } - while (insn) { + /* fixup_var_refs_insn might modify insn, so save its next + pointer now. */ rtx next = NEXT_INSN (insn); - rtx set, prev, prev_set; - rtx note; + /* CALL_PLACEHOLDERs are special; we have to switch into each of + the three sequences they (potentially) contain, and process + them recursively. The CALL_INSN itself is not interesting. */ + + if (GET_CODE (insn) == CALL_INSN + && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) + { + int i; + + /* Look at the Normal call, sibling call and tail recursion + sequences attached to the CALL_PLACEHOLDER. */ + for (i = 0; i < 3; i++) + { + rtx seq = XEXP (PATTERN (insn), i); + if (seq) + { + push_to_sequence (seq); + fixup_var_refs_insns (seq, var, promoted_mode, unsignedp, 0); + XEXP (PATTERN (insn), i) = get_insns (); + end_sequence (); + } + } + } + + else if (INSN_P (insn)) + fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel); + + insn = next; + } +} + +/* Look up the insns which reference VAR in HT and fix them up. Other + arguments are the same as fixup_var_refs_insns. + + N.B. No need for special processing of CALL_PLACEHOLDERs here, + because the hash table will point straight to the interesting insn + (inside the CALL_PLACEHOLDER). */ +static void +fixup_var_refs_insns_with_hash (ht, var, promoted_mode, unsignedp) + struct hash_table *ht; + rtx var; + enum machine_mode promoted_mode; + int unsignedp; +{ + struct insns_for_mem_entry *ime = (struct insns_for_mem_entry *) + hash_lookup (ht, var, /*create=*/0, /*copy=*/0); + rtx insn_list = ime->insns; + + while (insn_list) + { + rtx insn = XEXP (insn_list, 0); + if (INSN_P (insn)) + fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, 0); + + insn_list = XEXP (insn_list, 1); + } +} + + +/* Per-insn processing by fixup_var_refs_insns(_with_hash). INSN is + the insn under examination, VAR is the variable to fix up + references to, PROMOTED_MODE and UNSIGNEDP describe VAR, and + TOPLEVEL is nonzero if this is the main insn chain for this + function. */ +static void +fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel) + rtx insn; + rtx var; + enum machine_mode promoted_mode; + int unsignedp; + int toplevel; +{ + rtx call_dest = 0; + rtx set, prev, prev_set; + rtx note; + + /* Remember the notes in case we delete the insn. */ + note = REG_NOTES (insn); + + /* If this is a CLOBBER of VAR, delete it. + + If it has a REG_LIBCALL note, delete the REG_LIBCALL + and REG_RETVAL notes too. */ + if (GET_CODE (PATTERN (insn)) == CLOBBER + && (XEXP (PATTERN (insn), 0) == var + || (GET_CODE (XEXP (PATTERN (insn), 0)) == CONCAT + && (XEXP (XEXP (PATTERN (insn), 0), 0) == var + || XEXP (XEXP (PATTERN (insn), 0), 1) == var)))) + { + if ((note = find_reg_note (insn, REG_LIBCALL, NULL_RTX)) != 0) + /* The REG_LIBCALL note will go away since we are going to + turn INSN into a NOTE, so just delete the + corresponding REG_RETVAL note. */ + remove_note (XEXP (note, 0), + find_reg_note (XEXP (note, 0), REG_RETVAL, + NULL_RTX)); + + /* In unoptimized compilation, we shouldn't call delete_insn + except in jump.c doing warnings. */ + PUT_CODE (insn, NOTE); + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (insn) = 0; + } + + /* The insn to load VAR from a home in the arglist + is now a no-op. When we see it, just delete it. + Similarly if this is storing VAR from a register from which + it was loaded in the previous insn. This will occur + when an ADDRESSOF was made for an arglist slot. */ + else if (toplevel + && (set = single_set (insn)) != 0 + && SET_DEST (set) == var + /* If this represents the result of an insn group, + don't delete the insn. */ + && find_reg_note (insn, REG_RETVAL, NULL_RTX) == 0 + && (rtx_equal_p (SET_SRC (set), var) + || (GET_CODE (SET_SRC (set)) == REG + && (prev = prev_nonnote_insn (insn)) != 0 + && (prev_set = single_set (prev)) != 0 + && SET_DEST (prev_set) == SET_SRC (set) + && rtx_equal_p (SET_SRC (prev_set), var)))) + { + /* In unoptimized compilation, we shouldn't call delete_insn + except in jump.c doing warnings. */ + PUT_CODE (insn, NOTE); + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (insn) = 0; + } + else + { + struct fixup_replacement *replacements = 0; + rtx next_insn = NEXT_INSN (insn); + + if (SMALL_REGISTER_CLASSES) { - /* Remember the notes in case we delete the insn. */ - note = REG_NOTES (insn); + /* If the insn that copies the results of a CALL_INSN + into a pseudo now references VAR, we have to use an + intermediate pseudo since we want the life of the + return value register to be only a single insn. - /* If this is a CLOBBER of VAR, delete it. + If we don't use an intermediate pseudo, such things as + address computations to make the address of VAR valid + if it is not can be placed between the CALL_INSN and INSN. - If it has a REG_LIBCALL note, delete the REG_LIBCALL - and REG_RETVAL notes too. */ - if (GET_CODE (PATTERN (insn)) == CLOBBER - && (XEXP (PATTERN (insn), 0) == var - || (GET_CODE (XEXP (PATTERN (insn), 0)) == CONCAT - && (XEXP (XEXP (PATTERN (insn), 0), 0) == var - || XEXP (XEXP (PATTERN (insn), 0), 1) == var)))) + To make sure this doesn't happen, we record the destination + of the CALL_INSN and see if the next insn uses both that + and VAR. */ + + if (call_dest != 0 && GET_CODE (insn) == INSN + && reg_mentioned_p (var, PATTERN (insn)) + && reg_mentioned_p (call_dest, PATTERN (insn))) { - if ((note = find_reg_note (insn, REG_LIBCALL, NULL_RTX)) != 0) - /* The REG_LIBCALL note will go away since we are going to - turn INSN into a NOTE, so just delete the - corresponding REG_RETVAL note. */ - remove_note (XEXP (note, 0), - find_reg_note (XEXP (note, 0), REG_RETVAL, - NULL_RTX)); + rtx temp = gen_reg_rtx (GET_MODE (call_dest)); - /* In unoptimized compilation, we shouldn't call delete_insn - except in jump.c doing warnings. */ - PUT_CODE (insn, NOTE); - NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; - NOTE_SOURCE_FILE (insn) = 0; + emit_insn_before (gen_move_insn (temp, call_dest), insn); + + PATTERN (insn) = replace_rtx (PATTERN (insn), + call_dest, temp); } - /* The insn to load VAR from a home in the arglist - is now a no-op. When we see it, just delete it. - Similarly if this is storing VAR from a register from which - it was loaded in the previous insn. This will occur - when an ADDRESSOF was made for an arglist slot. */ - else if (toplevel - && (set = single_set (insn)) != 0 - && SET_DEST (set) == var - /* If this represents the result of an insn group, - don't delete the insn. */ - && find_reg_note (insn, REG_RETVAL, NULL_RTX) == 0 - && (rtx_equal_p (SET_SRC (set), var) - || (GET_CODE (SET_SRC (set)) == REG - && (prev = prev_nonnote_insn (insn)) != 0 - && (prev_set = single_set (prev)) != 0 - && SET_DEST (prev_set) == SET_SRC (set) - && rtx_equal_p (SET_SRC (prev_set), var)))) - { - /* In unoptimized compilation, we shouldn't call delete_insn - except in jump.c doing warnings. */ - PUT_CODE (insn, NOTE); - NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; - NOTE_SOURCE_FILE (insn) = 0; - if (insn == last_parm_insn) - last_parm_insn = PREV_INSN (next); - } + if (GET_CODE (insn) == CALL_INSN + && GET_CODE (PATTERN (insn)) == SET) + call_dest = SET_DEST (PATTERN (insn)); + else if (GET_CODE (insn) == CALL_INSN + && GET_CODE (PATTERN (insn)) == PARALLEL + && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) + call_dest = SET_DEST (XVECEXP (PATTERN (insn), 0, 0)); else - { - struct fixup_replacement *replacements = 0; - rtx next_insn = NEXT_INSN (insn); - - if (SMALL_REGISTER_CLASSES) - { - /* If the insn that copies the results of a CALL_INSN - into a pseudo now references VAR, we have to use an - intermediate pseudo since we want the life of the - return value register to be only a single insn. - - If we don't use an intermediate pseudo, such things as - address computations to make the address of VAR valid - if it is not can be placed between the CALL_INSN and INSN. - - To make sure this doesn't happen, we record the destination - of the CALL_INSN and see if the next insn uses both that - and VAR. */ - - if (call_dest != 0 && GET_CODE (insn) == INSN - && reg_mentioned_p (var, PATTERN (insn)) - && reg_mentioned_p (call_dest, PATTERN (insn))) - { - rtx temp = gen_reg_rtx (GET_MODE (call_dest)); - - emit_insn_before (gen_move_insn (temp, call_dest), insn); - - PATTERN (insn) = replace_rtx (PATTERN (insn), - call_dest, temp); - } - - if (GET_CODE (insn) == CALL_INSN - && GET_CODE (PATTERN (insn)) == SET) - call_dest = SET_DEST (PATTERN (insn)); - else if (GET_CODE (insn) == CALL_INSN - && GET_CODE (PATTERN (insn)) == PARALLEL - && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) - call_dest = SET_DEST (XVECEXP (PATTERN (insn), 0, 0)); - else - call_dest = 0; - } - - /* See if we have to do anything to INSN now that VAR is in - memory. If it needs to be loaded into a pseudo, use a single - pseudo for the entire insn in case there is a MATCH_DUP - between two operands. We pass a pointer to the head of - a list of struct fixup_replacements. If fixup_var_refs_1 - needs to allocate pseudos or replacement MEMs (for SUBREGs), - it will record them in this list. - - If it allocated a pseudo for any replacement, we copy into - it here. */ - - fixup_var_refs_1 (var, promoted_mode, &PATTERN (insn), insn, - &replacements); - - /* If this is last_parm_insn, and any instructions were output - after it to fix it up, then we must set last_parm_insn to - the last such instruction emitted. */ - if (insn == last_parm_insn) - last_parm_insn = PREV_INSN (next_insn); - - while (replacements) - { - struct fixup_replacement *next; - - if (GET_CODE (replacements->new) == REG) - { - rtx insert_before; - rtx seq; - - /* OLD might be a (subreg (mem)). */ - if (GET_CODE (replacements->old) == SUBREG) - replacements->old - = fixup_memory_subreg (replacements->old, insn, 0); - else - replacements->old - = fixup_stack_1 (replacements->old, insn); - - insert_before = insn; - - /* If we are changing the mode, do a conversion. - This might be wasteful, but combine.c will - eliminate much of the waste. */ - - if (GET_MODE (replacements->new) - != GET_MODE (replacements->old)) - { - start_sequence (); - convert_move (replacements->new, - replacements->old, unsignedp); - seq = gen_sequence (); - end_sequence (); - } - else - seq = gen_move_insn (replacements->new, - replacements->old); - - emit_insn_before (seq, insert_before); - } - - next = replacements->next; - free (replacements); - replacements = next; - } - } - - /* Also fix up any invalid exprs in the REG_NOTES of this insn. - But don't touch other insns referred to by reg-notes; - we will get them elsewhere. */ - while (note) - { - if (GET_CODE (note) != INSN_LIST) - XEXP (note, 0) - = walk_fixup_memory_subreg (XEXP (note, 0), insn, 1); - note = XEXP (note, 1); - } + call_dest = 0; } - if (!ht) - insn = next; - else if (insn_list) + /* See if we have to do anything to INSN now that VAR is in + memory. If it needs to be loaded into a pseudo, use a single + pseudo for the entire insn in case there is a MATCH_DUP + between two operands. We pass a pointer to the head of + a list of struct fixup_replacements. If fixup_var_refs_1 + needs to allocate pseudos or replacement MEMs (for SUBREGs), + it will record them in this list. + + If it allocated a pseudo for any replacement, we copy into + it here. */ + + fixup_var_refs_1 (var, promoted_mode, &PATTERN (insn), insn, + &replacements); + + /* If this is last_parm_insn, and any instructions were output + after it to fix it up, then we must set last_parm_insn to + the last such instruction emitted. */ + if (insn == last_parm_insn) + last_parm_insn = PREV_INSN (next_insn); + + while (replacements) { - insn = XEXP (insn_list, 0); - insn_list = XEXP (insn_list, 1); + struct fixup_replacement *next; + + if (GET_CODE (replacements->new) == REG) + { + rtx insert_before; + rtx seq; + + /* OLD might be a (subreg (mem)). */ + if (GET_CODE (replacements->old) == SUBREG) + replacements->old + = fixup_memory_subreg (replacements->old, insn, 0); + else + replacements->old + = fixup_stack_1 (replacements->old, insn); + + insert_before = insn; + + /* If we are changing the mode, do a conversion. + This might be wasteful, but combine.c will + eliminate much of the waste. */ + + if (GET_MODE (replacements->new) + != GET_MODE (replacements->old)) + { + start_sequence (); + convert_move (replacements->new, + replacements->old, unsignedp); + seq = gen_sequence (); + end_sequence (); + } + else + seq = gen_move_insn (replacements->new, + replacements->old); + + emit_insn_before (seq, insert_before); + } + + next = replacements->next; + free (replacements); + replacements = next; } - else - insn = NULL_RTX; + } + + /* Also fix up any invalid exprs in the REG_NOTES of this insn. + But don't touch other insns referred to by reg-notes; + we will get them elsewhere. */ + while (note) + { + if (GET_CODE (note) != INSN_LIST) + XEXP (note, 0) + = walk_fixup_memory_subreg (XEXP (note, 0), insn, 1); + note = XEXP (note, 1); } } @@ -1861,7 +1892,7 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel, ht) to modify this insn by replacing a memory reference with a pseudo or by making a new MEM to implement a SUBREG, we consult that list to see if we have already chosen a replacement. If none has already been allocated, - we allocate it and update the list. fixup_var_refs_insns will copy VAR + we allocate it and update the list. fixup_var_refs_insn will copy VAR or the SUBREG, as appropriate, to the pseudo. */ static void @@ -4564,7 +4595,7 @@ assign_parms (fndecl) && GET_CODE (XEXP (XVECEXP (entry_parm, 0, i), 0)) == REG && (GET_MODE (XEXP (XVECEXP (entry_parm, 0, i), 0)) == passed_mode) - && INTVAL (XEXP (XVECEXP (entry_parm, 0, i), 1)) == 0) + && XINT (XEXP (XVECEXP (entry_parm, 0, i), 1), 0) == 0) { entry_parm = XEXP (XVECEXP (entry_parm, 0, i), 0); DECL_INCOMING_RTL (parm) = entry_parm; diff --git a/gcc/testsuite/gcc.c-torture/compile/20010118-1.c b/gcc/testsuite/gcc.c-torture/compile/20010118-1.c new file mode 100644 index 00000000000..6d1fc6431c6 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20010118-1.c @@ -0,0 +1,21 @@ +static unsigned int bar(void *h, unsigned int n) +{ + static int i; + return i++; +} + +static void baz(unsigned int *x) +{ + (*x)++; +} + +long +foo(void *h, unsigned int l) +{ + unsigned int n; + long m; + n = bar(h, 0); + n = bar(h, n); + m = ({ baz(&n); 21; }); + return m; +}