From e78d9500be1a9722b1936bab50706befa67ee6ca Mon Sep 17 00:00:00 2001 From: Jeffrey A Law <law@cygnus.com> Date: Wed, 10 Mar 1999 19:45:18 +0000 Subject: [PATCH] gcse.c (run_jump_opt_after_gcse): New variable. * gcse.c (run_jump_opt_after_gcse): New variable. (gcse_main): Returns an integer. (hash_scan_set): Record initializations from CONST_DOUBLEs too. (try_replace_reg): Update some comments. (cprop_insn): Allow propagation into some JUMP_INSNs too. * rtl.h (gcse_main): Update prototype. * toplev.c (rest_of_compilation): If gcse_main returns nonzero, then run a jump optimization pass. * jump.c (delete_barrier_successors): Delete nop jumps too. From-SVN: r25673 --- gcc/ChangeLog | 12 +++++ gcc/gcse.c | 120 +++++++++++++++++++++++++++++++++++++++++++++----- gcc/jump.c | 12 ++++- gcc/rtl.h | 2 +- gcc/toplev.c | 11 ++++- 5 files changed, 144 insertions(+), 13 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 93012fe9303f..6c0b0c2bd2c5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +Wed Mar 10 20:28:29 1999 Jeffrey A Law (law@cygnus.com) + + * gcse.c (run_jump_opt_after_gcse): New variable. + (gcse_main): Returns an integer. + (hash_scan_set): Record initializations from CONST_DOUBLEs too. + (try_replace_reg): Update some comments. + (cprop_insn): Allow propagation into some JUMP_INSNs too. + * rtl.h (gcse_main): Update prototype. + * toplev.c (rest_of_compilation): If gcse_main returns nonzero, + then run a jump optimization pass. + * jump.c (delete_barrier_successors): Delete nop jumps too. + Wed Mar 10 19:04:31 1999 J"orn Rennecke <amylaar@cygnus.co.uk> * sh.c (fp_arith_reg_operand): Actually test if reg is suitable diff --git a/gcc/gcse.c b/gcc/gcse.c index e9d4afae6613..a80570400d8d 100644 --- a/gcc/gcse.c +++ b/gcc/gcse.c @@ -188,7 +188,7 @@ yyy 4) Perform global cse. - 5) Perform another pass of copy/constant propagation [only if PRE]. + 5) Perform another pass of copy/constant propagation. Two passes of copy/constant propagation are done because the first one enables more GCSE and the second one helps to clean up the copies that @@ -333,6 +333,15 @@ static int_list_ptr *s_succs; static int *num_preds; static int *num_succs; +/* Note whether or not we should run jump optimization after gcse. We + want to do this for two cases. + + * If we changed any jumps via cprop. + + * If we added any labels via edge splitting. */ + +static int run_jump_opt_after_gcse; + /* Hash table of expressions. */ struct expr @@ -648,7 +657,7 @@ static void add_label_notes PROTO ((rtx, rtx)); /* Entry point for global common subexpression elimination. F is the first instruction in the function. */ -void +int gcse_main (f, file) rtx f; FILE *file; @@ -661,10 +670,12 @@ gcse_main (f, file) /* Point to release obstack data from for each pass. */ char *gcse_obstack_bottom; + run_jump_opt_after_gcse = 0; + /* It's impossible to construct a correct control flow graph in the presense of setjmp, so just punt to be safe. */ if (current_function_calls_setjmp) - return; + return 0; /* For calling dump_foo fns from gdb. */ debug_stderr = stderr; @@ -677,7 +688,7 @@ gcse_main (f, file) { /* Free storage allocated by find_basic_blocks. */ free_basic_block_vars (0); - return; + return 0; } /* See what modes support reg/reg copy operations. */ @@ -778,6 +789,7 @@ gcse_main (f, file) free_bb_mem (); /* Free storage allocated by find_basic_blocks. */ free_basic_block_vars (0); + return run_jump_opt_after_gcse; } /* Misc. utilities. */ @@ -1800,7 +1812,8 @@ hash_scan_set (pat, insn, set_p) && REGNO (src) >= FIRST_PSEUDO_REGISTER && can_copy_p [GET_MODE (dest)]) /* ??? CONST_INT:wip */ - || GET_CODE (src) == CONST_INT) + || GET_CODE (src) == CONST_INT + || GET_CODE (src) == CONST_DOUBLE) /* A copy is not available if its src or dest is subsequently modified. Here we want to search from INSN+1 on, but oprs_available_p searches from INSN on. */ @@ -3690,6 +3703,11 @@ static int try_replace_reg (from, to, insn) rtx from, to, insn; { + /* If this fails we could try to simplify the result of the + replacement and attempt to recognize the simplified insn. + + But we need a general simplify_rtx that doesn't have pass + specific state variables. I'm not aware of one at the moment. */ return validate_replace_src (from, to, insn); } @@ -3723,8 +3741,10 @@ cprop_insn (insn) struct reg_use *reg_used; int changed = 0; - /* ??? For now only propagate into SETs. */ - if (GET_CODE (insn) != INSN + /* Only propagate into SETs. Note that a conditional jump is a + SET with pc_rtx as the destination. */ + if ((GET_CODE (insn) != INSN + && GET_CODE (insn) != JUMP_INSN) || GET_CODE (PATTERN (insn)) != SET) return 0; @@ -3760,9 +3780,12 @@ cprop_insn (insn) abort (); src = SET_SRC (pat); - if (GET_CODE (src) == CONST_INT) + /* Constant propagation. */ + if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE) { - if (try_replace_reg (reg_used->reg_rtx, src, insn)) + /* Handle normal insns first. */ + if (GET_CODE (insn) == INSN + && try_replace_reg (reg_used->reg_rtx, src, insn)) { changed = 1; const_prop_count++; @@ -3770,13 +3793,90 @@ cprop_insn (insn) { fprintf (gcse_file, "CONST-PROP: Replacing reg %d in insn %d with constant ", regno, INSN_UID (insn)); - fprintf (gcse_file, HOST_WIDE_INT_PRINT_DEC, INTVAL (src)); + print_rtl (gcse_file, src); fprintf (gcse_file, "\n"); } /* The original insn setting reg_used may or may not now be deletable. We leave the deletion to flow. */ } + + /* Try to propagate a CONST_INT into a conditional jump. + We're pretty specific about what we will handle in this + code, we can extend this as necessary over time. + + Right now the insn in question must look like + + (set (pc) (if_then_else ...)) + + Note this does not currently handle machines which use cc0. */ + else if (GET_CODE (insn) == JUMP_INSN && condjump_p (insn)) + { + /* We want a copy of the JUMP_INSN so we can modify it + in-place as needed without effecting the original. */ + rtx copy = copy_rtx (insn); + rtx set = PATTERN (copy); + rtx temp; + + /* Replace the register with the appropriate constant. */ + replace_rtx (SET_SRC (set), reg_used->reg_rtx, src); + + temp = simplify_ternary_operation (GET_CODE (SET_SRC (set)), + GET_MODE (SET_SRC (set)), + GET_MODE (XEXP (SET_SRC (set), 0)), + XEXP (SET_SRC (set), 0), + XEXP (SET_SRC (set), 1), + XEXP (SET_SRC (set), 2)); + + /* If no simplification can be made, then try the next + register. */ + if (temp) + SET_SRC (set) = temp; + else + continue; + + /* That may have changed the structure of TEMP, so + force it to be rerecognized if it has not turned + into a nop or unconditional jump. */ + + INSN_CODE (copy) = -1; + if ((SET_DEST (set) == pc_rtx + && (SET_SRC (set) == pc_rtx + || GET_CODE (SET_SRC (set)) == LABEL_REF)) + || recog (PATTERN (copy), copy, NULL) >= 0) + { + /* This has either become an unconditional jump + or a nop-jump. We'd like to delete nop jumps + here, but doing so confuses gcse. So we just + make the replacement and let later passes + sort things out. */ + PATTERN (insn) = set; + INSN_CODE (insn) = -1; + + /* One less use of the label this insn used to jump to + if we turned this into a NOP jump. */ + if (SET_SRC (set) == pc_rtx && JUMP_LABEL (insn) != 0) + --LABEL_NUSES (JUMP_LABEL (insn)); + + /* If this has turned into an unconditional jump, + then put a barrier after it so that the unreachable + code will be deleted. */ + if (GET_CODE (SET_SRC (set)) == LABEL_REF) + emit_barrier_after (insn); + + run_jump_opt_after_gcse = 1; + + changed = 1; + const_prop_count++; + if (gcse_file != NULL) + { + fprintf (gcse_file, "CONST-PROP: Replacing reg %d in insn %d with constant ", + regno, INSN_UID (insn)); + print_rtl (gcse_file, src); + fprintf (gcse_file, "\n"); + } + } + } } else if (GET_CODE (src) == REG && REGNO (src) >= FIRST_PSEUDO_REGISTER diff --git a/gcc/jump.c b/gcc/jump.c index 7d25a97d3c5a..4ffeeff3f218 100644 --- a/gcc/jump.c +++ b/gcc/jump.c @@ -2076,7 +2076,9 @@ init_label_info (f) return largest_uid; } -/* Delete insns following barriers, up to next label. */ +/* Delete insns following barriers, up to next label. + + Also delete no-op jumps created by gcse. */ static void delete_barrier_successors (f) rtx f; @@ -2098,6 +2100,14 @@ delete_barrier_successors (f) } /* INSN is now the code_label. */ } + /* Also remove (set (pc) (pc)) insns which can be created by + gcse. We eliminate such insns now to avoid having them + cause problems later. */ + else if (GET_CODE (insn) == JUMP_INSN + && SET_SRC (PATTERN (insn)) == pc_rtx + && SET_DEST (PATTERN (insn)) == pc_rtx) + insn = delete_insn (insn); + else insn = NEXT_INSN (insn); } diff --git a/gcc/rtl.h b/gcc/rtl.h index bee3f052c3d2..7f4460f19346 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1452,7 +1452,7 @@ extern rtx expand_mult_highpart PROTO ((enum machine_mode, rtx, /* In gcse.c */ #ifdef BUFSIZ -extern void gcse_main PROTO ((rtx, FILE *)); +extern int gcse_main PROTO ((rtx, FILE *)); #endif /* In global.c */ diff --git a/gcc/toplev.c b/gcc/toplev.c index 2cc2885ca61f..f9a4c204ad13 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -3789,7 +3789,16 @@ rest_of_compilation (decl) if (gcse_dump) open_dump_file (".gcse", IDENTIFIER_POINTER (DECL_NAME (decl))); - TIMEVAR (gcse_time, gcse_main (insns, rtl_dump_file)); + TIMEVAR (gcse_time, tem = gcse_main (insns, rtl_dump_file)); + + /* If gcse altered any jumps, rerun jump optimizations to clean + things up. */ + if (tem) + { + TIMEVAR (jump_time, jump_optimize (insns, !JUMP_CROSS_JUMP, + !JUMP_NOOP_MOVES, + !JUMP_AFTER_REGSCAN)); + } if (gcse_dump) { -- GitLab