]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR target/1532 (-O3 generates (obviously) redundant tests and jumps)
authorIan Lance Taylor <ian@wasabisystems.com>
Fri, 5 Mar 2004 17:55:57 +0000 (17:55 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 5 Mar 2004 17:55:57 +0000 (17:55 +0000)
PR target/1532
Backport from mainline:

2004-02-24  Kazu Hirata  <kazu@cs.umass.edu>

* 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  <rth@redhat.com>

* flow.c (insn_dead_p): A clobber of a dead hard register is a
dead insn after reload.

2004-01-24  Ian Lance Taylor  <ian@wasabisystems.com>

* 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  <a.tobler@schweiz.ch>

* cse.c: (cse_cc_succs) Fix comparison warning.

2004-01-23  Ian Lance Taylor  <ian@wasabisystems.com>

* 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

13 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/config/i386/i386.c
gcc/cse.c
gcc/doc/gccint.texi
gcc/doc/tm.texi
gcc/flow.c
gcc/hooks.c
gcc/hooks.h
gcc/rtl.h
gcc/target-def.h
gcc/target.h
gcc/toplev.c

index aeade98f3978a264feb38c422d2078dae3aa8bf5..9b4e41a9b6e6fc869aa465e4669e2093e8ebc031 100644 (file)
@@ -1,5 +1,59 @@
 2004-03-05  Ian Lance Taylor  <ian@wasabisystems.com>
 
+       PR target/1532
+       Backport from mainline:
+
+       2004-02-24  Kazu Hirata  <kazu@cs.umass.edu>
+
+       * 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  <rth@redhat.com>
+
+       * flow.c (insn_dead_p): A clobber of a dead hard register is a
+       dead insn after reload.
+
+       2004-01-24  Ian Lance Taylor  <ian@wasabisystems.com>
+
+       * 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  <a.tobler@schweiz.ch>
+
+       * cse.c: (cse_cc_succs) Fix comparison warning.
+
+       2004-01-23  Ian Lance Taylor  <ian@wasabisystems.com>
+
+       * 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.
index 21895de7c630e9d9875b31637a4f7f342066cbab..e10f243b5baffe0c107da29eed3f15350d7a96c6 100644 (file)
@@ -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
index 1106e02f6b7e63e2f4e13ae6edce10e88d2f90b5..3e1aa83b2d381ff8ff91c1bb22c0e547cef04946 100644 (file)
@@ -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;
 \f
 /* 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
index 9566865debefc3f7893499ab328b1dcba79c8d69..e729cef2a55e3dce561b4cd72030bd732591bb19 100644 (file)
--- 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));
 \f
 /* 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 (&REG_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 (&REG_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;
+}
index b6bec095fa0a92aea3f0bdfae16b07a5e35809dd..eee13763913478a8a7b9a2ea067ba417171556f8 100644 (file)
@@ -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
index 2c097012f4b9c63f1cb482ebf0472e44a5d9eb4e..5ea634a870e8f1dd1123b62e112046390f2c48ff 100644 (file)
@@ -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
index c5699b77e4d30f4c35260d2a3b6b2a1e2992bf3a..11b15dc0ce4d2867e35a856e14a4a1fe41d0fea2 100644 (file)
@@ -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;
 }
 
index 3f212ef3e1b69f61237a21c3b10d1c4f0ca42fb9..36d7b2f45874b1ed921449d4e6e441c2defd3f2a 100644 (file)
@@ -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;
+}
index 8c28194f6aca6c2f80e8189f1186f0ca97336321..198d114d759ba308616e45a31993d7591ffef12e 100644 (file)
@@ -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));
index a2cb1dbf1ab947992e5df730cee3286f7b1570a5..2d66fd79ad2083d42423c5855021d23d2f83c44d 100644 (file)
--- 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));
index 154d58d47e9a78570883760130bc659e0b1a6662..5e377c74883baa19c6aa580f7ac9a78bb0ff6785 100644 (file)
@@ -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,                             \
index 0ac1c5aa17b60d0f7f80177654dd8183dfc3fb92..7b25eda0640d10c307f8395f1dda574430926dbf 100644 (file)
@@ -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.  */
index 128eee0b347bb5294a1ebfd621db5e24566dacd8..8e8486d8a624875be0e8456beb0d8920790e3a26 100644 (file)
@@ -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 ());