#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
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))
/* 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)))
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. */
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 PARAMS ((rtx x));
-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 *));
+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 *);
\f
/* 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. */
static bool
-fixed_base_plus_p (x)
- rtx x;
+fixed_base_plus_p (rtx x)
{
switch (GET_CODE (x))
{
/* 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;
/* 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;
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;
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. */
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
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;
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 target hook does not deal with ADDRESSOF nodes. But,
during CSE, such nodes are present. Using an ADDRESSOF node which
/* If the target doesn't override, compute the cost as with arithmetic. */
int
-default_address_cost (x)
- rtx x;
+default_address_cost (rtx x)
{
return rtx_cost (x, MEM);
}
\f
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 = ®_hash[REGHASH_FN (regno)];
struct cse_reg_info *p;
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;
for a new basic block. */
static void
-new_basic_block ()
+new_basic_block (void)
{
int i;
/* 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)
{
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;
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);
/* 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);
of X. */
static int
-mention_regs (x)
- rtx x;
+mention_regs (rtx x)
{
enum rtx_code code;
int i, j;
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)
{
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;
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;
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;
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));
(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;
else
{
n_elements_made++;
- elt = (struct table_elt *) xmalloc (sizeof (struct table_elt));
+ elt = xmalloc (sizeof (struct table_elt));
}
elt->exp = x;
{
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;
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;
/* Flush the entire hash table. */
static void
-flush_hash_table ()
+flush_hash_table (void)
{
int i;
struct table_elt *p;
};
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)
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;
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;
/* 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;
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;
register. Also update their TICK values. */
static void
-invalidate_for_call ()
+invalidate_for_call (void)
{
unsigned int regno, endregno;
unsigned int i;
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;
\f
/* 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;
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;
record = false;
else
record = true;
-
+
if (!record)
{
do_not_record = 1;
/* 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;
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;
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
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;
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;
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);
|| 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);
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;
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;
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)
|| 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);
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
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)))
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);
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;
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;
};
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;
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.
{
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
{
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,
&& (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,
- copy_rtx (new));
+ 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. */
src_folded_force_flag = 1;
src_folded = trial;
src_folded_cost = constant_pool_entries_cost;
+ src_folded_regcost = constant_pool_entries_regcost;
}
}
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)))
- {
- 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;
-
- 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));
- }
- }
- }
}
/* Now deal with the destination. */
}
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.
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
/* Remove from the hash table all expressions that reference memory. */
static void
-invalidate_memory ()
+invalidate_memory (void)
{
int i;
struct table_elt *p, *next;
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
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)
{
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);
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;
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);
conditionally executed. */
static void
-invalidate_skipped_block (start)
- rtx start;
+invalidate_skipped_block (rtx start)
{
rtx insn;
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;
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;
abort ();
}
else
- emit_insn_after (move, p);
+ {
+ 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
+ therefore use emit_insn_after. */
+ emit_insn_before (move, next_nonnote_insn (p));
+ else
+ emit_insn_after (move, p);
+ }
}
break;
}
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;
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
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 ();
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
/* 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,
end_alias_analysis ();
free (uid_cuid);
free (reg_eqv_table);
+ free (val.path);
return cse_jumps_altered || recorded_label_ref;
}
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;
/* 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 ();
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,
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;
\f
/* 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;
switch (code = GET_CODE (x))
{
case REG:
- if (x != dest)
- counts[REGNO (x)] += incr;
+ counts[REGNO (x)] += incr;
return;
case PC:
/* 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);
- count_reg_usage (SET_SRC (x), counts,
- 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:
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);
}
}
\f
/* 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;
/* 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)))
/* 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;
+
+ set = single_set (insn);
+ if (!set)
+ return false;
- if (!new)
- new = XEXP (note, 0);
+ 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 (set && validate_change (insn, &SET_SRC (set), new, 0))
+ 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 (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;
}
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;
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
{
if (! live_insn)
{
- count_reg_usage (insn, counts, NULL_RTX, -1);
+ count_reg_usage (insn, counts, -1);
delete_insn_and_edges (insn);
ndead++;
}