diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7ce74962c71..7c2267c670c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2002-02-09 Alexandre Oliva + + * hooks.c: New file. + * hooks.h: New file. + * Makefile.in (HOOKS_H): New. + (TARGET_DEF_H): Added $(HOOKS_H). + (OBJS): Added hooks.o. + (cfgcleanup.o, bb-reorder.o): Added target.h. + (hooks.o): Added dependencies. + * target-def.h (TARGET_CANNOT_MODIFY_JUMPS_P): New, added to... + (TARGET_INITIALIZER): this. + * doc/tm.texi (TARGET_CANNOT_MODIFY_JUMPS_P): Document. + * target.h (struct gcc_target): Added cannot_modify_jumps_p. + * bb-reorder.c: Include target.h. + (reorder_basic_blocks): Skip if cannot modify jumps. + * cfgcleanup.c: Include target.h. + (try_optimize_cfg): Skip merge blocking if cannot modify jumps. + 2002-02-08 Chris Demetriou * config/mips/mips.md (casesi_internal, casesi_internal_di): diff --git a/gcc/Makefile.in b/gcc/Makefile.in index f21ed3df33d..59f1d3aff3d 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -543,7 +543,8 @@ HCONFIG_H = hconfig.h $(build_xm_file_list) CONFIG_H = $(GCONFIG_H) insn-constants.h insn-flags.h TCONFIG_H = tconfig.h $(xm_file_list) TARGET_H = target.h -TARGET_DEF_H = target-def.h +HOOKS_H = hooks.h +TARGET_DEF_H = target-def.h $(HOOKS_H) TM_P_H = tm_p.h $(tm_p_file_list) tm-preds.h MACHMODE_H = machmode.h machmode.def @@ -718,7 +719,7 @@ OBJS = alias.o bb-reorder.o bitmap.o builtins.o caller-save.o calls.o \ df.o diagnostic.o doloop.o dominance.o dwarf2asm.o dwarf2out.o dwarfout.o \ emit-rtl.o except.o explow.o expmed.o expr.o final.o flow.o \ fold-const.o function.o gcse.o genrtl.o ggc-common.o global.o graph.o \ - haifa-sched.o hash.o hashtable.o ifcvt.o insn-attrtab.o insn-emit.o \ + haifa-sched.o hash.o hashtable.o hooks.o ifcvt.o insn-attrtab.o insn-emit.o \ insn-extract.o insn-opinit.o insn-output.o insn-peep.o insn-recog.o \ integrate.o intl.o jump.o langhooks.o lcm.o lists.o local-alloc.o \ loop.o mbchar.o optabs.o params.o predict.o print-rtl.o print-tree.o \ @@ -1495,7 +1496,7 @@ cfgbuild.o : cfgbuild.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) flags.h insn-config.h \ function.h except.h $(GGC_H) cfgcleanup.o : cfgcleanup.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TIMEVAR_H)\ $(BASIC_BLOCK_H) hard-reg-set.h output.h flags.h $(RECOG_H) toplev.h \ - $(GGC_H) insn-config.h cselib.h $(TM_P_H) + $(GGC_H) insn-config.h cselib.h $(TARGET_H) $(TM_P_H) cfgloop.o : cfgloop.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \ $(BASIC_BLOCK_H) hard-reg-set.h dominance.o : dominance.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) hard-reg-set.h \ @@ -1564,8 +1565,8 @@ predict.o: predict.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \ insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h \ $(RECOG_H) function.h except.h $(EXPR_H) $(TM_P_H) $(PREDICT_H) lists.o: lists.c $(CONFIG_H) $(SYSTEM_H) toplev.h $(RTL_H) $(GGC_H) -bb-reorder.o : bb-reorder.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \ - $(BASIC_BLOCK_H) hard-reg-set.h output.h cfglayout.h +bb-reorder.o : bb-reorder.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) \ + flags.h $(BASIC_BLOCK_H) hard-reg-set.h output.h cfglayout.h $(TARGET_H) cfglayout.o : cfglayout.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) \ insn-config.h $(BASIC_BLOCK_H) hard-reg-set.h output.h function.h \ cfglayout.h @@ -1579,6 +1580,7 @@ ifcvt.o : ifcvt.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(REGS_H) toplev.h \ dependence.o : dependence.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) \ $(C_COMMON_H) flags.h varray.h $(EXPR_H) params.o : params.c $(CONFIG_H) $(SYSTEM_H) $(PARAMS_H) toplev.h +hooks.o: hooks.c $(CONFIG_H) $(SYSTEM_H) $(HOOKS_H) $(out_object_file): $(out_file) $(CONFIG_H) $(TREE_H) $(GGC_H) \ $(RTL_H) $(REGS_H) hard-reg-set.h real.h insn-config.h conditions.h \ diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c index 97ad1426b36..2578604889e 100644 --- a/gcc/bb-reorder.c +++ b/gcc/bb-reorder.c @@ -1,5 +1,5 @@ /* Basic block reordering routines for the GNU compiler. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2002 Free Software Foundation, Inc. This file is part of GCC. @@ -89,6 +89,7 @@ #include "flags.h" #include "output.h" #include "cfglayout.h" +#include "target.h" /* Local function prototypes. */ static void make_reorder_chain PARAMS ((void)); @@ -260,6 +261,9 @@ reorder_basic_blocks () if (n_basic_blocks <= 1) return; + if ((* targetm.cannot_modify_jumps_p) ()) + return; + cfg_layout_initialize (); make_reorder_chain (); diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c index 13c5a8e1352..d9f9cf261e5 100644 --- a/gcc/cfgcleanup.c +++ b/gcc/cfgcleanup.c @@ -44,6 +44,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "toplev.h" #include "cselib.h" #include "tm_p.h" +#include "target.h" #include "obstack.h" @@ -1531,149 +1532,158 @@ try_optimize_cfg (mode) for (i = 0; i < n_basic_blocks; i++) update_forwarder_flag (BASIC_BLOCK (i)); - /* Attempt to merge blocks as made possible by edge removal. If a block - has only one successor, and the successor has only one predecessor, - they may be combined. */ - do + if (! (* targetm.cannot_modify_jumps_p) ()) { - changed = false; - iterations++; - - if (rtl_dump_file) - fprintf (rtl_dump_file, "\n\ntry_optimize_cfg iteration %i\n\n", - iterations); - - for (i = 0; i < n_basic_blocks;) + /* Attempt to merge blocks as made possible by edge removal. If + a block has only one successor, and the successor has only + one predecessor, they may be combined. */ + do { - basic_block c, b = BASIC_BLOCK (i); - edge s; - bool changed_here = false; + changed = false; + iterations++; - /* Delete trivially dead basic blocks. */ - while (b->pred == NULL) + if (rtl_dump_file) + fprintf (rtl_dump_file, + "\n\ntry_optimize_cfg iteration %i\n\n", + iterations); + + for (i = 0; i < n_basic_blocks;) { - c = BASIC_BLOCK (b->index - 1); - if (rtl_dump_file) - fprintf (rtl_dump_file, "Deleting block %i.\n", b->index); + basic_block c, b = BASIC_BLOCK (i); + edge s; + bool changed_here = false; - flow_delete_block (b); - changed = true; - b = c; + /* Delete trivially dead basic blocks. */ + while (b->pred == NULL) + { + c = BASIC_BLOCK (b->index - 1); + if (rtl_dump_file) + fprintf (rtl_dump_file, "Deleting block %i.\n", + b->index); + + flow_delete_block (b); + changed = true; + b = c; + } + + /* Remove code labels no longer used. Don't do this + before CALL_PLACEHOLDER is removed, as some branches + may be hidden within. */ + if (b->pred->pred_next == NULL + && (b->pred->flags & EDGE_FALLTHRU) + && !(b->pred->flags & EDGE_COMPLEX) + && GET_CODE (b->head) == CODE_LABEL + && (!(mode & CLEANUP_PRE_SIBCALL) + || !tail_recursion_label_p (b->head)) + /* If the previous block ends with a branch to this + block, we can't delete the label. Normally this + is a condjump that is yet to be simplified, but + if CASE_DROPS_THRU, this can be a tablejump with + some element going to the same place as the + default (fallthru). */ + && (b->pred->src == ENTRY_BLOCK_PTR + || GET_CODE (b->pred->src->end) != JUMP_INSN + || ! label_is_jump_target_p (b->head, + b->pred->src->end))) + { + rtx label = b->head; + + b->head = NEXT_INSN (b->head); + delete_insn_chain (label, label); + if (rtl_dump_file) + fprintf (rtl_dump_file, "Deleted label in block %i.\n", + b->index); + } + + /* If we fall through an empty block, we can remove it. */ + if (b->pred->pred_next == NULL + && (b->pred->flags & EDGE_FALLTHRU) + && GET_CODE (b->head) != CODE_LABEL + && FORWARDER_BLOCK_P (b) + /* Note that forwarder_block_p true ensures that + there is a successor for this block. */ + && (b->succ->flags & EDGE_FALLTHRU) + && n_basic_blocks > 1) + { + if (rtl_dump_file) + fprintf (rtl_dump_file, + "Deleting fallthru block %i.\n", + b->index); + + c = BASIC_BLOCK (b->index ? b->index - 1 : 1); + redirect_edge_succ_nodup (b->pred, b->succ->dest); + flow_delete_block (b); + changed = true; + b = c; + } + + /* Merge blocks. Loop because chains of blocks might be + combineable. */ + while ((s = b->succ) != NULL + && s->succ_next == NULL + && !(s->flags & EDGE_COMPLEX) + && (c = s->dest) != EXIT_BLOCK_PTR + && c->pred->pred_next == NULL + /* If the jump insn has side effects, + we can't kill the edge. */ + && (GET_CODE (b->end) != JUMP_INSN + || onlyjump_p (b->end)) + && merge_blocks (s, b, c, mode)) + changed_here = true; + + /* Simplify branch over branch. */ + if ((mode & CLEANUP_EXPENSIVE) && try_simplify_condjump (b)) + { + BB_SET_FLAG (b, BB_UPDATE_LIFE); + changed_here = true; + } + + /* If B has a single outgoing edge, but uses a + non-trivial jump instruction without side-effects, we + can either delete the jump entirely, or replace it + with a simple unconditional jump. Use + redirect_edge_and_branch to do the dirty work. */ + if (b->succ + && ! b->succ->succ_next + && b->succ->dest != EXIT_BLOCK_PTR + && onlyjump_p (b->end) + && redirect_edge_and_branch (b->succ, b->succ->dest)) + { + BB_SET_FLAG (b, BB_UPDATE_LIFE); + update_forwarder_flag (b); + changed_here = true; + } + + /* Simplify branch to branch. */ + if (try_forward_edges (mode, b)) + changed_here = true; + + /* Look for shared code between blocks. */ + if ((mode & CLEANUP_CROSSJUMP) + && try_crossjump_bb (mode, b)) + changed_here = true; + + /* Don't get confused by the index shift caused by + deleting blocks. */ + if (!changed_here) + i = b->index + 1; + else + changed = true; } - /* Remove code labels no longer used. Don't do this before - CALL_PLACEHOLDER is removed, as some branches may be hidden - within. */ - if (b->pred->pred_next == NULL - && (b->pred->flags & EDGE_FALLTHRU) - && !(b->pred->flags & EDGE_COMPLEX) - && GET_CODE (b->head) == CODE_LABEL - && (!(mode & CLEANUP_PRE_SIBCALL) - || !tail_recursion_label_p (b->head)) - /* If the previous block ends with a branch to this block, - we can't delete the label. Normally this is a condjump - that is yet to be simplified, but if CASE_DROPS_THRU, - this can be a tablejump with some element going to the - same place as the default (fallthru). */ - && (b->pred->src == ENTRY_BLOCK_PTR - || GET_CODE (b->pred->src->end) != JUMP_INSN - || ! label_is_jump_target_p (b->head, b->pred->src->end))) - { - rtx label = b->head; - - b->head = NEXT_INSN (b->head); - delete_insn_chain (label, label); - if (rtl_dump_file) - fprintf (rtl_dump_file, "Deleted label in block %i.\n", - b->index); - } - - /* If we fall through an empty block, we can remove it. */ - if (b->pred->pred_next == NULL - && (b->pred->flags & EDGE_FALLTHRU) - && GET_CODE (b->head) != CODE_LABEL - && FORWARDER_BLOCK_P (b) - /* Note that forwarder_block_p true ensures that there - is a successor for this block. */ - && (b->succ->flags & EDGE_FALLTHRU) - && n_basic_blocks > 1) - { - if (rtl_dump_file) - fprintf (rtl_dump_file, "Deleting fallthru block %i.\n", - b->index); - - c = BASIC_BLOCK (b->index ? b->index - 1 : 1); - redirect_edge_succ_nodup (b->pred, b->succ->dest); - flow_delete_block (b); - changed = true; - b = c; - } - - /* Merge blocks. Loop because chains of blocks might be - combineable. */ - while ((s = b->succ) != NULL - && s->succ_next == NULL - && !(s->flags & EDGE_COMPLEX) - && (c = s->dest) != EXIT_BLOCK_PTR - && c->pred->pred_next == NULL - /* If the jump insn has side effects, - we can't kill the edge. */ - && (GET_CODE (b->end) != JUMP_INSN - || onlyjump_p (b->end)) - && merge_blocks (s, b, c, mode)) - changed_here = true; - - /* Simplify branch over branch. */ - if ((mode & CLEANUP_EXPENSIVE) && try_simplify_condjump (b)) - { - BB_SET_FLAG (b, BB_UPDATE_LIFE); - changed_here = true; - } - - /* If B has a single outgoing edge, but uses a non-trivial jump - instruction without side-effects, we can either delete the - jump entirely, or replace it with a simple unconditional jump. - Use redirect_edge_and_branch to do the dirty work. */ - if (b->succ - && ! b->succ->succ_next - && b->succ->dest != EXIT_BLOCK_PTR - && onlyjump_p (b->end) - && redirect_edge_and_branch (b->succ, b->succ->dest)) - { - BB_SET_FLAG (b, BB_UPDATE_LIFE); - update_forwarder_flag (b); - changed_here = true; - } - - /* Simplify branch to branch. */ - if (try_forward_edges (mode, b)) - changed_here = true; - - /* Look for shared code between blocks. */ if ((mode & CLEANUP_CROSSJUMP) - && try_crossjump_bb (mode, b)) - changed_here = true; - - /* Don't get confused by the index shift caused by deleting - blocks. */ - if (!changed_here) - i = b->index + 1; - else + && try_crossjump_bb (mode, EXIT_BLOCK_PTR)) changed = true; - } - - if ((mode & CLEANUP_CROSSJUMP) - && try_crossjump_bb (mode, EXIT_BLOCK_PTR)) - changed = true; #ifdef ENABLE_CHECKING - if (changed) - verify_flow_info (); + if (changed) + verify_flow_info (); #endif - changed_overall |= changed; + changed_overall |= changed; + } + while (changed); } - while (changed); if (mode & CLEANUP_CROSSJUMP) remove_fake_edges (); diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index ff255238da4..3cb5c68c5fa 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -8616,3 +8616,18 @@ object files that are not referenced from @code{main} and uses export lists. @end table + +@deftypefn {Target Hook} bool TARGET_CANNOT_MODIFY_JUMPS_P (void) +This target hook returns @code{true} past the point in which new jump +instructions could be created. On machines that require a register for +every jump such as the SHmedia ISA of SH5, this point would typically be +reload, so this target hook should be defined to a function such as: + +@smallexample +static bool +cannot_modify_jumps_past_reload_p () +@{ + return (reload_completed || reload_in_progress); +@} +@end smallexample +@end deftypefn diff --git a/gcc/hooks.c b/gcc/hooks.c new file mode 100644 index 00000000000..387f4db961a --- /dev/null +++ b/gcc/hooks.c @@ -0,0 +1,34 @@ +/* General-purpose hooks. + Copyright (C) 2002 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +/* This file contains generic hooks that can be used as defaults for + target or language-dependent hook initializers. */ + +#include "config.h" +#include "system.h" +#include "hooks.h" + +/* Generic hook that takes no arguments and returns false. */ +bool +hook_void_bool_false () +{ + return false; +} diff --git a/gcc/hooks.h b/gcc/hooks.h new file mode 100644 index 00000000000..7a8daa55d7f --- /dev/null +++ b/gcc/hooks.h @@ -0,0 +1,22 @@ +/* General-purpose hooks. + Copyright (C) 2002 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +bool hook_void_bool_false PARAMS ((void)); diff --git a/gcc/target-def.h b/gcc/target-def.h index bc93b507f7e..71987f5caf6 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -175,6 +175,9 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define TARGET_SECTION_TYPE_FLAGS default_section_type_flags #endif +/* In hook.c. */ +#define TARGET_CANNOT_MODIFY_JUMPS_P hook_void_bool_false + /* The whole shebang. */ #define TARGET_INITIALIZER \ { \ @@ -192,5 +195,8 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. TARGET_EXPAND_BUILTIN, \ TARGET_SECTION_TYPE_FLAGS, \ TARGET_HAVE_NAMED_SECTIONS, \ - TARGET_HAVE_CTORS_DTORS \ + TARGET_HAVE_CTORS_DTORS, \ + TARGET_CANNOT_MODIFY_JUMPS_P \ } + +#include "hooks.h" diff --git a/gcc/target.h b/gcc/target.h index 38ce359eea2..5ee9aa64d57 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -184,6 +184,10 @@ struct gcc_target /* True if "native" constructors and destructors are supported, false if we're using collect2 for the job. */ bool have_ctors_dtors; + + /* True if new jumps cannot be created, to replace existing ones or + not, at the current point in the compilation. */ + bool (* cannot_modify_jumps_p) PARAMS ((void)); }; extern struct gcc_target targetm;