summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/cse.c
diff options
context:
space:
mode:
authorkan <kan@FreeBSD.org>2004-07-28 03:11:36 +0000
committerkan <kan@FreeBSD.org>2004-07-28 03:11:36 +0000
commit5e00ec74d8ce58f99801200d4d3d0412c7cc1b28 (patch)
tree052f4bb635f2bea2c5e350bd60c902be100a0d1e /contrib/gcc/cse.c
parent87b8398a7d9f9bf0e28bbcd54a4fc27db2125f38 (diff)
downloadFreeBSD-src-5e00ec74d8ce58f99801200d4d3d0412c7cc1b28.zip
FreeBSD-src-5e00ec74d8ce58f99801200d4d3d0412c7cc1b28.tar.gz
Gcc 3.4.2 20040728.
Diffstat (limited to 'contrib/gcc/cse.c')
-rw-r--r--contrib/gcc/cse.c1289
1 files changed, 770 insertions, 519 deletions
diff --git a/contrib/gcc/cse.c b/contrib/gcc/cse.c
index 9566865..5081926 100644
--- a/contrib/gcc/cse.c
+++ b/contrib/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, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
@@ -22,6 +22,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "config.h"
/* stdio.h must precede rtl.h for FFS. */
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "rtl.h"
#include "tm_p.h"
@@ -38,6 +40,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "output.h"
#include "ggc.h"
#include "timevar.h"
+#include "except.h"
+#include "target.h"
+#include "params.h"
/* The basic idea of common subexpression elimination is to go
through the code, keeping a record of expressions that would
@@ -247,8 +252,10 @@ struct qty_table_elem
rtx comparison_const;
int comparison_qty;
unsigned int first_reg, last_reg;
- enum machine_mode mode;
- enum rtx_code comparison_code;
+ /* The sizes of these fields should match the sizes of the
+ code and mode fields of struct rtx_def (see rtl.h). */
+ ENUM_BITFIELD(rtx_code) comparison_code : 16;
+ ENUM_BITFIELD(machine_mode) mode : 8;
};
/* The table of all qtys, indexed by qty number. */
@@ -266,11 +273,11 @@ static struct qty_table_elem *qty_table;
static rtx prev_insn_cc0;
static enum machine_mode prev_insn_cc0_mode;
-#endif
/* Previous actual insn. 0 if at first insn of basic block. */
static rtx prev_insn;
+#endif
/* Insn being scanned. */
@@ -458,7 +465,9 @@ struct table_elt
struct table_elt *related_value;
int cost;
int regcost;
- enum machine_mode mode;
+ /* The size of this field should match the size
+ of the mode field of struct rtx_def (see rtl.h). */
+ ENUM_BITFIELD(machine_mode) mode : 8;
char in_memory;
char is_const;
char flag;
@@ -494,9 +503,9 @@ struct table_elt
a cost of 2. Aside from these special cases, call `rtx_cost'. */
#define CHEAP_REGNO(N) \
- ((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM \
- || (N) == STACK_POINTER_REGNUM || (N) == ARG_POINTER_REGNUM \
- || ((N) >= FIRST_VIRTUAL_REGISTER && (N) <= LAST_VIRTUAL_REGISTER) \
+ ((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM \
+ || (N) == STACK_POINTER_REGNUM || (N) == ARG_POINTER_REGNUM \
+ || ((N) >= FIRST_VIRTUAL_REGISTER && (N) <= LAST_VIRTUAL_REGISTER) \
|| ((N) < FIRST_PSEUDO_REGISTER \
&& FIXED_REGNO_P (N) && REGNO_REG_CLASS (N) != NO_REGS))
@@ -505,7 +514,7 @@ struct table_elt
/* Get the info associated with register N. */
-#define GET_CSE_REG_INFO(N) \
+#define GET_CSE_REG_INFO(N) \
(((N) == cached_regno && cached_cse_reg_info) \
? cached_cse_reg_info : get_cse_reg_info ((N)))
@@ -560,10 +569,7 @@ static struct table_elt *last_jump_equiv_class;
the insn. */
static int constant_pool_entries_cost;
-
-/* Define maximum length of a branch path. */
-
-#define PATHLENGTH 10
+static int constant_pool_entries_regcost;
/* This data describes a block that will be processed by cse_basic_block. */
@@ -588,125 +594,110 @@ struct cse_basic_block_data
except that it is used when the destination label is not preceded
by a BARRIER. */
enum taken {TAKEN, NOT_TAKEN, AROUND} status;
- } path[PATHLENGTH];
+ } *path;
};
+static bool fixed_base_plus_p (rtx x);
+static int notreg_cost (rtx, enum rtx_code);
+static int approx_reg_cost_1 (rtx *, void *);
+static int approx_reg_cost (rtx);
+static int preferrable (int, int, int, int);
+static void new_basic_block (void);
+static void make_new_qty (unsigned int, enum machine_mode);
+static void make_regs_eqv (unsigned int, unsigned int);
+static void delete_reg_equiv (unsigned int);
+static int mention_regs (rtx);
+static int insert_regs (rtx, struct table_elt *, int);
+static void remove_from_table (struct table_elt *, unsigned);
+static struct table_elt *lookup (rtx, unsigned, enum machine_mode);
+static struct table_elt *lookup_for_remove (rtx, unsigned, enum machine_mode);
+static rtx lookup_as_function (rtx, enum rtx_code);
+static struct table_elt *insert (rtx, struct table_elt *, unsigned,
+ enum machine_mode);
+static void merge_equiv_classes (struct table_elt *, struct table_elt *);
+static void invalidate (rtx, enum machine_mode);
+static int cse_rtx_varies_p (rtx, int);
+static void remove_invalid_refs (unsigned int);
+static void remove_invalid_subreg_refs (unsigned int, unsigned int,
+ enum machine_mode);
+static void rehash_using_reg (rtx);
+static void invalidate_memory (void);
+static void invalidate_for_call (void);
+static rtx use_related_value (rtx, struct table_elt *);
+static unsigned canon_hash (rtx, enum machine_mode);
+static unsigned canon_hash_string (const char *);
+static unsigned safe_hash (rtx, enum machine_mode);
+static int exp_equiv_p (rtx, rtx, int, int);
+static rtx canon_reg (rtx, rtx);
+static void find_best_addr (rtx, rtx *, enum machine_mode);
+static enum rtx_code find_comparison_args (enum rtx_code, rtx *, rtx *,
+ enum machine_mode *,
+ enum machine_mode *);
+static rtx fold_rtx (rtx, rtx);
+static rtx equiv_constant (rtx);
+static void record_jump_equiv (rtx, int);
+static void record_jump_cond (enum rtx_code, enum machine_mode, rtx, rtx,
+ int);
+static void cse_insn (rtx, rtx);
+static int addr_affects_sp_p (rtx);
+static void invalidate_from_clobbers (rtx);
+static rtx cse_process_notes (rtx, rtx);
+static void cse_around_loop (rtx);
+static void invalidate_skipped_set (rtx, rtx, void *);
+static void invalidate_skipped_block (rtx);
+static void cse_check_loop_start (rtx, rtx, void *);
+static void cse_set_around_loop (rtx, rtx, rtx);
+static rtx cse_basic_block (rtx, rtx, struct branch_path *, int);
+static void count_reg_usage (rtx, int *, int);
+static int check_for_label_ref (rtx *, void *);
+extern void dump_class (struct table_elt*);
+static struct cse_reg_info * get_cse_reg_info (unsigned int);
+static int check_dependence (rtx *, void *);
+
+static void flush_hash_table (void);
+static bool insn_live_p (rtx, int *);
+static bool set_live_p (rtx, rtx, int *);
+static bool dead_libcall_p (rtx, int *);
+static int cse_change_cc_mode (rtx *, void *);
+static void cse_change_cc_mode_insns (rtx, rtx, rtx);
+static enum machine_mode cse_cc_succs (basic_block, rtx, rtx, bool);
+
/* Nonzero if X has the form (PLUS frame-pointer integer). We check for
virtual regs here because the simplify_*_operation routines are called
- by integrate.c, which is called before virtual register instantiation.
-
- ?!? FIXED_BASE_PLUS_P and NONZERO_BASE_PLUS_P need to move into
- a header file so that their definitions can be shared with the
- simplification routines in simplify-rtx.c. Until then, do not
- change these macros without also changing the copy in simplify-rtx.c. */
-
-#define FIXED_BASE_PLUS_P(X) \
- ((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx \
- || ((X) == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM])\
- || (X) == virtual_stack_vars_rtx \
- || (X) == virtual_incoming_args_rtx \
- || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
- && (XEXP (X, 0) == frame_pointer_rtx \
- || XEXP (X, 0) == hard_frame_pointer_rtx \
- || ((X) == arg_pointer_rtx \
- && fixed_regs[ARG_POINTER_REGNUM]) \
- || XEXP (X, 0) == virtual_stack_vars_rtx \
- || XEXP (X, 0) == virtual_incoming_args_rtx)) \
- || GET_CODE (X) == ADDRESSOF)
-
-/* Similar, but also allows reference to the stack pointer.
-
- This used to include FIXED_BASE_PLUS_P, however, we can't assume that
- arg_pointer_rtx by itself is nonzero, because on at least one machine,
- the i960, the arg pointer is zero when it is unused. */
-
-#define NONZERO_BASE_PLUS_P(X) \
- ((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx \
- || (X) == virtual_stack_vars_rtx \
- || (X) == virtual_incoming_args_rtx \
- || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
- && (XEXP (X, 0) == frame_pointer_rtx \
- || XEXP (X, 0) == hard_frame_pointer_rtx \
- || ((X) == arg_pointer_rtx \
- && fixed_regs[ARG_POINTER_REGNUM]) \
- || XEXP (X, 0) == virtual_stack_vars_rtx \
- || XEXP (X, 0) == virtual_incoming_args_rtx)) \
- || (X) == stack_pointer_rtx \
- || (X) == virtual_stack_dynamic_rtx \
- || (X) == virtual_outgoing_args_rtx \
- || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
- && (XEXP (X, 0) == stack_pointer_rtx \
- || XEXP (X, 0) == virtual_stack_dynamic_rtx \
- || XEXP (X, 0) == virtual_outgoing_args_rtx)) \
- || GET_CODE (X) == ADDRESSOF)
-
-static int notreg_cost PARAMS ((rtx, enum rtx_code));
-static int approx_reg_cost_1 PARAMS ((rtx *, void *));
-static int approx_reg_cost PARAMS ((rtx));
-static int preferrable PARAMS ((int, int, int, int));
-static void new_basic_block PARAMS ((void));
-static void make_new_qty PARAMS ((unsigned int, enum machine_mode));
-static void make_regs_eqv PARAMS ((unsigned int, unsigned int));
-static void delete_reg_equiv PARAMS ((unsigned int));
-static int mention_regs PARAMS ((rtx));
-static int insert_regs PARAMS ((rtx, struct table_elt *, int));
-static void remove_from_table PARAMS ((struct table_elt *, unsigned));
-static struct table_elt *lookup PARAMS ((rtx, unsigned, enum machine_mode)),
- *lookup_for_remove PARAMS ((rtx, unsigned, enum machine_mode));
-static rtx lookup_as_function PARAMS ((rtx, enum rtx_code));
-static struct table_elt *insert PARAMS ((rtx, struct table_elt *, unsigned,
- enum machine_mode));
-static void merge_equiv_classes PARAMS ((struct table_elt *,
- struct table_elt *));
-static void invalidate PARAMS ((rtx, enum machine_mode));
-static int cse_rtx_varies_p PARAMS ((rtx, int));
-static void remove_invalid_refs PARAMS ((unsigned int));
-static void remove_invalid_subreg_refs PARAMS ((unsigned int, unsigned int,
- enum machine_mode));
-static void rehash_using_reg PARAMS ((rtx));
-static void invalidate_memory PARAMS ((void));
-static void invalidate_for_call PARAMS ((void));
-static rtx use_related_value PARAMS ((rtx, struct table_elt *));
-static unsigned canon_hash PARAMS ((rtx, enum machine_mode));
-static unsigned canon_hash_string PARAMS ((const char *));
-static unsigned safe_hash PARAMS ((rtx, enum machine_mode));
-static int exp_equiv_p PARAMS ((rtx, rtx, int, int));
-static rtx canon_reg PARAMS ((rtx, rtx));
-static void find_best_addr PARAMS ((rtx, rtx *, enum machine_mode));
-static enum rtx_code find_comparison_args PARAMS ((enum rtx_code, rtx *, rtx *,
- enum machine_mode *,
- enum machine_mode *));
-static rtx fold_rtx PARAMS ((rtx, rtx));
-static rtx equiv_constant PARAMS ((rtx));
-static void record_jump_equiv PARAMS ((rtx, int));
-static void record_jump_cond PARAMS ((enum rtx_code, enum machine_mode,
- rtx, rtx, int));
-static void cse_insn PARAMS ((rtx, rtx));
-static int addr_affects_sp_p PARAMS ((rtx));
-static void invalidate_from_clobbers PARAMS ((rtx));
-static rtx cse_process_notes PARAMS ((rtx, rtx));
-static void cse_around_loop PARAMS ((rtx));
-static void invalidate_skipped_set PARAMS ((rtx, rtx, void *));
-static void invalidate_skipped_block PARAMS ((rtx));
-static void cse_check_loop_start PARAMS ((rtx, rtx, void *));
-static void cse_set_around_loop PARAMS ((rtx, rtx, rtx));
-static rtx cse_basic_block PARAMS ((rtx, rtx, struct branch_path *, int));
-static void count_reg_usage PARAMS ((rtx, int *, rtx, int));
-static int check_for_label_ref PARAMS ((rtx *, void *));
-extern void dump_class PARAMS ((struct table_elt*));
-static struct cse_reg_info * get_cse_reg_info PARAMS ((unsigned int));
-static int check_dependence PARAMS ((rtx *, void *));
-
-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 *));
-
+ by integrate.c, which is called before virtual register instantiation. */
+
+static bool
+fixed_base_plus_p (rtx x)
+{
+ switch (GET_CODE (x))
+ {
+ case REG:
+ if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx)
+ return true;
+ if (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM])
+ return true;
+ if (REGNO (x) >= FIRST_VIRTUAL_REGISTER
+ && REGNO (x) <= LAST_VIRTUAL_REGISTER)
+ return true;
+ return false;
+
+ case PLUS:
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ return false;
+ return fixed_base_plus_p (XEXP (x, 0));
+
+ case ADDRESSOF:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
/* Dump the expressions in the equivalence class indicated by CLASSP.
This function is used only for debugging. */
void
-dump_class (classp)
- struct table_elt *classp;
+dump_class (struct table_elt *classp)
{
struct table_elt *elt;
@@ -724,9 +715,7 @@ dump_class (classp)
/* Subroutine of approx_reg_cost; called through for_each_rtx. */
static int
-approx_reg_cost_1 (xp, data)
- rtx *xp;
- void *data;
+approx_reg_cost_1 (rtx *xp, void *data)
{
rtx x = *xp;
int *cost_p = data;
@@ -757,8 +746,7 @@ approx_reg_cost_1 (xp, data)
0. If any other hard register reference occurs, return MAX_COST. */
static int
-approx_reg_cost (x)
- rtx x;
+approx_reg_cost (rtx x)
{
int cost = 0;
@@ -773,8 +761,7 @@ approx_reg_cost (x)
Return a positive value if A is less desirable, or 0 if the two are
equally good. */
static int
-preferrable (cost_a, regcost_a, cost_b, regcost_b)
- int cost_a, regcost_a, cost_b, regcost_b;
+preferrable (int cost_a, int regcost_a, int cost_b, int regcost_b)
{
/* First, get rid of cases involving expressions that are entirely
unwanted. */
@@ -808,9 +795,7 @@ preferrable (cost_a, regcost_a, cost_b, regcost_b)
from COST macro to keep it simple. */
static int
-notreg_cost (x, outer)
- rtx x;
- enum rtx_code outer;
+notreg_cost (rtx x, enum rtx_code outer)
{
return ((GET_CODE (x) == SUBREG
&& GET_CODE (SUBREG_REG (x)) == REG
@@ -831,9 +816,7 @@ notreg_cost (x, outer)
Other uses like the latter are expected in the future. */
int
-rtx_cost (x, outer_code)
- rtx x;
- enum rtx_code outer_code ATTRIBUTE_UNUSED;
+rtx_cost (rtx x, enum rtx_code outer_code ATTRIBUTE_UNUSED)
{
int i, j;
enum rtx_code code;
@@ -844,7 +827,7 @@ rtx_cost (x, outer_code)
return 0;
/* Compute the default costs of certain things.
- Note that RTX_COSTS can override the defaults. */
+ Note that targetm.rtx_costs can override the defaults. */
code = GET_CODE (x);
switch (code)
@@ -879,17 +862,9 @@ rtx_cost (x, outer_code)
+ GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD);
break;
-#ifdef RTX_COSTS
- RTX_COSTS (x, code, outer_code);
-#endif
-#ifdef CONST_COSTS
- CONST_COSTS (x, code, outer_code);
-#endif
-
default:
-#ifdef DEFAULT_RTX_COSTS
- DEFAULT_RTX_COSTS (x, code, outer_code);
-#endif
+ if ((*targetm.rtx_costs) (x, code, outer_code, &total))
+ return total;
break;
}
@@ -911,11 +886,9 @@ rtx_cost (x, outer_code)
Expect that X is properly formed address reference. */
int
-address_cost (x, mode)
- rtx x;
- enum machine_mode mode;
+address_cost (rtx x, enum machine_mode mode)
{
- /* The ADDRESS_COST macro does not deal with ADDRESSOF nodes. But,
+ /* The address_cost target hook does not deal with ADDRESSOF nodes. But,
during CSE, such nodes are present. Using an ADDRESSOF node which
refers to the address of a REG is a good thing because we can then
turn (MEM (ADDRESSSOF (REG))) into just plain REG. */
@@ -925,21 +898,24 @@ address_cost (x, mode)
/* We may be asked for cost of various unusual addresses, such as operands
of push instruction. It is not worthwhile to complicate writing
- of ADDRESS_COST macro by such cases. */
+ of the target hook by such cases. */
if (!memory_address_p (mode, x))
return 1000;
-#ifdef ADDRESS_COST
- return ADDRESS_COST (x);
-#else
- return rtx_cost (x, MEM);
-#endif
+
+ return (*targetm.address_cost) (x);
}
+/* If the target doesn't override, compute the cost as with arithmetic. */
+
+int
+default_address_cost (rtx x)
+{
+ return rtx_cost (x, MEM);
+}
static struct cse_reg_info *
-get_cse_reg_info (regno)
- unsigned int regno;
+get_cse_reg_info (unsigned int regno)
{
struct cse_reg_info **hash_head = &reg_hash[REGHASH_FN (regno)];
struct cse_reg_info *p;
@@ -957,7 +933,7 @@ get_cse_reg_info (regno)
cse_reg_info_free_list = p->next;
}
else
- p = (struct cse_reg_info *) xmalloc (sizeof (struct cse_reg_info));
+ p = xmalloc (sizeof (struct cse_reg_info));
/* Insert into hash table. */
p->hash_next = *hash_head;
@@ -987,7 +963,7 @@ get_cse_reg_info (regno)
for a new basic block. */
static void
-new_basic_block ()
+new_basic_block (void)
{
int i;
@@ -995,7 +971,7 @@ new_basic_block ()
/* Clear out hash table state for this pass. */
- memset ((char *) reg_hash, 0, sizeof reg_hash);
+ memset (reg_hash, 0, sizeof reg_hash);
if (cse_reg_info_used_list)
{
@@ -1032,9 +1008,8 @@ new_basic_block ()
}
}
- prev_insn = 0;
-
#ifdef HAVE_cc0
+ prev_insn = 0;
prev_insn_cc0 = 0;
#endif
}
@@ -1043,9 +1018,7 @@ new_basic_block ()
register before and initialize that quantity. */
static void
-make_new_qty (reg, mode)
- unsigned int reg;
- enum machine_mode mode;
+make_new_qty (unsigned int reg, enum machine_mode mode)
{
int q;
struct qty_table_elem *ent;
@@ -1070,8 +1043,7 @@ make_new_qty (reg, mode)
OLD is not changing; NEW is. */
static void
-make_regs_eqv (new, old)
- unsigned int new, old;
+make_regs_eqv (unsigned int new, unsigned int old)
{
unsigned int lastr, firstr;
int q = REG_QTY (old);
@@ -1134,8 +1106,7 @@ make_regs_eqv (new, old)
/* Remove REG from its equivalence class. */
static void
-delete_reg_equiv (reg)
- unsigned int reg;
+delete_reg_equiv (unsigned int reg)
{
struct qty_table_elem *ent;
int q = REG_QTY (reg);
@@ -1175,8 +1146,7 @@ delete_reg_equiv (reg)
of X. */
static int
-mention_regs (x)
- rtx x;
+mention_regs (rtx x)
{
enum rtx_code code;
int i, j;
@@ -1285,10 +1255,7 @@ mention_regs (x)
so X's hash code may be different. */
static int
-insert_regs (x, classp, modified)
- rtx x;
- struct table_elt *classp;
- int modified;
+insert_regs (rtx x, struct table_elt *classp, int modified)
{
if (GET_CODE (x) == REG)
{
@@ -1365,9 +1332,7 @@ insert_regs (x, classp, modified)
and we save much time not recomputing it. */
static void
-remove_from_table (elt, hash)
- struct table_elt *elt;
- unsigned hash;
+remove_from_table (struct table_elt *elt, unsigned int hash)
{
if (elt == 0)
return;
@@ -1450,10 +1415,7 @@ remove_from_table (elt, hash)
looks like X. */
static struct table_elt *
-lookup (x, hash, mode)
- rtx x;
- unsigned hash;
- enum machine_mode mode;
+lookup (rtx x, unsigned int hash, enum machine_mode mode)
{
struct table_elt *p;
@@ -1469,10 +1431,7 @@ lookup (x, hash, mode)
Also ignore discrepancies in the machine mode of a register. */
static struct table_elt *
-lookup_for_remove (x, hash, mode)
- rtx x;
- unsigned hash;
- enum machine_mode mode;
+lookup_for_remove (rtx x, unsigned int hash, enum machine_mode mode)
{
struct table_elt *p;
@@ -1501,9 +1460,7 @@ lookup_for_remove (x, hash, mode)
If one is found, return that expression. */
static rtx
-lookup_as_function (x, code)
- rtx x;
- enum rtx_code code;
+lookup_as_function (rtx x, enum rtx_code code)
{
struct table_elt *p
= lookup (x, safe_hash (x, VOIDmode) & HASH_MASK, GET_MODE (x));
@@ -1559,11 +1516,7 @@ lookup_as_function (x, code)
(preferrable ((X)->cost, (X)->regcost, (Y)->cost, (Y)->regcost) < 0)
static struct table_elt *
-insert (x, classp, hash, mode)
- rtx x;
- struct table_elt *classp;
- unsigned hash;
- enum machine_mode mode;
+insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mode)
{
struct table_elt *elt;
@@ -1591,7 +1544,7 @@ insert (x, classp, hash, mode)
else
{
n_elements_made++;
- elt = (struct table_elt *) xmalloc (sizeof (struct table_elt));
+ elt = xmalloc (sizeof (struct table_elt));
}
elt->exp = x;
@@ -1611,7 +1564,7 @@ insert (x, classp, hash, mode)
|| (GET_CODE (x) == REG
&& RTX_UNCHANGING_P (x)
&& REGNO (x) >= FIRST_PSEUDO_REGISTER)
- || FIXED_BASE_PLUS_P (x));
+ || fixed_base_plus_p (x));
if (table[hash])
table[hash]->prev_same_hash = elt;
@@ -1622,7 +1575,7 @@ insert (x, classp, hash, mode)
{
classp = classp->first_same_value;
if (CHEAPER (elt, classp))
- /* Insert at the head of the class */
+ /* Insert at the head of the class. */
{
struct table_elt *p;
elt->next_same_value = classp;
@@ -1749,8 +1702,7 @@ insert (x, classp, hash, mode)
Any invalid entries in CLASS2 will not be copied. */
static void
-merge_equiv_classes (class1, class2)
- struct table_elt *class1, *class2;
+merge_equiv_classes (struct table_elt *class1, struct table_elt *class2)
{
struct table_elt *elt, *next, *new;
@@ -1775,15 +1727,20 @@ merge_equiv_classes (class1, class2)
hash code (it also isn't necessary). */
if (GET_CODE (exp) == REG || exp_equiv_p (exp, exp, 1, 0))
{
+ bool need_rehash = false;
+
hash_arg_in_memory = 0;
hash = HASH (exp, mode);
if (GET_CODE (exp) == REG)
- delete_reg_equiv (REGNO (exp));
+ {
+ need_rehash = (unsigned) REG_QTY (REGNO (exp)) != REGNO (exp);
+ delete_reg_equiv (REGNO (exp));
+ }
remove_from_table (elt, hash);
- if (insert_regs (exp, class1, 0))
+ if (insert_regs (exp, class1, 0) || need_rehash)
{
rehash_using_reg (exp);
hash = HASH (exp, mode);
@@ -1797,7 +1754,7 @@ merge_equiv_classes (class1, class2)
/* Flush the entire hash table. */
static void
-flush_hash_table ()
+flush_hash_table (void)
{
int i;
struct table_elt *p;
@@ -1819,16 +1776,16 @@ struct check_dependence_data
{
enum machine_mode mode;
rtx exp;
+ rtx addr;
};
static int
-check_dependence (x, data)
- rtx *x;
- void *data;
+check_dependence (rtx *x, void *data)
{
struct check_dependence_data *d = (struct check_dependence_data *) data;
if (*x && GET_CODE (*x) == MEM)
- return true_dependence (d->exp, d->mode, *x, cse_rtx_varies_p);
+ return canon_true_dependence (d->exp, d->mode, d->addr, *x,
+ cse_rtx_varies_p);
else
return 0;
}
@@ -1846,12 +1803,11 @@ check_dependence (x, data)
or it may be either of those plus a numeric offset. */
static void
-invalidate (x, full_mode)
- rtx x;
- enum machine_mode full_mode;
+invalidate (rtx x, enum machine_mode full_mode)
{
int i;
struct table_elt *p;
+ rtx addr;
switch (GET_CODE (x))
{
@@ -1942,6 +1898,7 @@ invalidate (x, full_mode)
return;
case MEM:
+ addr = canon_rtx (get_addr (XEXP (x, 0)));
/* Calculate the canonical version of X here so that
true_dependence doesn't generate new RTL for X on each call. */
x = canon_rtx (x);
@@ -1969,6 +1926,7 @@ invalidate (x, full_mode)
if (!p->canon_exp)
p->canon_exp = canon_rtx (p->exp);
d.exp = x;
+ d.addr = addr;
d.mode = full_mode;
if (for_each_rtx (&p->canon_exp, check_dependence, &d))
remove_from_table (p, i);
@@ -1988,8 +1946,7 @@ invalidate (x, full_mode)
expressions to reappear as valid. */
static void
-remove_invalid_refs (regno)
- unsigned int regno;
+remove_invalid_refs (unsigned int regno)
{
unsigned int i;
struct table_elt *p, *next;
@@ -2007,10 +1964,8 @@ remove_invalid_refs (regno)
/* Likewise for a subreg with subreg_reg REGNO, subreg_byte OFFSET,
and mode MODE. */
static void
-remove_invalid_subreg_refs (regno, offset, mode)
- unsigned int regno;
- unsigned int offset;
- enum machine_mode mode;
+remove_invalid_subreg_refs (unsigned int regno, unsigned int offset,
+ enum machine_mode mode)
{
unsigned int i;
struct table_elt *p, *next;
@@ -2040,8 +1995,7 @@ remove_invalid_subreg_refs (regno, offset, mode)
This is called when we make a jump equivalence. */
static void
-rehash_using_reg (x)
- rtx x;
+rehash_using_reg (rtx x)
{
unsigned int i;
struct table_elt *p, *next;
@@ -2059,14 +2013,13 @@ rehash_using_reg (x)
return;
/* Scan all hash chains looking for valid entries that mention X.
- If we find one and it is in the wrong hash chain, move it. We can skip
- objects that are registers, since they are handled specially. */
+ If we find one and it is in the wrong hash chain, move it. */
for (i = 0; i < HASH_SIZE; i++)
for (p = table[i]; p; p = next)
{
next = p->next_same_hash;
- if (GET_CODE (p->exp) != REG && reg_mentioned_p (x, p->exp)
+ if (reg_mentioned_p (x, p->exp)
&& exp_equiv_p (p->exp, p->exp, 1, 0)
&& i != (hash = safe_hash (p->exp, p->mode) & HASH_MASK))
{
@@ -2091,7 +2044,7 @@ rehash_using_reg (x)
register. Also update their TICK values. */
static void
-invalidate_for_call ()
+invalidate_for_call (void)
{
unsigned int regno, endregno;
unsigned int i;
@@ -2150,9 +2103,7 @@ invalidate_for_call ()
If none can be found, return 0. */
static rtx
-use_related_value (x, elt)
- rtx x;
- struct table_elt *elt;
+use_related_value (rtx x, struct table_elt *elt)
{
struct table_elt *relt = 0;
struct table_elt *p, *q;
@@ -2220,8 +2171,7 @@ use_related_value (x, elt)
/* Hash a string. Just add its bytes up. */
static inline unsigned
-canon_hash_string (ps)
- const char *ps;
+canon_hash_string (const char *ps)
{
unsigned hash = 0;
const unsigned char *p = (const unsigned char *) ps;
@@ -2247,9 +2197,7 @@ canon_hash_string (ps)
is just (int) MEM plus the hash code of the address. */
static unsigned
-canon_hash (x, mode)
- rtx x;
- enum machine_mode mode;
+canon_hash (rtx x, enum machine_mode mode)
{
int i, j;
unsigned hash = 0;
@@ -2301,7 +2249,7 @@ canon_hash (x, mode)
record = false;
else
record = true;
-
+
if (!record)
{
do_not_record = 1;
@@ -2378,10 +2326,9 @@ canon_hash (x, mode)
do_not_record = 1;
return 0;
}
- if (! RTX_UNCHANGING_P (x) || FIXED_BASE_PLUS_P (XEXP (x, 0)))
- {
- hash_arg_in_memory = 1;
- }
+ if (! RTX_UNCHANGING_P (x) || fixed_base_plus_p (XEXP (x, 0)))
+ hash_arg_in_memory = 1;
+
/* Now that we have already found this special case,
might as well speed it up as much as possible. */
hash += (unsigned) MEM;
@@ -2399,7 +2346,7 @@ canon_hash (x, mode)
hash += (unsigned) USE;
x = XEXP (x, 0);
- if (! RTX_UNCHANGING_P (x) || FIXED_BASE_PLUS_P (XEXP (x, 0)))
+ if (! RTX_UNCHANGING_P (x) || fixed_base_plus_p (XEXP (x, 0)))
hash_arg_in_memory = 1;
/* Now that we have already found this special case,
@@ -2502,9 +2449,7 @@ canon_hash (x, mode)
/* Like canon_hash but with no side effects. */
static unsigned
-safe_hash (x, mode)
- rtx x;
- enum machine_mode mode;
+safe_hash (rtx x, enum machine_mode mode)
{
int save_do_not_record = do_not_record;
int save_hash_arg_in_memory = hash_arg_in_memory;
@@ -2530,10 +2475,7 @@ safe_hash (x, mode)
is the same as that of the given value is pure luck. */
static int
-exp_equiv_p (x, y, validate, equal_values)
- rtx x, y;
- int validate;
- int equal_values;
+exp_equiv_p (rtx x, rtx y, int validate, int equal_values)
{
int i, j;
enum rtx_code code;
@@ -2725,9 +2667,7 @@ exp_equiv_p (x, y, validate, equal_values)
against certain constants or near-constants. */
static int
-cse_rtx_varies_p (x, from_alias)
- rtx x;
- int from_alias;
+cse_rtx_varies_p (rtx x, int from_alias)
{
/* We need not check for X and the equivalence class being of the same
mode because if X is equivalent to a constant in some mode, it
@@ -2795,9 +2735,7 @@ cse_rtx_varies_p (x, from_alias)
generally be discarded since the changes we are making are optional. */
static rtx
-canon_reg (x, insn)
- rtx x;
- rtx insn;
+canon_reg (rtx x, rtx insn)
{
int i;
enum rtx_code code;
@@ -2886,26 +2824,20 @@ canon_reg (x, insn)
is a good approximation for that cost. However, most RISC machines have
only a few (usually only one) memory reference formats. If an address is
valid at all, it is often just as cheap as any other address. Hence, for
- RISC machines, we use the configuration macro `ADDRESS_COST' to compare the
- costs of various addresses. For two addresses of equal cost, choose the one
- with the highest `rtx_cost' value as that has the potential of eliminating
- the most insns. For equal costs, we choose the first in the equivalence
- class. Note that we ignore the fact that pseudo registers are cheaper
- than hard registers here because we would also prefer the pseudo registers.
- */
+ RISC machines, we use `address_cost' to compare the costs of various
+ addresses. For two addresses of equal cost, choose the one with the
+ highest `rtx_cost' value as that has the potential of eliminating the
+ most insns. For equal costs, we choose the first in the equivalence
+ class. Note that we ignore the fact that pseudo registers are cheaper than
+ hard registers here because we would also prefer the pseudo registers. */
static void
-find_best_addr (insn, loc, mode)
- rtx insn;
- rtx *loc;
- enum machine_mode mode;
+find_best_addr (rtx insn, rtx *loc, enum machine_mode mode)
{
struct table_elt *elt;
rtx addr = *loc;
-#ifdef ADDRESS_COST
struct table_elt *p;
int found_better = 1;
-#endif
int save_do_not_record = do_not_record;
int save_hash_arg_in_memory = hash_arg_in_memory;
int addr_volatile;
@@ -2969,22 +2901,6 @@ find_best_addr (insn, loc, mode)
elt = lookup (addr, hash, Pmode);
-#ifndef ADDRESS_COST
- if (elt)
- {
- int our_cost = elt->cost;
-
- /* Find the lowest cost below ours that works. */
- for (elt = elt->first_same_value; elt; elt = elt->next_same_value)
- if (elt->cost < our_cost
- && (GET_CODE (elt->exp) == REG
- || exp_equiv_p (elt->exp, elt->exp, 1, 0))
- && validate_change (insn, loc,
- canon_reg (copy_rtx (elt->exp), NULL_RTX), 0))
- return;
- }
-#else
-
if (elt)
{
/* We need to find the best (under the criteria documented above) entry
@@ -3043,10 +2959,9 @@ find_best_addr (insn, loc, mode)
if (flag_expensive_optimizations
&& (GET_RTX_CLASS (GET_CODE (*loc)) == '2'
|| GET_RTX_CLASS (GET_CODE (*loc)) == 'c')
- && GET_CODE (XEXP (*loc, 0)) == REG
- && GET_CODE (XEXP (*loc, 1)) == CONST_INT)
+ && GET_CODE (XEXP (*loc, 0)) == REG)
{
- rtx c = XEXP (*loc, 1);
+ rtx op1 = XEXP (*loc, 1);
do_not_record = 0;
hash = HASH (XEXP (*loc, 0), Pmode);
@@ -3088,7 +3003,7 @@ find_best_addr (insn, loc, mode)
|| exp_equiv_p (p->exp, p->exp, 1, 0)))
{
rtx new = simplify_gen_binary (GET_CODE (*loc), Pmode,
- p->exp, c);
+ p->exp, op1);
int new_cost;
new_cost = address_cost (new, mode);
@@ -3115,7 +3030,6 @@ find_best_addr (insn, loc, mode)
}
}
}
-#endif
}
/* Given an operation (CODE, *PARG1, *PARG2), where code is a comparison
@@ -3131,10 +3045,8 @@ find_best_addr (insn, loc, mode)
A or the code corresponding to the inverse of the comparison. */
static enum rtx_code
-find_comparison_args (code, parg1, parg2, pmode1, pmode2)
- enum rtx_code code;
- rtx *parg1, *parg2;
- enum machine_mode *pmode1, *pmode2;
+find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
+ enum machine_mode *pmode1, enum machine_mode *pmode2)
{
rtx arg1, arg2;
@@ -3276,9 +3188,10 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
break;
}
- /* If this is fp + constant, the equivalent is a better operand since
- it may let us predict the value of the comparison. */
- else if (NONZERO_BASE_PLUS_P (p->exp))
+ /* If this non-trapping address, e.g. fp + constant, the
+ equivalent is a better operand since it may let us predict
+ the value of the comparison. */
+ else if (!rtx_addr_can_trap_p (p->exp))
{
arg1 = p->exp;
continue;
@@ -3328,9 +3241,7 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
of X before modifying it. */
static rtx
-fold_rtx (x, insn)
- rtx x;
- rtx insn;
+fold_rtx (rtx x, rtx insn)
{
enum rtx_code code;
enum machine_mode mode;
@@ -3387,17 +3298,11 @@ fold_rtx (x, insn)
/* If the next insn is a CODE_LABEL followed by a jump table,
PC's value is a LABEL_REF pointing to that label. That
lets us fold switch statements on the VAX. */
- if (insn && GET_CODE (insn) == JUMP_INSN)
- {
- rtx next = next_nonnote_insn (insn);
-
- if (next && GET_CODE (next) == CODE_LABEL
- && NEXT_INSN (next) != 0
- && GET_CODE (NEXT_INSN (next)) == JUMP_INSN
- && (GET_CODE (PATTERN (NEXT_INSN (next))) == ADDR_VEC
- || GET_CODE (PATTERN (NEXT_INSN (next))) == ADDR_DIFF_VEC))
- return gen_rtx_LABEL_REF (Pmode, next);
- }
+ {
+ rtx next;
+ if (insn && tablejump_p (insn, &next, NULL))
+ return gen_rtx_LABEL_REF (Pmode, next);
+ }
break;
case SUBREG:
@@ -3637,7 +3542,10 @@ fold_rtx (x, insn)
rtx new;
if (CONSTANT_P (constant) && GET_CODE (constant) != CONST_INT)
- constant_pool_entries_cost = COST (constant);
+ {
+ constant_pool_entries_cost = COST (constant);
+ constant_pool_entries_regcost = approx_reg_cost (constant);
+ }
/* If we are loading the full constant, we have an equivalence. */
if (offset == 0 && mode == const_mode)
@@ -3850,6 +3758,23 @@ fold_rtx (x, insn)
|| (new_cost == old_cost && CONSTANT_P (XEXP (x, i))))
break;
+ /* It's not safe to substitute the operand of a conversion
+ operator with a constant, as the conversion's identity
+ depends upon the mode of it's operand. This optimization
+ is handled by the call to simplify_unary_operation. */
+ if (GET_RTX_CLASS (code) == '1'
+ && GET_MODE (replacements[j]) != mode_arg0
+ && (code == ZERO_EXTEND
+ || code == SIGN_EXTEND
+ || code == TRUNCATE
+ || code == FLOAT_TRUNCATE
+ || code == FLOAT_EXTEND
+ || code == FLOAT
+ || code == FIX
+ || code == UNSIGNED_FLOAT
+ || code == UNSIGNED_FIX))
+ continue;
+
if (validate_change (insn, &XEXP (x, i), replacements[j], 0))
break;
@@ -3891,10 +3816,11 @@ fold_rtx (x, insn)
|| code == LTGT || code == UNEQ || code == ORDERED
|| code == UNORDERED)
{
- if (must_swap || (const_arg0
- && (const_arg1 == 0
- || (GET_CODE (const_arg0) == CONST_INT
- && GET_CODE (const_arg1) != CONST_INT))))
+ if (must_swap
+ || swap_commutative_operands_p (const_arg0 ? const_arg0
+ : XEXP (x, 0),
+ const_arg1 ? const_arg1
+ : XEXP (x, 1)))
{
rtx tem = XEXP (x, 0);
@@ -3979,17 +3905,10 @@ fold_rtx (x, insn)
comparison. */
if (const_arg0 == 0 || const_arg1 == 0)
{
- /* Is FOLDED_ARG0 frame-pointer plus a constant? Or
- non-explicit constant? These aren't zero, but we
- don't know their sign. */
+ /* Some addresses are known to be nonzero. We don't know
+ their sign, but equality comparisons are known. */
if (const_arg1 == const0_rtx
- && (NONZERO_BASE_PLUS_P (folded_arg0)
-#if 0 /* Sad to say, on sysvr4, #pragma weak can make a symbol address
- come out as 0. */
- || GET_CODE (folded_arg0) == SYMBOL_REF
-#endif
- || GET_CODE (folded_arg0) == LABEL_REF
- || GET_CODE (folded_arg0) == CONST))
+ && nonzero_address_p (folded_arg0))
{
if (code == EQ)
return false_rtx;
@@ -4267,7 +4186,7 @@ fold_rtx (x, insn)
with a pre- or post-increment. Similarly for two subtracts of
identical powers of two with post decrement. */
- if (code == PLUS && INTVAL (const_arg1) == INTVAL (inner_const)
+ if (code == PLUS && const_arg1 == inner_const
&& ((HAVE_PRE_INCREMENT
&& exact_log2 (INTVAL (const_arg1)) >= 0)
|| (HAVE_POST_INCREMENT
@@ -4353,9 +4272,14 @@ fold_rtx (x, insn)
break;
case 'x':
- /* Always eliminate CONSTANT_P_RTX at this stage. */
+ /* Eliminate CONSTANT_P_RTX if its constant. */
if (code == CONSTANT_P_RTX)
- return (const_arg0 ? const1_rtx : const0_rtx);
+ {
+ if (const_arg0)
+ return const1_rtx;
+ if (optimize == 0 || !flag_gcse)
+ return const0_rtx;
+ }
break;
}
@@ -4366,8 +4290,7 @@ fold_rtx (x, insn)
Return 0 if we don't know one. */
static rtx
-equiv_constant (x)
- rtx x;
+equiv_constant (rtx x)
{
if (GET_CODE (x) == REG
&& REGNO_QTY_VALID_P (REGNO (x)))
@@ -4417,9 +4340,7 @@ equiv_constant (x)
This is similar to gen_lowpart in emit-rtl.c. */
rtx
-gen_lowpart_if_possible (mode, x)
- enum machine_mode mode;
- rtx x;
+gen_lowpart_if_possible (enum machine_mode mode, rtx x)
{
rtx result = gen_lowpart_common (mode, x);
@@ -4455,16 +4376,14 @@ gen_lowpart_if_possible (mode, x)
In certain cases, this can cause us to add an equivalence. For example,
if we are following the taken case of
- if (i == 2)
+ if (i == 2)
we can add the fact that `i' and '2' are now equivalent.
In any case, we can record that this comparison was passed. If the same
comparison is seen later, we will know its value. */
static void
-record_jump_equiv (insn, taken)
- rtx insn;
- int taken;
+record_jump_equiv (rtx insn, int taken)
{
int cond_known_true;
rtx op0, op1;
@@ -4515,11 +4434,8 @@ record_jump_equiv (insn, taken)
above function and called recursively. */
static void
-record_jump_cond (code, mode, op0, op1, reversed_nonequality)
- enum rtx_code code;
- enum machine_mode mode;
- rtx op0, op1;
- int reversed_nonequality;
+record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
+ rtx op1, int reversed_nonequality)
{
unsigned op0_hash, op1_hash;
int op0_in_memory, op1_in_memory;
@@ -4755,8 +4671,10 @@ struct set
/* Nonzero if the SET_SRC contains something
whose value cannot be predicted and understood. */
char src_volatile;
- /* Original machine mode, in case it becomes a CONST_INT. */
- enum machine_mode mode;
+ /* Original machine mode, in case it becomes a CONST_INT.
+ The size of this field should match the size of the mode
+ field of struct rtx_def (see rtl.h). */
+ ENUM_BITFIELD(machine_mode) mode : 8;
/* A constant equivalent for SET_SRC, if any. */
rtx src_const;
/* Original SET_SRC value used for libcall notes. */
@@ -4768,9 +4686,7 @@ struct set
};
static void
-cse_insn (insn, libcall_insn)
- rtx insn;
- rtx libcall_insn;
+cse_insn (rtx insn, rtx libcall_insn)
{
rtx x = PATTERN (insn);
int i;
@@ -4810,7 +4726,7 @@ cse_insn (insn, libcall_insn)
if (GET_CODE (x) == SET)
{
- sets = (struct set *) alloca (sizeof (struct set));
+ sets = alloca (sizeof (struct set));
sets[0].rtl = x;
/* Ignore SETs that are unconditional jumps.
@@ -4845,7 +4761,7 @@ cse_insn (insn, libcall_insn)
{
int lim = XVECLEN (x, 0);
- sets = (struct set *) alloca (lim * sizeof (struct set));
+ sets = alloca (lim * sizeof (struct set));
/* Find all regs explicitly clobbered in this insn,
and ensure they are not replaced with any other regs
@@ -5529,7 +5445,11 @@ cse_insn (insn, libcall_insn)
{
trial = src_folded, src_folded_cost = MAX_COST;
if (src_folded_force_flag)
- trial = force_const_mem (mode, trial);
+ {
+ rtx forced = force_const_mem (mode, trial);
+ if (forced)
+ trial = forced;
+ }
}
else if (src
&& preferrable (src_cost, src_regcost,
@@ -5578,6 +5498,8 @@ cse_insn (insn, libcall_insn)
/* Look for a substitution that makes a valid insn. */
else if (validate_change (insn, &SET_SRC (sets[i].rtl), trial, 0))
{
+ rtx new = canon_reg (SET_SRC (sets[i].rtl), insn);
+
/* If we just made a substitution inside a libcall, then we
need to make the same substitution in any notes attached
to the RETVAL insn. */
@@ -5585,15 +5507,13 @@ cse_insn (insn, libcall_insn)
&& (GET_CODE (sets[i].orig_src) == REG
|| GET_CODE (sets[i].orig_src) == SUBREG
|| GET_CODE (sets[i].orig_src) == MEM))
- replace_rtx (REG_NOTES (libcall_insn), sets[i].orig_src,
- canon_reg (SET_SRC (sets[i].rtl), insn));
+ simplify_replace_rtx (REG_NOTES (libcall_insn),
+ sets[i].orig_src, copy_rtx (new));
/* The result of apply_change_group can be ignored; see
canon_reg. */
- validate_change (insn, &SET_SRC (sets[i].rtl),
- canon_reg (SET_SRC (sets[i].rtl), insn),
- 1);
+ validate_change (insn, &SET_SRC (sets[i].rtl), new, 1);
apply_change_group ();
break;
}
@@ -5624,6 +5544,7 @@ cse_insn (insn, libcall_insn)
src_folded_force_flag = 1;
src_folded = trial;
src_folded_cost = constant_pool_entries_cost;
+ src_folded_regcost = constant_pool_entries_regcost;
}
}
@@ -5706,46 +5627,15 @@ cse_insn (insn, libcall_insn)
&& GET_CODE (XEXP (XEXP (src_const, 0), 0)) == LABEL_REF
&& GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF))
{
- /* Make sure that the rtx is not shared with any other insn. */
- src_const = copy_rtx (src_const);
-
- /* Record the actual constant value in a REG_EQUAL note, making
- a new one if one does not already exist. */
- set_unique_reg_note (insn, REG_EQUAL, src_const);
-
- /* If storing a constant value in a register that
- previously held the constant value 0,
- record this fact with a REG_WAS_0 note on this insn.
-
- Note that the *register* is required to have previously held 0,
- not just any register in the quantity and we must point to the
- insn that set that register to zero.
-
- Rather than track each register individually, we just see if
- the last set for this quantity was for this register. */
-
- if (REGNO_QTY_VALID_P (REGNO (dest)))
+ /* We only want a REG_EQUAL note if src_const != src. */
+ if (! rtx_equal_p (src, src_const))
{
- int dest_q = REG_QTY (REGNO (dest));
- struct qty_table_elem *dest_ent = &qty_table[dest_q];
-
- if (dest_ent->const_rtx == const0_rtx)
- {
- /* See if we previously had a REG_WAS_0 note. */
- rtx note = find_reg_note (insn, REG_WAS_0, NULL_RTX);
- rtx const_insn = dest_ent->const_insn;
+ /* Make sure that the rtx is not shared. */
+ src_const = copy_rtx (src_const);
- if ((tem = single_set (const_insn)) != 0
- && rtx_equal_p (SET_DEST (tem), dest))
- {
- if (note)
- XEXP (note, 0) = const_insn;
- else
- REG_NOTES (insn)
- = gen_rtx_INSN_LIST (REG_WAS_0, const_insn,
- REG_NOTES (insn));
- }
- }
+ /* Record the actual constant value in a REG_EQUAL note,
+ making a new one if one does not already exist. */
+ set_unique_reg_note (insn, REG_EQUAL, src_const);
}
}
@@ -5966,6 +5856,16 @@ cse_insn (insn, libcall_insn)
enum machine_mode mode
= GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src);
+ /* It's possible that we have a source value known to be
+ constant but don't have a REG_EQUAL note on the insn.
+ Lack of a note will mean src_eqv_elt will be NULL. This
+ can happen where we've generated a SUBREG to access a
+ CONST_INT that is already in a register in a wider mode.
+ Ensure that the source expression is put in the proper
+ constant class. */
+ if (!classp)
+ classp = sets[i].src_const_elt;
+
if (sets[i].src_elt == 0)
{
/* Don't put a hard register source into the table if this is
@@ -6189,7 +6089,7 @@ cse_insn (insn, libcall_insn)
elt->in_memory = (GET_CODE (sets[i].inner_dest) == MEM
&& (! RTX_UNCHANGING_P (sets[i].inner_dest)
- || FIXED_BASE_PLUS_P (XEXP (sets[i].inner_dest,
+ || fixed_base_plus_p (XEXP (sets[i].inner_dest,
0))));
/* If we have (set (subreg:m1 (reg:m2 foo) 0) (bar:m1)), M1 is no
@@ -6325,7 +6225,7 @@ cse_insn (insn, libcall_insn)
}
while (prev && GET_CODE (prev) == NOTE
&& NOTE_LINE_NUMBER (prev) != NOTE_INSN_BASIC_BLOCK);
-
+
/* Do not swap the registers around if the previous instruction
attaches a REG_EQUIV note to REG1.
@@ -6352,20 +6252,6 @@ cse_insn (insn, libcall_insn)
validate_change (insn, &SET_SRC (sets[0].rtl), dest, 1);
apply_change_group ();
- /* If there was a REG_WAS_0 note on PREV, remove it. Move
- any REG_WAS_0 note on INSN to PREV. */
- note = find_reg_note (prev, REG_WAS_0, NULL_RTX);
- if (note)
- remove_note (prev, note);
-
- note = find_reg_note (insn, REG_WAS_0, NULL_RTX);
- if (note)
- {
- remove_note (insn, note);
- XEXP (note, 1) = REG_NOTES (prev);
- REG_NOTES (prev) = note;
- }
-
/* If INSN has a REG_EQUAL note, and this note mentions
REG0, then we must delete it, because the value in
REG0 has changed. If the note's value is REG1, we must
@@ -6400,15 +6286,14 @@ cse_insn (insn, libcall_insn)
prev_insn_cc0 = this_insn_cc0;
prev_insn_cc0_mode = this_insn_cc0_mode;
-#endif
-
prev_insn = insn;
+#endif
}
/* Remove from the hash table all expressions that reference memory. */
static void
-invalidate_memory ()
+invalidate_memory (void)
{
int i;
struct table_elt *p, *next;
@@ -6426,8 +6311,7 @@ invalidate_memory ()
1 and update the register tables to show the effect. Else, return 0. */
static int
-addr_affects_sp_p (addr)
- rtx addr;
+addr_affects_sp_p (rtx addr)
{
if (GET_RTX_CLASS (GET_CODE (addr)) == 'a'
&& GET_CODE (XEXP (addr, 0)) == REG
@@ -6458,8 +6342,7 @@ addr_affects_sp_p (addr)
X is the pattern of the insn. */
static void
-invalidate_from_clobbers (x)
- rtx x;
+invalidate_from_clobbers (rtx x)
{
if (GET_CODE (x) == CLOBBER)
{
@@ -6504,9 +6387,7 @@ invalidate_from_clobbers (x)
Return the replacement for X. */
static rtx
-cse_process_notes (x, object)
- rtx x;
- rtx object;
+cse_process_notes (rtx x, rtx object)
{
enum rtx_code code = GET_CODE (x);
const char *fmt = GET_RTX_FORMAT (code);
@@ -6598,8 +6479,7 @@ cse_process_notes (x, object)
jumps to a label used only once. */
static void
-cse_around_loop (loop_start)
- rtx loop_start;
+cse_around_loop (rtx loop_start)
{
rtx insn;
int i;
@@ -6670,10 +6550,7 @@ cse_around_loop (loop_start)
since they are done elsewhere. This function is called via note_stores. */
static void
-invalidate_skipped_set (dest, set, data)
- rtx set;
- rtx dest;
- void *data ATTRIBUTE_UNUSED;
+invalidate_skipped_set (rtx dest, rtx set, void *data ATTRIBUTE_UNUSED)
{
enum rtx_code code = GET_CODE (dest);
@@ -6692,9 +6569,7 @@ invalidate_skipped_set (dest, set, data)
}
if (GET_CODE (set) == CLOBBER
-#ifdef HAVE_cc0
- || dest == cc0_rtx
-#endif
+ || CC0_P (dest)
|| dest == pc_rtx)
return;
@@ -6709,8 +6584,7 @@ invalidate_skipped_set (dest, set, data)
conditionally executed. */
static void
-invalidate_skipped_block (start)
- rtx start;
+invalidate_skipped_block (rtx start)
{
rtx insn;
@@ -6737,10 +6611,7 @@ invalidate_skipped_block (start)
NULL_RTX. */
static void
-cse_check_loop_start (x, set, data)
- rtx x;
- rtx set ATTRIBUTE_UNUSED;
- void *data;
+cse_check_loop_start (rtx x, rtx set ATTRIBUTE_UNUSED, void *data)
{
rtx *cse_check_loop_start_value = (rtx *) data;
@@ -6771,10 +6642,7 @@ cse_check_loop_start (x, set, data)
In any event, we invalidate whatever this SET or CLOBBER modifies. */
static void
-cse_set_around_loop (x, insn, loop_start)
- rtx x;
- rtx insn;
- rtx loop_start;
+cse_set_around_loop (rtx x, rtx insn, rtx loop_start)
{
struct table_elt *src_elt;
@@ -6826,6 +6694,8 @@ cse_set_around_loop (x, insn, loop_start)
SET_SRC, add an insn after P to copy its destination
to what we will be replacing SET_SRC with. */
if (cse_check_loop_start_value
+ && single_set (p)
+ && !can_throw_internal (insn)
&& validate_change (insn, &SET_SRC (x),
src_elt->exp, 0))
{
@@ -6845,6 +6715,10 @@ cse_set_around_loop (x, insn, loop_start)
}
else
{
+ if (CONSTANT_P (SET_SRC (set))
+ && ! find_reg_equal_equiv_note (insn))
+ set_unique_reg_note (insn, REG_EQUAL,
+ SET_SRC (set));
if (control_flow_insn_p (p))
/* p can cause a control flow transfer so it
is the last insn of a basic block. We can't
@@ -6887,12 +6761,8 @@ cse_set_around_loop (x, insn, loop_start)
to construct the output branch path. */
void
-cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
- rtx insn;
- struct cse_basic_block_data *data;
- int follow_jumps;
- int after_loop;
- int skip_blocks;
+cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
+ int follow_jumps, int after_loop, int skip_blocks)
{
rtx p = insn, q;
int nsets = 0;
@@ -6989,7 +6859,7 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
In this case invalidate_skipped_block will be called to invalidate any
registers set in the block when following the jump. */
- else if ((follow_jumps || skip_blocks) && path_size < PATHLENGTH - 1
+ else if ((follow_jumps || skip_blocks) && path_size < PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH) - 1
&& GET_CODE (p) == JUMP_INSN
&& GET_CODE (PATTERN (p)) == SET
&& GET_CODE (SET_SRC (PATTERN (p))) == IF_THEN_ELSE
@@ -7109,19 +6979,19 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
in conditional jump instructions. */
int
-cse_main (f, nregs, after_loop, file)
- rtx f;
- int nregs;
- int after_loop;
- FILE *file;
+cse_main (rtx f, int nregs, int after_loop, FILE *file)
{
struct cse_basic_block_data val;
rtx insn = f;
int i;
+ val.path = xmalloc (sizeof (struct branch_path)
+ * PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH));
+
cse_jumps_altered = 0;
recorded_label_ref = 0;
constant_pool_entries_cost = 0;
+ constant_pool_entries_regcost = 0;
val.path_size = 0;
init_recog ();
@@ -7131,8 +7001,7 @@ cse_main (f, nregs, after_loop, file)
max_insn_uid = get_max_uid ();
- reg_eqv_table = (struct reg_eqv_elem *)
- xmalloc (nregs * sizeof (struct reg_eqv_elem));
+ reg_eqv_table = xmalloc (nregs * sizeof (struct reg_eqv_elem));
#ifdef LOAD_EXTEND_OP
@@ -7148,7 +7017,7 @@ cse_main (f, nregs, after_loop, file)
/* Find the largest uid. */
max_uid = get_max_uid ();
- uid_cuid = (int *) xcalloc (max_uid + 1, sizeof (int));
+ uid_cuid = xcalloc (max_uid + 1, sizeof (int));
/* Compute the mapping from uids to cuids.
CUIDs are numbers assigned to insns, like uids,
@@ -7242,6 +7111,7 @@ cse_main (f, nregs, after_loop, file)
end_alias_analysis ();
free (uid_cuid);
free (reg_eqv_table);
+ free (val.path);
return cse_jumps_altered || recorded_label_ref;
}
@@ -7255,22 +7125,19 @@ cse_main (f, nregs, after_loop, file)
block and this CSE pass is before loop.c. */
static rtx
-cse_basic_block (from, to, next_branch, around_loop)
- rtx from, to;
- struct branch_path *next_branch;
- int around_loop;
+cse_basic_block (rtx from, rtx to, struct branch_path *next_branch,
+ int around_loop)
{
rtx insn;
int to_usage = 0;
rtx libcall_insn = NULL_RTX;
int num_insns = 0;
+ int no_conflict = 0;
/* This array is undefined before max_reg, so only allocate
the space actually needed and adjust the start. */
- qty_table
- = (struct qty_table_elem *) xmalloc ((max_qty - max_reg)
- * sizeof (struct qty_table_elem));
+ qty_table = xmalloc ((max_qty - max_reg) * sizeof (struct qty_table_elem));
qty_table -= max_reg;
new_basic_block ();
@@ -7314,8 +7181,8 @@ cse_basic_block (from, to, next_branch, around_loop)
Then follow this branch. */
#ifdef HAVE_cc0
prev_insn_cc0 = 0;
-#endif
prev_insn = insn;
+#endif
insn = JUMP_LABEL (insn);
continue;
}
@@ -7345,11 +7212,26 @@ cse_basic_block (from, to, next_branch, around_loop)
if ((p = find_reg_note (insn, REG_LIBCALL, NULL_RTX)))
libcall_insn = XEXP (p, 0);
else if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
- libcall_insn = 0;
+ {
+ /* Keep libcall_insn for the last SET insn of a no-conflict
+ block to prevent changing the destination. */
+ if (! no_conflict)
+ libcall_insn = 0;
+ else
+ no_conflict = -1;
+ }
+ else if (find_reg_note (insn, REG_NO_CONFLICT, NULL_RTX))
+ no_conflict = 1;
}
cse_insn (insn, libcall_insn);
+ if (no_conflict == -1)
+ {
+ libcall_insn = 0;
+ no_conflict = 0;
+ }
+
/* If we haven't already found an insn where we added a LABEL_REF,
check this one. */
if (GET_CODE (insn) == INSN && ! recorded_label_ref
@@ -7419,7 +7301,10 @@ cse_basic_block (from, to, next_branch, around_loop)
following branches in this case. */
to_usage = 0;
val.path_size = 0;
+ val.path = xmalloc (sizeof (struct branch_path)
+ * PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH));
cse_end_of_basic_block (insn, &val, 0, 0, 0);
+ free (val.path);
/* If the tables we allocated have enough space left
to handle all the SETs in the next basic block,
@@ -7468,9 +7353,7 @@ cse_basic_block (from, to, next_branch, around_loop)
there isn't a REG_LABEL note. Return one if so. DATA is the insn. */
static int
-check_for_label_ref (rtl, data)
- rtx *rtl;
- void *data;
+check_for_label_ref (rtx *rtl, void *data)
{
rtx insn = (rtx) data;
@@ -7487,18 +7370,10 @@ check_for_label_ref (rtl, data)
/* Count the number of times registers are used (not set) in X.
COUNTS is an array in which we accumulate the count, INCR is how much
- we count each register usage.
-
- Don't count a usage of DEST, which is the SET_DEST of a SET which
- contains X in its SET_SRC. This is because such a SET does not
- modify the liveness of DEST. */
+ we count each register usage. */
static void
-count_reg_usage (x, counts, dest, incr)
- rtx x;
- int *counts;
- rtx dest;
- int incr;
+count_reg_usage (rtx x, int *counts, int incr)
{
enum rtx_code code;
rtx note;
@@ -7511,8 +7386,7 @@ count_reg_usage (x, counts, dest, incr)
switch (code = GET_CODE (x))
{
case REG:
- if (x != dest)
- counts[REGNO (x)] += incr;
+ counts[REGNO (x)] += incr;
return;
case PC:
@@ -7529,39 +7403,61 @@ count_reg_usage (x, counts, dest, incr)
/* If we are clobbering a MEM, mark any registers inside the address
as being used. */
if (GET_CODE (XEXP (x, 0)) == MEM)
- count_reg_usage (XEXP (XEXP (x, 0), 0), counts, NULL_RTX, incr);
+ count_reg_usage (XEXP (XEXP (x, 0), 0), counts, incr);
return;
case SET:
/* Unless we are setting a REG, count everything in SET_DEST. */
if (GET_CODE (SET_DEST (x)) != REG)
- count_reg_usage (SET_DEST (x), counts, NULL_RTX, incr);
-
- /* If SRC has side-effects, then we can't delete this insn, so the
- usage of SET_DEST inside SRC counts.
-
- ??? Strictly-speaking, we might be preserving this insn
- because some other SET has side-effects, but that's hard
- to do and can't happen now. */
- count_reg_usage (SET_SRC (x), counts,
- side_effects_p (SET_SRC (x)) ? NULL_RTX : SET_DEST (x),
- incr);
+ count_reg_usage (SET_DEST (x), counts, incr);
+ count_reg_usage (SET_SRC (x), counts, incr);
return;
case CALL_INSN:
- count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, NULL_RTX, incr);
+ count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, incr);
/* Fall through. */
case INSN:
case JUMP_INSN:
- count_reg_usage (PATTERN (x), counts, NULL_RTX, incr);
+ count_reg_usage (PATTERN (x), counts, incr);
/* Things used in a REG_EQUAL note aren't dead since loop may try to
use them. */
note = find_reg_equal_equiv_note (x);
if (note)
- count_reg_usage (XEXP (note, 0), counts, NULL_RTX, incr);
+ {
+ rtx eqv = XEXP (note, 0);
+
+ if (GET_CODE (eqv) == EXPR_LIST)
+ /* This REG_EQUAL note describes the result of a function call.
+ Process all the arguments. */
+ do
+ {
+ count_reg_usage (XEXP (eqv, 0), counts, incr);
+ eqv = XEXP (eqv, 1);
+ }
+ while (eqv && GET_CODE (eqv) == EXPR_LIST);
+ else
+ count_reg_usage (eqv, counts, incr);
+ }
+ return;
+
+ case EXPR_LIST:
+ if (REG_NOTE_KIND (x) == REG_EQUAL
+ || (REG_NOTE_KIND (x) != REG_NONNEG && GET_CODE (XEXP (x,0)) == USE)
+ /* FUNCTION_USAGE expression lists may include (CLOBBER (mem /u)),
+ involving registers in the address. */
+ || GET_CODE (XEXP (x, 0)) == CLOBBER)
+ count_reg_usage (XEXP (x, 0), counts, incr);
+
+ count_reg_usage (XEXP (x, 1), counts, incr);
+ return;
+
+ case ASM_OPERANDS:
+ /* Iterate over just the inputs, not the constraints as well. */
+ for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
+ count_reg_usage (ASM_OPERANDS_INPUT (x, i), counts, incr);
return;
case INSN_LIST:
@@ -7575,19 +7471,17 @@ count_reg_usage (x, counts, dest, incr)
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
- count_reg_usage (XEXP (x, i), counts, dest, incr);
+ count_reg_usage (XEXP (x, i), counts, incr);
else if (fmt[i] == 'E')
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- count_reg_usage (XVECEXP (x, i, j), counts, dest, incr);
+ count_reg_usage (XVECEXP (x, i, j), counts, incr);
}
}
/* Return true if set is live. */
static bool
-set_live_p (set, insn, counts)
- rtx set;
- rtx insn ATTRIBUTE_UNUSED; /* Only used with HAVE_cc0. */
- int *counts;
+set_live_p (rtx set, rtx insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0. */
+ int *counts)
{
#ifdef HAVE_cc0
rtx tem;
@@ -7620,9 +7514,7 @@ set_live_p (set, insn, counts)
/* Return true if insn is live. */
static bool
-insn_live_p (insn, counts)
- rtx insn;
- int *counts;
+insn_live_p (rtx insn, int *counts)
{
int i;
if (flag_non_call_exceptions && may_trap_p (PATTERN (insn)))
@@ -7652,37 +7544,51 @@ insn_live_p (insn, counts)
/* Return true if libcall is dead as a whole. */
static bool
-dead_libcall_p (insn, counts)
- rtx insn;
- int *counts;
+dead_libcall_p (rtx insn, int *counts)
{
- rtx note;
+ rtx note, set, new;
+
/* See if there's a REG_EQUAL note on this insn and try to
replace the source with the REG_EQUAL expression.
We assume that insns with REG_RETVALs can only be reg->reg
copies at this point. */
note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
- if (note)
- {
- rtx set = single_set (insn);
- rtx new = simplify_rtx (XEXP (note, 0));
+ if (!note)
+ return false;
- if (!new)
- new = XEXP (note, 0);
+ set = single_set (insn);
+ if (!set)
+ return false;
+
+ new = simplify_rtx (XEXP (note, 0));
+ if (!new)
+ new = XEXP (note, 0);
- /* While changing insn, we must update the counts accordingly. */
- count_reg_usage (insn, counts, NULL_RTX, -1);
+ /* While changing insn, we must update the counts accordingly. */
+ count_reg_usage (insn, counts, -1);
+
+ if (validate_change (insn, &SET_SRC (set), new, 0))
+ {
+ count_reg_usage (insn, counts, 1);
+ remove_note (insn, find_reg_note (insn, REG_RETVAL, NULL_RTX));
+ remove_note (insn, note);
+ return true;
+ }
- if (set && validate_change (insn, &SET_SRC (set), new, 0))
+ if (CONSTANT_P (new))
+ {
+ new = force_const_mem (GET_MODE (SET_DEST (set)), new);
+ if (new && validate_change (insn, &SET_SRC (set), new, 0))
{
- count_reg_usage (insn, counts, NULL_RTX, 1);
+ count_reg_usage (insn, counts, 1);
remove_note (insn, find_reg_note (insn, REG_RETVAL, NULL_RTX));
remove_note (insn, note);
return true;
}
- count_reg_usage (insn, counts, NULL_RTX, 1);
}
+
+ count_reg_usage (insn, counts, 1);
return false;
}
@@ -7695,9 +7601,7 @@ dead_libcall_p (insn, counts)
remaining passes of the compilation are also sped up. */
int
-delete_trivially_dead_insns (insns, nreg)
- rtx insns;
- int nreg;
+delete_trivially_dead_insns (rtx insns, int nreg)
{
int *counts;
rtx insn, prev;
@@ -7706,9 +7610,9 @@ delete_trivially_dead_insns (insns, nreg)
timevar_push (TV_DELETE_TRIVIALLY_DEAD);
/* First count the number of times each register is used. */
- counts = (int *) xcalloc (nreg, sizeof (int));
+ counts = xcalloc (nreg, sizeof (int));
for (insn = next_real_insn (insns); insn; insn = next_real_insn (insn))
- count_reg_usage (insn, counts, NULL_RTX, 1);
+ count_reg_usage (insn, counts, 1);
do
{
@@ -7752,7 +7656,7 @@ delete_trivially_dead_insns (insns, nreg)
if (! live_insn)
{
- count_reg_usage (insn, counts, NULL_RTX, -1);
+ count_reg_usage (insn, counts, -1);
delete_insn_and_edges (insn);
ndead++;
}
@@ -7774,3 +7678,350 @@ 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 (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 (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 (basic_block bb, rtx cc_reg, rtx cc_src, bool 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 (BB_END (e->dest));
+ for (insn = BB_HEAD (e->dest); 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 (void)
+{
+ 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 (bb);
+ 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 (bb));
+ 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);
+ }
+ }
+ }
+}
OpenPOWER on IntegriCloud