diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a27835d9ff6acbff4916f436eeffd5974b312afa..07d016c072603ae9b8d963a233ef15496318e746 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2003-06-24 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz> + + * Makefile.in (cfgrtl.o): Add expr.h dependency. + * cfgrtl.c: Include expr.h. + (mark_killed_regs, safe_insert_insn_on_edge): New + functions. + * config/i386/i386.h (AVOID_CCMODE_COPIES): Define. + * basic-block.h (safe_insert_insn_on_edge): Declare. + 2003-06-26 Neil Booth <neil@daikokuya.co.uk> * c-opts.c (missing_arg): Make non-static. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index a3cc5df30ecc9d0325a480eb4caafe16bc768f44..5029c52db229660339297e8649b02a3d9854b2c6 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1659,7 +1659,7 @@ cfghooks.o: cfghooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TR $(BASIC_BLOCK_H) cfglayout.h cfgrtl.o : cfgrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_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 $(GGC_H) $(TM_P_H) insn-config.h + function.h except.h $(GGC_H) $(TM_P_H) insn-config.h $(EXPR_H) cfganal.o : cfganal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(BASIC_BLOCK_H) hard-reg-set.h insn-config.h $(RECOG_H) $(GGC_H) $(TM_P_H) cfgbuild.o : cfgbuild.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \ diff --git a/gcc/basic-block.h b/gcc/basic-block.h index 40775b9ad9a0b5e6e2b89a6d55de03fdc485a7da..b26b14399d11122158b1ce4f8c370dbb8efd63a6 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -340,6 +340,7 @@ extern void update_bb_for_insn PARAMS ((basic_block)); extern void free_basic_block_vars PARAMS ((int)); extern void insert_insn_on_edge PARAMS ((rtx, edge)); +bool safe_insert_insn_on_edge (rtx, edge); extern void commit_edge_insertions PARAMS ((void)); extern void commit_edge_insertions_watch_calls PARAMS ((void)); diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c index 569a6049882c93c28a244fdff0fcefe05eb5147a..a08d29f3da94da025d181a60f039e04c8c9dfa63 100644 --- a/gcc/cfgrtl.c +++ b/gcc/cfgrtl.c @@ -56,6 +56,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "obstack.h" #include "insn-config.h" #include "cfglayout.h" +#include "expr.h" /* Stubs in case we don't have a return insn. */ #ifndef HAVE_return @@ -88,6 +89,7 @@ static bool rtl_redirect_edge_and_branch (edge, basic_block); static edge rtl_split_block (basic_block, void *); static void rtl_dump_bb (basic_block, FILE *); static int rtl_verify_flow_info_1 (void); +static void mark_killed_regs (rtx, rtx, void *); /* Return true if NOTE is not one of the ones that must be kept paired, so that we may simply delete it. */ @@ -1305,6 +1307,101 @@ insert_insn_on_edge (rtx pattern, edge e) end_sequence (); } +/* Called from safe_insert_insn_on_edge through note_stores, marks live + registers that are killed by the store. */ +static void +mark_killed_regs (rtx reg, rtx set ATTRIBUTE_UNUSED, void *data) +{ + regset killed = data; + int regno, i; + + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); + if (!REG_P (reg)) + return; + regno = REGNO (reg); + if (regno >= FIRST_PSEUDO_REGISTER) + SET_REGNO_REG_SET (killed, regno); + else + { + for (i = 0; i < HARD_REGNO_NREGS (regno, GET_MODE (reg)); i++) + SET_REGNO_REG_SET (killed, regno + i); + } +} + +/* Similar to insert_insn_on_edge, tries to put INSN to edge E. Additionally + it checks whether this will not clobber the registers that are live on the + edge (i.e. it requieres liveness information to be up-to-date) and if there + are some, then it tries to save and restore them. Returns true if + succesful. */ +bool +safe_insert_insn_on_edge (rtx insn, edge e) +{ + rtx x; + regset_head killed_head; + regset killed = INITIALIZE_REG_SET (killed_head); + rtx save_regs = NULL_RTX; + int regno, noccmode; + enum machine_mode mode; + +#ifdef AVOID_CCMODE_COPIES + noccmode = true; +#else + noccmode = false; +#endif + + for (x = insn; x; x = NEXT_INSN (x)) + if (INSN_P (x)) + note_stores (PATTERN (x), mark_killed_regs, killed); + bitmap_operation (killed, killed, e->dest->global_live_at_start, + BITMAP_AND); + + EXECUTE_IF_SET_IN_REG_SET (killed, 0, regno, + { + mode = regno < FIRST_PSEUDO_REGISTER + ? reg_raw_mode[regno] + : GET_MODE (regno_reg_rtx[regno]); + if (mode == VOIDmode) + return false; + + if (noccmode && mode == CCmode) + return false; + + save_regs = alloc_EXPR_LIST (0, + alloc_EXPR_LIST (0, + gen_reg_rtx (mode), + gen_raw_REG (mode, regno)), + save_regs); + }); + + if (save_regs) + { + rtx from, to; + + start_sequence (); + for (x = save_regs; x; x = XEXP (x, 1)) + { + from = XEXP (XEXP (x, 0), 1); + to = XEXP (XEXP (x, 0), 0); + emit_move_insn (to, from); + } + emit_insn (insn); + for (x = save_regs; x; x = XEXP (x, 1)) + { + from = XEXP (XEXP (x, 0), 0); + to = XEXP (XEXP (x, 0), 1); + emit_move_insn (to, from); + } + insn = get_insns (); + end_sequence (); + free_EXPR_LIST_list (&save_regs); + } + insert_insn_on_edge (insn, e); + + FREE_REG_SET (killed); + return true; +} + /* Update the CFG for the instructions queued on edge E. */ static void diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 5f390f0e1552676cf1ec3319d154aa11ed0f8c63..c115f6a21997a959e95b05974fa962a2c4d293df 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1123,6 +1123,9 @@ do { \ && (TARGET_64BIT || !TARGET_PARTIAL_REG_STALL)) \ || ((MODE2) == DImode && TARGET_64BIT)))) +/* It is possible to write patterns to move flags; but until someone + does it, */ +#define AVOID_CCMODE_COPIES /* Specify the modes required to caller save a given hard regno. We do this on i386 to prevent flags from being saved at all.