From: Ian Lance Taylor Date: Fri, 5 Mar 2004 17:55:57 +0000 (+0000) Subject: re PR target/1532 (-O3 generates (obviously) redundant tests and jumps) X-Git-Tag: releases/gcc-3.3.4~199 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=be35d2c8c86f0d5b5388d6667138ff8679df21a1;p=thirdparty%2Fgcc.git re PR target/1532 (-O3 generates (obviously) redundant tests and jumps) PR target/1532 Backport from mainline: 2004-02-24 Kazu Hirata * cse.c (cse_change_cc_mode_insns): Stop at any instruction which modifies NEWREG. (cse_condition_code_reg): Update the mode of CC_REG in CC_SRC_INSN on our own. 2004-02-11 Richard Henderson * flow.c (insn_dead_p): A clobber of a dead hard register is a dead insn after reload. 2004-01-24 Ian Lance Taylor * cse.c (cse_cc_succs): Change the mode of the source expression as soon as decide we need a new mode. Don't permit changing modes if we found a match in a successor block. (cse_condition_code_reg): Save original mode of source expression so that we know whether we have to change the mode in other insns. 2004-01-24 Andreas Tobler * cse.c: (cse_cc_succs) Fix comparison warning. 2004-01-23 Ian Lance Taylor * cse.c: Include "target.h". (cse_change_cc_mode): New static function. (cse_change_cc_mode_insns, cse_cc_succs): Likewise. (cse_condition_code_reg): New function. (default_cc_modes_compatible): New function. * rtl.h (cse_condition_code_reg): Declare. (default_cc_modes_compatible): Declare. * toplev.c (rest_of_compilation): Call cse_condition_code_reg. * target.h (struct gcc_target): Add fixed_condition_code_regs and cc_modes_compatible. * target-def.h (TARGET_FIXED_CONDITION_CODE_REGS): Define. (TARGET_CC_MODES_COMPATIBLE): Define. (TARGET_INITIALIZER): Add new initializers. * targhooks.c (default_cc_modes_compatible): Declare. * hooks.c (hook_bool_intp_intp_false): New function. * hooks.h (hook_bool_intp_intp_false): Declare. * config/i386/i386.c (TARGET_FIXED_CONDITION_CODE_REGS): Define. (TARGET_CC_MODES_COMPATIBLE): Define. (ix86_fixed_condition_code_regs): New static function. (ix86_cc_modes_compatible): Likewise. * doc/gccint.texi: Add copyright 2004. * doc/tm.texi (Condition Code): Document new hooks. * Makefile.in (cse.o): Depend upon $(TARGET_H). From-SVN: r78979 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index aeade98f3978..9b4e41a9b6e6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,59 @@ 2004-03-05 Ian Lance Taylor + PR target/1532 + Backport from mainline: + + 2004-02-24 Kazu Hirata + + * cse.c (cse_change_cc_mode_insns): Stop at any instruction + which modifies NEWREG. + (cse_condition_code_reg): Update the mode of CC_REG in + CC_SRC_INSN on our own. + + 2004-02-11 Richard Henderson + + * flow.c (insn_dead_p): A clobber of a dead hard register is a + dead insn after reload. + + 2004-01-24 Ian Lance Taylor + + * cse.c (cse_cc_succs): Change the mode of the source expression + as soon as decide we need a new mode. Don't permit changing modes + if we found a match in a successor block. + (cse_condition_code_reg): Save original mode of source expression + so that we know whether we have to change the mode in other + insns. + + 2004-01-24 Andreas Tobler + + * cse.c: (cse_cc_succs) Fix comparison warning. + + 2004-01-23 Ian Lance Taylor + + * cse.c: Include "target.h". + (cse_change_cc_mode): New static function. + (cse_change_cc_mode_insns, cse_cc_succs): Likewise. + (cse_condition_code_reg): New function. + (default_cc_modes_compatible): New function. + * rtl.h (cse_condition_code_reg): Declare. + (default_cc_modes_compatible): Declare. + * toplev.c (rest_of_compilation): Call cse_condition_code_reg. + * target.h (struct gcc_target): Add fixed_condition_code_regs and + cc_modes_compatible. + * target-def.h (TARGET_FIXED_CONDITION_CODE_REGS): Define. + (TARGET_CC_MODES_COMPATIBLE): Define. + (TARGET_INITIALIZER): Add new initializers. + * targhooks.c (default_cc_modes_compatible): Declare. + * hooks.c (hook_bool_intp_intp_false): New function. + * hooks.h (hook_bool_intp_intp_false): Declare. + * config/i386/i386.c (TARGET_FIXED_CONDITION_CODE_REGS): Define. + (TARGET_CC_MODES_COMPATIBLE): Define. + (ix86_fixed_condition_code_regs): New static function. + (ix86_cc_modes_compatible): Likewise. + * doc/gccint.texi: Add copyright 2004. + * doc/tm.texi (Condition Code): Document new hooks. + * Makefile.in (cse.o): Depend upon $(TARGET_H). + PR inline-asm/6162 * reload.c (find_reloads): Only support one pair of commutative operands. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 21895de7c630..e10f243b5baf 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1513,7 +1513,7 @@ cselib.o : cselib.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(REGS_H) \ output.h function.h cselib.h $(GGC_H) $(TM_P_H) gt-cselib.h cse.o : cse.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(REGS_H) hard-reg-set.h flags.h \ real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h output.h function.h \ - $(BASIC_BLOCK_H) $(GGC_H) $(TM_P_H) $(TIMEVAR_H) + $(BASIC_BLOCK_H) $(GGC_H) $(TM_P_H) $(TIMEVAR_H) $(TARGET_H) gcse.o : gcse.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(REGS_H) hard-reg-set.h \ flags.h real.h insn-config.h ggc.h $(RECOG_H) $(EXPR_H) $(BASIC_BLOCK_H) \ function.h output.h toplev.h $(TM_P_H) $(PARAMS_H) except.h gt-gcse.h diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 1106e02f6b7e..3e1aa83b2d38 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -1,6 +1,6 @@ /* Subroutines used for code generation on IA-32. Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - 2002, 2003 Free Software Foundation, Inc. + 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GNU CC. @@ -720,6 +720,10 @@ static rtx maybe_get_pool_constant PARAMS ((rtx)); static rtx ix86_expand_int_compare PARAMS ((enum rtx_code, rtx, rtx)); static enum rtx_code ix86_prepare_fp_compare_args PARAMS ((enum rtx_code, rtx *, rtx *)); +static bool ix86_fixed_condition_code_regs PARAMS ((unsigned int *, + unsigned int *)); +static enum machine_mode ix86_cc_modes_compatible PARAMS ((enum machine_mode, + enum machine_mode)); static rtx get_thread_pointer PARAMS ((void)); static void get_pc_thunk_name PARAMS ((char [32], unsigned int)); static rtx gen_push PARAMS ((rtx)); @@ -910,6 +914,11 @@ static enum x86_64_reg_class merge_classes PARAMS ((enum x86_64_reg_class, #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK #define TARGET_ASM_CAN_OUTPUT_MI_THUNK x86_can_output_mi_thunk +#undef TARGET_FIXED_CONDITION_CODE_REGS +#define TARGET_FIXED_CONDITION_CODE_REGS ix86_fixed_condition_code_regs +#undef TARGET_CC_MODES_COMPATIBLE +#define TARGET_CC_MODES_COMPATIBLE ix86_cc_modes_compatible + struct gcc_target targetm = TARGET_INITIALIZER; /* The svr4 ABI for the i386 says that records and unions are returned @@ -8367,6 +8376,68 @@ ix86_cc_mode (code, op0, op1) } } +/* Return the fixed registers used for condition codes. */ + +static bool +ix86_fixed_condition_code_regs (p1, p2) + unsigned int *p1; + unsigned int *p2; +{ + *p1 = FLAGS_REG; + *p2 = FPSR_REG; + return true; +} + +/* If two condition code modes are compatible, return a condition code + mode which is compatible with both. Otherwise, return + VOIDmode. */ + +static enum machine_mode +ix86_cc_modes_compatible (m1, m2) + enum machine_mode m1; + enum machine_mode m2; +{ + if (m1 == m2) + return m1; + + if (GET_MODE_CLASS (m1) != MODE_CC || GET_MODE_CLASS (m2) != MODE_CC) + return VOIDmode; + + if ((m1 == CCGCmode && m2 == CCGOCmode) + || (m1 == CCGOCmode && m2 == CCGCmode)) + return CCGCmode; + + switch (m1) + { + default: + abort (); + + case CCmode: + case CCGCmode: + case CCGOCmode: + case CCNOmode: + case CCZmode: + switch (m2) + { + default: + return VOIDmode; + + case CCmode: + case CCGCmode: + case CCGOCmode: + case CCNOmode: + case CCZmode: + return CCmode; + } + + case CCFPmode: + case CCFPUmode: + /* These are only compatible with themselves, which we already + checked above. */ + return VOIDmode; + } +} + /* Return true if we should use an FCOMI instruction for this fp comparison. */ int diff --git a/gcc/cse.c b/gcc/cse.c index 9566865debef..e729cef2a55e 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -1,6 +1,6 @@ /* Common subexpression elimination for GNU compiler. Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998 - 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -38,6 +38,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "output.h" #include "ggc.h" #include "timevar.h" +#include "target.h" /* The basic idea of common subexpression elimination is to go through the code, keeping a record of expressions that would @@ -701,6 +702,9 @@ static void flush_hash_table PARAMS ((void)); static bool insn_live_p PARAMS ((rtx, int *)); static bool set_live_p PARAMS ((rtx, rtx, int *)); static bool dead_libcall_p PARAMS ((rtx, int *)); +static int cse_change_cc_mode PARAMS ((rtx *, void *)); +static void cse_change_cc_mode_insns PARAMS ((rtx, rtx, rtx)); +static enum machine_mode cse_cc_succs PARAMS ((basic_block, rtx, rtx, int)); /* Dump the expressions in the equivalence class indicated by CLASSP. This function is used only for debugging. */ @@ -7774,3 +7778,369 @@ delete_trivially_dead_insns (insns, nreg) timevar_pop (TV_DELETE_TRIVIALLY_DEAD); return ndead; } + +/* This function is called via for_each_rtx. The argument, NEWREG, is + a condition code register with the desired mode. If we are looking + at the same register in a different mode, replace it with + NEWREG. */ + +static int +cse_change_cc_mode (loc, data) + rtx *loc; + void *data; +{ + rtx newreg = (rtx) data; + + if (*loc + && GET_CODE (*loc) == REG + && REGNO (*loc) == REGNO (newreg) + && GET_MODE (*loc) != GET_MODE (newreg)) + { + *loc = newreg; + return -1; + } + return 0; +} + +/* Change the mode of any reference to the register REGNO (NEWREG) to + GET_MODE (NEWREG), starting at START. Stop before END. Stop at + any instruction which modifies NEWREG. */ + +static void +cse_change_cc_mode_insns (start, end, newreg) + rtx start; + rtx end; + rtx newreg; +{ + rtx insn; + + for (insn = start; insn != end; insn = NEXT_INSN (insn)) + { + if (! INSN_P (insn)) + continue; + + if (reg_set_p (newreg, insn)) + return; + + for_each_rtx (&PATTERN (insn), cse_change_cc_mode, newreg); + for_each_rtx (®_NOTES (insn), cse_change_cc_mode, newreg); + } +} + +/* BB is a basic block which finishes with CC_REG as a condition code + register which is set to CC_SRC. Look through the successors of BB + to find blocks which have a single predecessor (i.e., this one), + and look through those blocks for an assignment to CC_REG which is + equivalent to CC_SRC. CAN_CHANGE_MODE indicates whether we are + permitted to change the mode of CC_SRC to a compatible mode. This + returns VOIDmode if no equivalent assignments were found. + Otherwise it returns the mode which CC_SRC should wind up with. + + The main complexity in this function is handling the mode issues. + We may have more than one duplicate which we can eliminate, and we + try to find a mode which will work for multiple duplicates. */ + +static enum machine_mode +cse_cc_succs (bb, cc_reg, cc_src, can_change_mode) + basic_block bb; + rtx cc_reg; + rtx cc_src; + int can_change_mode; +{ + bool found_equiv; + enum machine_mode mode; + unsigned int insn_count; + edge e; + rtx insns[2]; + enum machine_mode modes[2]; + rtx last_insns[2]; + unsigned int i; + rtx newreg; + + /* We expect to have two successors. Look at both before picking + the final mode for the comparison. If we have more successors + (i.e., some sort of table jump, although that seems unlikely), + then we require all beyond the first two to use the same + mode. */ + + found_equiv = false; + mode = GET_MODE (cc_src); + insn_count = 0; + for (e = bb->succ; e; e = e->succ_next) + { + rtx insn; + rtx end; + + if (e->flags & EDGE_COMPLEX) + continue; + + if (! e->dest->pred + || e->dest->pred->pred_next + || e->dest == EXIT_BLOCK_PTR) + continue; + + end = NEXT_INSN (e->dest->end); + for (insn = e->dest->head; insn != end; insn = NEXT_INSN (insn)) + { + rtx set; + + if (! INSN_P (insn)) + continue; + + /* If CC_SRC is modified, we have to stop looking for + something which uses it. */ + if (modified_in_p (cc_src, insn)) + break; + + /* Check whether INSN sets CC_REG to CC_SRC. */ + set = single_set (insn); + if (set + && GET_CODE (SET_DEST (set)) == REG + && REGNO (SET_DEST (set)) == REGNO (cc_reg)) + { + bool found; + enum machine_mode set_mode; + enum machine_mode comp_mode; + + found = false; + set_mode = GET_MODE (SET_SRC (set)); + comp_mode = set_mode; + if (rtx_equal_p (cc_src, SET_SRC (set))) + found = true; + else if (GET_CODE (cc_src) == COMPARE + && GET_CODE (SET_SRC (set)) == COMPARE + && mode != set_mode + && rtx_equal_p (XEXP (cc_src, 0), + XEXP (SET_SRC (set), 0)) + && rtx_equal_p (XEXP (cc_src, 1), + XEXP (SET_SRC (set), 1))) + + { + comp_mode = (*targetm.cc_modes_compatible) (mode, set_mode); + if (comp_mode != VOIDmode + && (can_change_mode || comp_mode == mode)) + found = true; + } + + if (found) + { + found_equiv = true; + if (insn_count < ARRAY_SIZE (insns)) + { + insns[insn_count] = insn; + modes[insn_count] = set_mode; + last_insns[insn_count] = end; + ++insn_count; + + if (mode != comp_mode) + { + if (! can_change_mode) + abort (); + mode = comp_mode; + PUT_MODE (cc_src, mode); + } + } + else + { + if (set_mode != mode) + { + /* We found a matching expression in the + wrong mode, but we don't have room to + store it in the array. Punt. This case + should be rare. */ + break; + } + /* INSN sets CC_REG to a value equal to CC_SRC + with the right mode. We can simply delete + it. */ + delete_insn (insn); + } + + /* We found an instruction to delete. Keep looking, + in the hopes of finding a three-way jump. */ + continue; + } + + /* We found an instruction which sets the condition + code, so don't look any farther. */ + break; + } + + /* If INSN sets CC_REG in some other way, don't look any + farther. */ + if (reg_set_p (cc_reg, insn)) + break; + } + + /* If we fell off the bottom of the block, we can keep looking + through successors. We pass CAN_CHANGE_MODE as false because + we aren't prepared to handle compatibility between the + further blocks and this block. */ + if (insn == end) + { + enum machine_mode submode; + + submode = cse_cc_succs (e->dest, cc_reg, cc_src, false); + if (submode != VOIDmode) + { + if (submode != mode) + abort (); + found_equiv = true; + can_change_mode = false; + } + } + } + + if (! found_equiv) + return VOIDmode; + + /* Now INSN_COUNT is the number of instructions we found which set + CC_REG to a value equivalent to CC_SRC. The instructions are in + INSNS. The modes used by those instructions are in MODES. */ + + newreg = NULL_RTX; + for (i = 0; i < insn_count; ++i) + { + if (modes[i] != mode) + { + /* We need to change the mode of CC_REG in INSNS[i] and + subsequent instructions. */ + if (! newreg) + { + if (GET_MODE (cc_reg) == mode) + newreg = cc_reg; + else + newreg = gen_rtx_REG (mode, REGNO (cc_reg)); + } + cse_change_cc_mode_insns (NEXT_INSN (insns[i]), last_insns[i], + newreg); + } + + delete_insn (insns[i]); + } + + return mode; +} + +/* If we have a fixed condition code register (or two), walk through + the instructions and try to eliminate duplicate assignments. */ + +void +cse_condition_code_reg () +{ + unsigned int cc_regno_1; + unsigned int cc_regno_2; + rtx cc_reg_1; + rtx cc_reg_2; + basic_block bb; + + if (! (*targetm.fixed_condition_code_regs) (&cc_regno_1, &cc_regno_2)) + return; + + cc_reg_1 = gen_rtx_REG (CCmode, cc_regno_1); + if (cc_regno_2 != INVALID_REGNUM) + cc_reg_2 = gen_rtx_REG (CCmode, cc_regno_2); + else + cc_reg_2 = NULL_RTX; + + FOR_EACH_BB (bb) + { + rtx last_insn; + rtx cc_reg; + rtx insn; + rtx cc_src_insn; + rtx cc_src; + enum machine_mode mode; + enum machine_mode orig_mode; + + /* Look for blocks which end with a conditional jump based on a + condition code register. Then look for the instruction which + sets the condition code register. Then look through the + successor blocks for instructions which set the condition + code register to the same value. There are other possible + uses of the condition code register, but these are by far the + most common and the ones which we are most likely to be able + to optimize. */ + + last_insn = bb->end; + if (GET_CODE (last_insn) != JUMP_INSN) + continue; + + if (reg_referenced_p (cc_reg_1, PATTERN (last_insn))) + cc_reg = cc_reg_1; + else if (cc_reg_2 && reg_referenced_p (cc_reg_2, PATTERN (last_insn))) + cc_reg = cc_reg_2; + else + continue; + + cc_src_insn = NULL_RTX; + cc_src = NULL_RTX; + for (insn = PREV_INSN (last_insn); + insn && insn != PREV_INSN (bb->head); + insn = PREV_INSN (insn)) + { + rtx set; + + if (! INSN_P (insn)) + continue; + set = single_set (insn); + if (set + && GET_CODE (SET_DEST (set)) == REG + && REGNO (SET_DEST (set)) == REGNO (cc_reg)) + { + cc_src_insn = insn; + cc_src = SET_SRC (set); + break; + } + else if (reg_set_p (cc_reg, insn)) + break; + } + + if (! cc_src_insn) + continue; + + if (modified_between_p (cc_src, cc_src_insn, NEXT_INSN (last_insn))) + continue; + + /* Now CC_REG is a condition code register used for a + conditional jump at the end of the block, and CC_SRC, in + CC_SRC_INSN, is the value to which that condition code + register is set, and CC_SRC is still meaningful at the end of + the basic block. */ + + orig_mode = GET_MODE (cc_src); + mode = cse_cc_succs (bb, cc_reg, cc_src, true); + if (mode != VOIDmode) + { + if (mode != GET_MODE (cc_src)) + abort (); + if (mode != orig_mode) + { + rtx newreg = gen_rtx_REG (mode, REGNO (cc_reg)); + + /* Change the mode of CC_REG in CC_SRC_INSN to + GET_MODE (NEWREG). */ + for_each_rtx (&PATTERN (cc_src_insn), cse_change_cc_mode, + newreg); + for_each_rtx (®_NOTES (cc_src_insn), cse_change_cc_mode, + newreg); + + /* Do the same in the following insns that use the + current value of CC_REG within BB. */ + cse_change_cc_mode_insns (NEXT_INSN (cc_src_insn), + NEXT_INSN (last_insn), + newreg); + } + } + } +} + +enum machine_mode +default_cc_modes_compatible (m1, m2) + enum machine_mode m1; + enum machine_mode m2; +{ + if (m1 == m2) + return m1; + return VOIDmode; +} diff --git a/gcc/doc/gccint.texi b/gcc/doc/gccint.texi index b6bec095fa0a..eee137639134 100644 --- a/gcc/doc/gccint.texi +++ b/gcc/doc/gccint.texi @@ -48,7 +48,7 @@ @copying Copyright @copyright{} 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, -1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. +1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 2c097012f4b9..5ea634a870e8 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -1,4 +1,4 @@ -@c Copyright (C) 1988,1989,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003 +@c Copyright (C) 1988,1989,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004 @c Free Software Foundation, Inc. @c This is part of the GCC manual. @c For copying conditions, see the file gcc.texi. @@ -5203,6 +5203,34 @@ follows: @end table +@deftypefn {Target Hook} bool TARGET_FIXED_CONDITION_CODE_REGS (unsigned int *, unsigned int *) +On targets which do not use @code{(cc0)}, and which use a hard +register rather than a pseudo-register to hold condition codes, the +regular CSE passes are often not able to identify cases in which the +hard register is set to a common value. Use this hook to enable a +small pass which optimizes such cases. This hook should return true +to enable this pass, and it should set the integers to which its +arguments point to the hard register numbers used for condition codes. +When there is only one such register, as is true on most systems, the +integer pointed to by the second argument should be set to +@code{INVALID_REGNUM}. + +The default version of this hook returns false. +@end deftypefn + +@deftypefn {Target Hook} enum machine_mode TARGET_CC_MODES_COMPATIBLE (enum machine_mode, enum machine_mode) +On targets which use multiple condition code modes in class +@code{MODE_CC}, it is sometimes the case that a comparison can be +validly done in more than one mode. On such a system, define this +target hook to take two mode arguments and to return a mode in which +both comparisons may be validly done. If there is no such mode, +return @code{VOIDmode}. + +The default version of this hook checks whether the modes are the +same. If they are, it returns that mode. If they are different, it +returns @code{VOIDmode}. +@end deftypefn + @node Costs @section Describing Relative Costs of Operations @cindex costs of instructions diff --git a/gcc/flow.c b/gcc/flow.c index c5699b77e4d3..11b15dc0ce4d 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -1,6 +1,6 @@ /* Data flow analysis for GNU compiler. Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -2293,14 +2293,22 @@ insn_dead_p (pbi, x, call_ok, notes) } /* A CLOBBER of a pseudo-register that is dead serves no purpose. That - is not necessarily true for hard registers. */ - else if (code == CLOBBER && GET_CODE (XEXP (x, 0)) == REG - && REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER - && ! REGNO_REG_SET_P (pbi->reg_live, REGNO (XEXP (x, 0)))) - return 1; - - /* We do not check other CLOBBER or USE here. An insn consisting of just - a CLOBBER or just a USE should not be deleted. */ + is not necessarily true for hard registers until after reload. */ + else if (code == CLOBBER) + { + if (GET_CODE (XEXP (x, 0)) == REG + && (REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER + || reload_completed) + && ! REGNO_REG_SET_P (pbi->reg_live, REGNO (XEXP (x, 0)))) + return 1; + } + + /* ??? A base USE is a historical relic. It ought not be needed anymore. + Instances where it is still used are either (1) temporary and the USE + escaped the pass, (2) cruft and the USE need not be emitted anymore, + or (3) hiding bugs elsewhere that are not properly representing data + flow. */ + return 0; } diff --git a/gcc/hooks.c b/gcc/hooks.c index 3f212ef3e1b6..36d7b2f45874 100644 --- a/gcc/hooks.c +++ b/gcc/hooks.c @@ -1,5 +1,5 @@ /* General-purpose hooks. - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2004 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 @@ -121,3 +121,11 @@ hook_bool_rtx_false (a) { return false; } + +bool +hook_bool_uintp_uintp_false (a, b) + unsigned int *a ATTRIBUTE_UNUSED; + unsigned int *b ATTRIBUTE_UNUSED; +{ + return false; +} diff --git a/gcc/hooks.h b/gcc/hooks.h index 8c28194f6aca..198d114d759b 100644 --- a/gcc/hooks.h +++ b/gcc/hooks.h @@ -1,5 +1,5 @@ /* General-purpose hooks. - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2004 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 @@ -29,6 +29,7 @@ bool hook_bool_tree_hwi_hwi_tree_false bool hook_bool_tree_hwi_hwi_tree_true PARAMS ((tree, HOST_WIDE_INT, HOST_WIDE_INT, tree)); bool hook_bool_rtx_false PARAMS ((rtx)); +bool hook_bool_uintp_uintp_false PARAMS ((unsigned int *, unsigned int *)); void hook_void_tree_int PARAMS ((tree, int)); void hook_void_void PARAMS ((void)); diff --git a/gcc/rtl.h b/gcc/rtl.h index a2cb1dbf1ab9..2d66fd79ad20 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1,6 +1,6 @@ /* Register Transfer Language (RTL) definitions for GNU C-Compiler Copyright (C) 1987, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -1932,6 +1932,9 @@ extern int cse_main PARAMS ((rtx, int, int, FILE *)); extern void cse_end_of_basic_block PARAMS ((rtx, struct cse_basic_block_data *, int, int, int)); +extern void cse_condition_code_reg PARAMS ((void)); +extern enum machine_mode default_cc_modes_compatible PARAMS ((enum machine_mode, + enum machine_mode)); /* In jump.c */ extern int comparison_dominates_p PARAMS ((enum rtx_code, enum rtx_code)); diff --git a/gcc/target-def.h b/gcc/target-def.h index 154d58d47e9a..5e377c74883b 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -1,5 +1,5 @@ /* Default initializers for a generic GCC target. - Copyright (C) 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2004 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 @@ -239,6 +239,9 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define TARGET_BINDS_LOCAL_P default_binds_local_p #endif +/* In cse.c. */ +#define TARGET_CC_MODES_COMPATIBLE default_cc_modes_compatible + /* In hook.c. */ #define TARGET_CANNOT_MODIFY_JUMPS_P hook_bool_void_false #define TARGET_CANNOT_FORCE_CONST_MEM hook_bool_rtx_false @@ -247,6 +250,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define TARGET_INSERT_ATTRIBUTES hook_void_tree_treeptr #define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P hook_bool_tree_false #define TARGET_MS_BITFIELD_LAYOUT_P hook_bool_tree_false +#define TARGET_FIXED_CONDITION_CODE_REGS hook_bool_uintp_uintp_false #ifndef TARGET_IN_SMALL_DATA_P #define TARGET_IN_SMALL_DATA_P hook_bool_tree_false @@ -278,6 +282,8 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. TARGET_BINDS_LOCAL_P, \ TARGET_ENCODE_SECTION_INFO, \ TARGET_STRIP_NAME_ENCODING, \ + TARGET_FIXED_CONDITION_CODE_REGS, \ + TARGET_CC_MODES_COMPATIBLE, \ TARGET_HAVE_NAMED_SECTIONS, \ TARGET_HAVE_CTORS_DTORS, \ TARGET_HAVE_TLS, \ diff --git a/gcc/target.h b/gcc/target.h index 0ac1c5aa17b6..7b25eda0640d 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -1,5 +1,5 @@ /* Data structure definitions for a generic GCC target. - Copyright (C) 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2004 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 @@ -279,6 +279,23 @@ struct gcc_target /* Undo the effects of encode_section_info on the symbol string. */ const char * (* strip_name_encoding) PARAMS ((const char *)); + /* Fetch the fixed register(s) which hold condition codes, for + targets where it makes sense to look for duplicate assignments to + the condition codes. This should return true if there is such a + register, false otherwise. The arguments should be set to the + fixed register numbers. Up to two condition code registers are + supported. If there is only one for this target, the int pointed + at by the second argument should be set to -1. */ + bool (* fixed_condition_code_regs) PARAMS ((unsigned int *, unsigned int *)); + + /* If two condition code modes are compatible, return a condition + code mode which is compatible with both, such that a comparison + done in the returned mode will work for both of the original + modes. If the condition code modes are not compatible, return + VOIDmode. */ + enum machine_mode (* cc_modes_compatible) PARAMS ((enum machine_mode, + enum machine_mode)); + /* Leave the boolean fields at the end. */ /* True if arbitrary sections are supported. */ diff --git a/gcc/toplev.c b/gcc/toplev.c index 128eee0b347b..8e8486d8a624 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -1,6 +1,6 @@ /* Top level of GNU C compiler Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GCC. @@ -3057,6 +3057,13 @@ rest_of_compilation (decl) dump_flow_info (rtl_dump_file); /* CFG is no longer maintained up-to-date. */ tem = cse_main (insns, max_reg_num (), 1, rtl_dump_file); + + /* Run a pass to eliminate duplicated assignments to condition + code registers. We have to run this after bypass_jumps, + because it makes it harder for that pass to determine whether + a jump can be bypassed safely. */ + cse_condition_code_reg (); + purge_all_dead_edges (0); delete_trivially_dead_insns (insns, max_reg_num ());