/* Common subexpression elimination for GNU compiler.
- Copyright (C) 1987-2014 Free Software Foundation, Inc.
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "tm_p.h"
#include "hard-reg-set.h"
#include "regs.h"
+#include "predict.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
+#include "cfgcleanup.h"
#include "basic-block.h"
#include "flags.h"
#include "insn-config.h"
#include "recog.h"
-#include "function.h"
+#include "symtab.h"
+#include "alias.h"
+#include "tree.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
#include "expr.h"
#include "diagnostic-core.h"
#include "toplev.h"
-#include "ggc.h"
#include "except.h"
#include "target.h"
#include "params.h"
#include "tree-pass.h"
#include "df.h"
#include "dbgcnt.h"
-#include "hash-set.h"
#include "rtl-iter.h"
/* The basic idea of common subexpression elimination is to go
/* The table of all qtys, indexed by qty number. */
static struct qty_table_elem *qty_table;
-#ifdef HAVE_cc0
/* For machines that have a CC0, we do not record its value in the hash
table since its use is guaranteed to be the insn immediately following
its definition and any other insn is presumed to invalidate it.
the mode in which the constant should be interpreted. */
static rtx this_insn_cc0, prev_insn_cc0;
-static enum machine_mode this_insn_cc0_mode, prev_insn_cc0_mode;
-#endif
+static machine_mode this_insn_cc0_mode, prev_insn_cc0_mode;
/* Insn being scanned. */
static int notreg_cost (rtx, enum rtx_code, int);
static int preferable (int, int, int, int);
static void new_basic_block (void);
-static void make_new_qty (unsigned int, enum machine_mode);
+static void make_new_qty (unsigned int, 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 void remove_pseudo_from_table (rtx, unsigned);
-static struct table_elt *lookup (rtx, unsigned, enum machine_mode);
-static struct table_elt *lookup_for_remove (rtx, unsigned, enum machine_mode);
+static struct table_elt *lookup (rtx, unsigned, machine_mode);
+static struct table_elt *lookup_for_remove (rtx, unsigned, machine_mode);
static rtx lookup_as_function (rtx, enum rtx_code);
static struct table_elt *insert_with_costs (rtx, struct table_elt *, unsigned,
- enum machine_mode, int, int);
+ machine_mode, int, int);
static struct table_elt *insert (rtx, struct table_elt *, unsigned,
- enum machine_mode);
+ machine_mode);
static void merge_equiv_classes (struct table_elt *, struct table_elt *);
-static void invalidate (rtx, enum machine_mode);
+static void invalidate (rtx, machine_mode);
static void remove_invalid_refs (unsigned int);
static void remove_invalid_subreg_refs (unsigned int, unsigned int,
- enum machine_mode);
+ 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 inline unsigned canon_hash (rtx, enum machine_mode);
-static inline unsigned safe_hash (rtx, enum machine_mode);
+static inline unsigned canon_hash (rtx, machine_mode);
+static inline unsigned safe_hash (rtx, machine_mode);
static inline unsigned hash_rtx_string (const char *);
static rtx canon_reg (rtx, rtx_insn *);
static enum rtx_code find_comparison_args (enum rtx_code, rtx *, rtx *,
- enum machine_mode *,
- enum machine_mode *);
+ machine_mode *,
+ machine_mode *);
static rtx fold_rtx (rtx, rtx_insn *);
static rtx equiv_constant (rtx);
static void record_jump_equiv (rtx_insn *, bool);
-static void record_jump_cond (enum rtx_code, enum machine_mode, rtx, rtx,
+static void record_jump_cond (enum rtx_code, machine_mode, rtx, rtx,
int);
static void cse_insn (rtx_insn *);
static void cse_prescan_path (struct cse_basic_block_data *);
static bool set_live_p (rtx, rtx_insn *, int *);
static void cse_change_cc_mode_insn (rtx_insn *, rtx);
static void cse_change_cc_mode_insns (rtx_insn *, rtx_insn *, rtx);
-static enum machine_mode cse_cc_succs (basic_block, basic_block, rtx, rtx,
+static machine_mode cse_cc_succs (basic_block, basic_block, rtx, rtx,
bool);
\f
}
}
-#ifdef HAVE_cc0
prev_insn_cc0 = 0;
-#endif
}
/* Say that register REG contains a quantity in mode MODE not in any
register before and initialize that quantity. */
static void
-make_new_qty (unsigned int reg, enum machine_mode mode)
+make_new_qty (unsigned int reg, machine_mode mode)
{
int q;
struct qty_table_elem *ent;
static void
insert_const_anchor (HOST_WIDE_INT anchor, rtx reg, HOST_WIDE_INT offs,
- enum machine_mode mode)
+ machine_mode mode)
{
struct table_elt *elt;
unsigned hash;
register-offset expressions using REG. */
static void
-insert_const_anchors (rtx reg, rtx cst, enum machine_mode mode)
+insert_const_anchors (rtx reg, rtx cst, machine_mode mode)
{
HOST_WIDE_INT lower_base, lower_offs, upper_base, upper_offs;
otherwise. */
static rtx
-try_const_anchors (rtx src_const, enum machine_mode mode)
+try_const_anchors (rtx src_const, machine_mode mode)
{
struct table_elt *lower_elt, *upper_elt;
HOST_WIDE_INT lower_base, lower_offs, upper_base, upper_offs;
looks like X. */
static struct table_elt *
-lookup (rtx x, unsigned int hash, enum machine_mode mode)
+lookup (rtx x, unsigned int hash, machine_mode mode)
{
struct table_elt *p;
Also ignore discrepancies in the machine mode of a register. */
static struct table_elt *
-lookup_for_remove (rtx x, unsigned int hash, enum machine_mode mode)
+lookup_for_remove (rtx x, unsigned int hash, machine_mode mode)
{
struct table_elt *p;
static struct table_elt *
insert_with_costs (rtx x, struct table_elt *classp, unsigned int hash,
- enum machine_mode mode, int cost, int reg_cost)
+ machine_mode mode, int cost, int reg_cost)
{
struct table_elt *elt;
static struct table_elt *
insert (rtx x, struct table_elt *classp, unsigned int hash,
- enum machine_mode mode)
+ machine_mode mode)
{
return
insert_with_costs (x, classp, hash, mode, COST (x), approx_reg_cost (x));
{
unsigned int hash;
rtx exp = elt->exp;
- enum machine_mode mode = elt->mode;
+ machine_mode mode = elt->mode;
next = elt->next_same_value;
}
new_elt = insert (exp, class1, hash, mode);
new_elt->in_memory = hash_arg_in_memory;
+ if (GET_CODE (exp) == ASM_OPERANDS && elt->cost == MAX_COST)
+ new_elt->cost = MAX_COST;
}
}
}
ADDR are as for canon_anti_dependence. */
static bool
-check_dependence (const_rtx x, rtx exp, enum machine_mode mode, rtx addr)
+check_dependence (const_rtx x, rtx exp, machine_mode mode, rtx addr)
{
subrtx_iterator::array_type array;
FOR_EACH_SUBRTX (iter, array, x, NONCONST)
or it may be either of those plus a numeric offset. */
static void
-invalidate (rtx x, enum machine_mode full_mode)
+invalidate (rtx x, machine_mode full_mode)
{
int i;
struct table_elt *p;
{
HOST_WIDE_INT in_table
= TEST_HARD_REG_BIT (hard_regs_in_table, regno);
- unsigned int endregno = END_HARD_REGNO (x);
+ unsigned int endregno = END_REGNO (x);
unsigned int tregno, tendregno, rn;
struct table_elt *p, *next;
continue;
tregno = REGNO (p->exp);
- tendregno = END_HARD_REGNO (p->exp);
+ tendregno = END_REGNO (p->exp);
if (tendregno > regno && tregno < endregno)
remove_from_table (p, hash);
}
gcc_unreachable ();
}
}
+
+/* Invalidate DEST. Used when DEST is not going to be added
+ into the hash table for some reason, e.g. do_not_record
+ flagged on it. */
+
+static void
+invalidate_dest (rtx dest)
+{
+ if (REG_P (dest)
+ || GET_CODE (dest) == SUBREG
+ || MEM_P (dest))
+ invalidate (dest, VOIDmode);
+ else if (GET_CODE (dest) == STRICT_LOW_PART
+ || GET_CODE (dest) == ZERO_EXTRACT)
+ invalidate (XEXP (dest, 0), GET_MODE (dest));
+}
\f
/* Remove all expressions that refer to register REGNO,
since they are already invalid, and we are about to
for (p = table[i]; p; p = next)
{
next = p->next_same_hash;
- if (!REG_P (p->exp)
- && refers_to_regno_p (regno, regno + 1, p->exp, (rtx *) 0))
+ if (!REG_P (p->exp) && refers_to_regno_p (regno, p->exp))
remove_from_table (p, i);
}
}
and mode MODE. */
static void
remove_invalid_subreg_refs (unsigned int regno, unsigned int offset,
- enum machine_mode mode)
+ machine_mode mode)
{
unsigned int i;
struct table_elt *p, *next;
|| (((SUBREG_BYTE (exp)
+ (GET_MODE_SIZE (GET_MODE (exp)) - 1)) >= offset)
&& SUBREG_BYTE (exp) <= end))
- && refers_to_regno_p (regno, regno + 1, p->exp, (rtx *) 0))
+ && refers_to_regno_p (regno, p->exp))
remove_from_table (p, i);
}
}
continue;
regno = REGNO (p->exp);
- endregno = END_HARD_REGNO (p->exp);
+ endregno = END_REGNO (p->exp);
for (i = regno; i < endregno; i++)
if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
When the callback returns true, we continue with the new rtx. */
unsigned
-hash_rtx_cb (const_rtx x, enum machine_mode mode,
+hash_rtx_cb (const_rtx x, machine_mode mode,
int *do_not_record_p, int *hash_arg_in_memory_p,
bool have_reg_qty, hash_rtx_callback_function cb)
{
unsigned hash = 0;
enum rtx_code code;
const char *fmt;
- enum machine_mode newmode;
+ machine_mode newmode;
rtx newx;
/* Used to turn recursion into iteration. We can't rely on GCC's
/* We don't hash on the address of the CODE_LABEL to avoid bootstrap
differences and differences between each stage's debugging dumps. */
hash += (((unsigned int) LABEL_REF << 7)
- + CODE_LABEL_NUMBER (XEXP (x, 0)));
+ + CODE_LABEL_NUMBER (LABEL_REF_LABEL (x)));
return hash;
case SYMBOL_REF:
is just (int) MEM plus the hash code of the address. */
unsigned
-hash_rtx (const_rtx x, enum machine_mode mode, int *do_not_record_p,
+hash_rtx (const_rtx x, machine_mode mode, int *do_not_record_p,
int *hash_arg_in_memory_p, bool have_reg_qty)
{
return hash_rtx_cb (x, mode, do_not_record_p,
does not have the MEM_READONLY_P flag set. */
static inline unsigned
-canon_hash (rtx x, enum machine_mode mode)
+canon_hash (rtx x, machine_mode mode)
{
return hash_rtx (x, mode, &do_not_record, &hash_arg_in_memory, true);
}
and hash_arg_in_memory are not changed. */
static inline unsigned
-safe_hash (rtx x, enum machine_mode mode)
+safe_hash (rtx x, machine_mode mode)
{
int dummy_do_not_record;
return hash_rtx (x, mode, &dummy_do_not_record, NULL, true);
return x == y;
case LABEL_REF:
- return XEXP (x, 0) == XEXP (y, 0);
+ return LABEL_REF_LABEL (x) == LABEL_REF_LABEL (y);
case SYMBOL_REF:
return XSTR (x, 0) == XSTR (y, 0);
static enum rtx_code
find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
- enum machine_mode *pmode1, enum machine_mode *pmode2)
+ machine_mode *pmode1, machine_mode *pmode2)
{
rtx arg1, arg2;
hash_set<rtx> *visited = NULL;
for (; p; p = p->next_same_value)
{
- enum machine_mode inner_mode = GET_MODE (p->exp);
+ machine_mode inner_mode = GET_MODE (p->exp);
#ifdef FLOAT_STORE_FLAG_VALUE
REAL_VALUE_TYPE fsfv;
#endif
fold_rtx (rtx x, rtx_insn *insn)
{
enum rtx_code code;
- enum machine_mode mode;
+ machine_mode mode;
const char *fmt;
int i;
rtx new_rtx = 0;
int changed = 0;
/* Operands of X. */
- rtx folded_arg0;
- rtx folded_arg1;
+ /* Workaround -Wmaybe-uninitialized false positive during
+ profiledbootstrap by initializing them. */
+ rtx folded_arg0 = NULL_RTX;
+ rtx folded_arg1 = NULL_RTX;
/* Constant equivalents of first three operands of X;
0 when no such equivalent is known. */
/* The mode of the first operand of X. We need this for sign and zero
extends. */
- enum machine_mode mode_arg0;
+ machine_mode mode_arg0;
if (x == 0)
return x;
{
case MEM:
case SUBREG:
+ /* The first operand of a SIGN/ZERO_EXTRACT has a different meaning
+ than it would in other contexts. Basically its mode does not
+ signify the size of the object read. That information is carried
+ by size operand. If we happen to have a MEM of the appropriate
+ mode in our tables with a constant value we could simplify the
+ extraction incorrectly if we allowed substitution of that value
+ for the MEM. */
+ case ZERO_EXTRACT:
+ case SIGN_EXTRACT:
if ((new_rtx = equiv_constant (x)) != NULL_RTX)
return new_rtx;
return x;
case EXPR_LIST:
return x;
-#ifdef HAVE_cc0
case CC0:
return prev_insn_cc0;
-#endif
case ASM_OPERANDS:
if (insn)
}
return x;
-#ifdef NO_FUNCTION_CSE
case CALL:
- if (CONSTANT_P (XEXP (XEXP (x, 0), 0)))
+ if (NO_FUNCTION_CSE && CONSTANT_P (XEXP (XEXP (x, 0), 0)))
return x;
break;
-#endif
/* Anything else goes through the loop below. */
default:
if (fmt[i] == 'e')
{
rtx folded_arg = XEXP (x, i), const_arg;
- enum machine_mode mode_arg = GET_MODE (folded_arg);
+ machine_mode mode_arg = GET_MODE (folded_arg);
switch (GET_CODE (folded_arg))
{
const_arg = folded_arg;
break;
-#ifdef HAVE_cc0
case CC0:
/* The cc0-user and cc0-setter may be in different blocks if
the cc0-setter potentially traps. In that case PREV_INSN_CC0
const_arg = equiv_constant (folded_arg);
}
break;
-#endif
default:
folded_arg = fold_rtx (folded_arg, insn);
{
struct table_elt *p0, *p1;
rtx true_rtx, false_rtx;
- enum machine_mode mode_arg1;
+ machine_mode mode_arg1;
if (SCALAR_FLOAT_MODE_P (mode))
{
: lookup_as_function (folded_arg0, MINUS);
if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
- && XEXP (XEXP (y, 1), 0) == XEXP (const_arg1, 0))
+ && LABEL_REF_LABEL (XEXP (y, 1)) == LABEL_REF_LABEL (const_arg1))
return XEXP (y, 0);
/* Now try for a CONST of a MINUS like the above. */
: lookup_as_function (folded_arg0, CONST))) != 0
&& GET_CODE (XEXP (y, 0)) == MINUS
&& GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
- && XEXP (XEXP (XEXP (y, 0), 1), 0) == XEXP (const_arg1, 0))
+ && LABEL_REF_LABEL (XEXP (XEXP (y, 0), 1)) == LABEL_REF_LABEL (const_arg1))
return XEXP (XEXP (y, 0), 0);
}
: lookup_as_function (folded_arg1, MINUS);
if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
- && XEXP (XEXP (y, 1), 0) == XEXP (const_arg0, 0))
+ && LABEL_REF_LABEL (XEXP (y, 1)) == LABEL_REF_LABEL (const_arg0))
return XEXP (y, 0);
/* Now try for a CONST of a MINUS like the above. */
: lookup_as_function (folded_arg1, CONST))) != 0
&& GET_CODE (XEXP (y, 0)) == MINUS
&& GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
- && XEXP (XEXP (XEXP (y, 0), 1), 0) == XEXP (const_arg0, 0))
+ && LABEL_REF_LABEL (XEXP (XEXP (y, 0), 1)) == LABEL_REF_LABEL (const_arg0))
return XEXP (XEXP (y, 0), 0);
}
if (GET_CODE (x) == SUBREG)
{
- enum machine_mode mode = GET_MODE (x);
- enum machine_mode imode = GET_MODE (SUBREG_REG (x));
+ machine_mode mode = GET_MODE (x);
+ machine_mode imode = GET_MODE (SUBREG_REG (x));
rtx new_rtx;
/* See if we previously assigned a constant value to this SUBREG. */
int cond_known_true;
rtx op0, op1;
rtx set;
- enum machine_mode mode, mode0, mode1;
+ machine_mode mode, mode0, mode1;
int reversed_nonequality = 0;
enum rtx_code code;
MODE, and we should assume OP has MODE iff it is naturally modeless. */
static rtx
-record_jump_cond_subreg (enum machine_mode mode, rtx op)
+record_jump_cond_subreg (machine_mode mode, rtx op)
{
- enum machine_mode op_mode = GET_MODE (op);
+ machine_mode op_mode = GET_MODE (op);
if (op_mode == mode || op_mode == VOIDmode)
return op;
return lowpart_subreg (mode, op, op_mode);
above function and called recursively. */
static void
-record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
+record_jump_cond (enum rtx_code code, machine_mode mode, rtx op0,
rtx op1, int reversed_nonequality)
{
unsigned op0_hash, op1_hash;
/* Note that GET_MODE (op0) may not equal MODE. */
if (code == EQ && paradoxical_subreg_p (op0))
{
- enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
+ machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
rtx tem = record_jump_cond_subreg (inner_mode, op1);
if (tem)
record_jump_cond (code, mode, SUBREG_REG (op0), tem,
if (code == EQ && paradoxical_subreg_p (op1))
{
- enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
+ machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
rtx tem = record_jump_cond_subreg (inner_mode, op0);
if (tem)
record_jump_cond (code, mode, SUBREG_REG (op1), tem,
&& (GET_MODE_SIZE (GET_MODE (op0))
< GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
{
- enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
+ machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
rtx tem = record_jump_cond_subreg (inner_mode, op1);
if (tem)
record_jump_cond (code, mode, SUBREG_REG (op0), tem,
&& (GET_MODE_SIZE (GET_MODE (op1))
< GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
{
- enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
+ machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
rtx tem = record_jump_cond_subreg (inner_mode, op0);
if (tem)
record_jump_cond (code, mode, SUBREG_REG (op1), tem,
{
int i, lim = XVECLEN (x, 0);
- /* Go over the epressions of the PARALLEL in forward order, to
+ /* Go over the expressions of the PARALLEL in forward order, to
put them in the same order in the SETS array. */
for (i = 0; i < lim; i++)
{
sets = XALLOCAVEC (struct set, XVECLEN (x, 0));
this_insn = insn;
-#ifdef HAVE_cc0
/* Records what this insn does to set CC0. */
this_insn_cc0 = 0;
this_insn_cc0_mode = VOIDmode;
-#endif
/* Find all regs explicitly clobbered in this insn,
to ensure they are not replaced with any other regs
rtx src, dest;
rtx src_folded;
struct table_elt *elt = 0, *p;
- enum machine_mode mode;
+ machine_mode mode;
rtx src_eqv_here;
rtx src_const = 0;
rtx src_related = 0;
if (src_eqv)
{
- enum machine_mode eqvmode = mode;
+ machine_mode eqvmode = mode;
if (GET_CODE (dest) == STRICT_LOW_PART)
eqvmode = GET_MODE (SUBREG_REG (XEXP (dest, 0)));
do_not_record = 0;
&& REGNO (dest) >= FIRST_PSEUDO_REGISTER)
sets[i].src_volatile = 1;
- /* Also do not record result of a non-volatile inline asm with
- more than one result or with clobbers, we do not want CSE to
- break the inline asm apart. */
else if (GET_CODE (src) == ASM_OPERANDS
&& GET_CODE (x) == PARALLEL)
- sets[i].src_volatile = 1;
+ {
+ /* Do not record result of a non-volatile inline asm with
+ more than one result. */
+ if (n_sets > 1)
+ sets[i].src_volatile = 1;
+
+ int j, lim = XVECLEN (x, 0);
+ for (j = 0; j < lim; j++)
+ {
+ rtx y = XVECEXP (x, 0, j);
+ /* And do not record result of a non-volatile inline asm
+ with "memory" clobber. */
+ if (GET_CODE (y) == CLOBBER && MEM_P (XEXP (y, 0)))
+ {
+ sets[i].src_volatile = 1;
+ break;
+ }
+ }
+ }
#if 0
/* It is no longer clear why we used to do this, but it doesn't
&& GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_PRECISION (mode) < BITS_PER_WORD)
{
- enum machine_mode wider_mode;
+ machine_mode wider_mode;
for (wider_mode = GET_MODE_WIDER_MODE (mode);
wider_mode != VOIDmode
&& GET_CODE (src) == AND && CONST_INT_P (XEXP (src, 1))
&& GET_MODE_SIZE (mode) < UNITS_PER_WORD)
{
- enum machine_mode tmode;
+ machine_mode tmode;
rtx new_and = gen_rtx_AND (VOIDmode, NULL_RTX, XEXP (src, 1));
for (tmode = GET_MODE_WIDER_MODE (mode);
{
struct rtx_def memory_extend_buf;
rtx memory_extend_rtx = &memory_extend_buf;
- enum machine_mode tmode;
+ machine_mode tmode;
/* Set what we are trying to extend and the operation it might
have been extended with. */
;
/* Look for a substitution that makes a valid insn. */
- else if (validate_unshare_change
- (insn, &SET_SRC (sets[i].rtl), trial, 0))
+ else if (validate_unshare_change (insn, &SET_SRC (sets[i].rtl),
+ trial, 0))
{
rtx new_rtx = canon_reg (SET_SRC (sets[i].rtl), insn);
and hope for the best. */
if (n_sets == 1)
{
- rtx new_rtx, note;
+ rtx_jump_insn *new_rtx;
+ rtx note;
new_rtx = emit_jump_insn_before (gen_jump (XEXP (src, 0)), insn);
JUMP_LABEL (new_rtx) = XEXP (src, 0);
}
delete_insn_and_edges (insn);
- insn = as_a <rtx_insn *> (new_rtx);
+ insn = new_rtx;
}
else
INSN_CODE (insn) = -1;
else if (do_not_record)
{
- if (REG_P (dest) || GET_CODE (dest) == SUBREG)
- invalidate (dest, VOIDmode);
- else if (MEM_P (dest))
- invalidate (dest, VOIDmode);
- else if (GET_CODE (dest) == STRICT_LOW_PART
- || GET_CODE (dest) == ZERO_EXTRACT)
- invalidate (XEXP (dest, 0), GET_MODE (dest));
+ invalidate_dest (dest);
sets[i].rtl = 0;
}
if (sets[i].rtl != 0 && dest != SET_DEST (sets[i].rtl))
- sets[i].dest_hash = HASH (SET_DEST (sets[i].rtl), mode);
+ {
+ do_not_record = 0;
+ sets[i].dest_hash = HASH (SET_DEST (sets[i].rtl), mode);
+ if (do_not_record)
+ {
+ invalidate_dest (SET_DEST (sets[i].rtl));
+ sets[i].rtl = 0;
+ }
+ }
-#ifdef HAVE_cc0
/* If setting CC0, record what it was set to, or a constant, if it
is equivalent to a constant. If it is being set to a floating-point
value, make a COMPARE with the appropriate constant of 0. If we
this_insn_cc0 = gen_rtx_COMPARE (VOIDmode, this_insn_cc0,
CONST0_RTX (mode));
}
-#endif
}
/* Now enter all non-volatile source expressions in the hash table
struct table_elt *elt;
struct table_elt *classp = sets[0].src_elt;
rtx dest = SET_DEST (sets[0].rtl);
- enum machine_mode eqvmode = GET_MODE (dest);
+ machine_mode eqvmode = GET_MODE (dest);
if (GET_CODE (dest) == STRICT_LOW_PART)
{
struct table_elt *classp = src_eqv_elt;
rtx src = sets[i].src;
rtx dest = SET_DEST (sets[i].rtl);
- enum machine_mode mode
+ 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
}
elt = insert (src, classp, sets[i].src_hash, mode);
elt->in_memory = sets[i].src_in_memory;
+ /* If inline asm has any clobbers, ensure we only reuse
+ existing inline asms and never try to put the ASM_OPERANDS
+ into an insn that isn't inline asm. */
+ if (GET_CODE (src) == ASM_OPERANDS
+ && GET_CODE (x) == PARALLEL)
+ elt->cost = MAX_COST;
sets[i].src_elt = classp = elt;
}
if (sets[i].src_const && sets[i].src_const_elt == 0
{
rtx x = sets[i].inner_dest;
struct table_elt *elt;
- enum machine_mode mode;
+ machine_mode mode;
unsigned hash;
if (MEM_P (x))
>= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))
&& sets[i].src_elt != 0)
{
- enum machine_mode new_mode = GET_MODE (SUBREG_REG (dest));
+ machine_mode new_mode = GET_MODE (SUBREG_REG (dest));
struct table_elt *elt, *classp = 0;
for (elt = sets[i].src_elt->first_same_value; elt;
}
src_elt = insert (new_src, classp, src_hash, new_mode);
src_elt->in_memory = elt->in_memory;
+ if (GET_CODE (new_src) == ASM_OPERANDS
+ && elt->cost == MAX_COST)
+ src_elt->cost = MAX_COST;
}
else if (classp && classp != src_elt->first_same_value)
/* Show that two things that we've seen before are
if (GET_CODE (x) == LABEL_REF
&& !LABEL_REF_NONLOCAL_P (x)
&& (!JUMP_P (insn)
- || !label_is_jump_target_p (XEXP (x, 0), insn))
- && LABEL_P (XEXP (x, 0))
- && INSN_UID (XEXP (x, 0)) != 0
- && !find_reg_note (insn, REG_LABEL_OPERAND, XEXP (x, 0)))
+ || !label_is_jump_target_p (LABEL_REF_LABEL (x), insn))
+ && LABEL_P (LABEL_REF_LABEL (x))
+ && INSN_UID (LABEL_REF_LABEL (x)) != 0
+ && !find_reg_note (insn, REG_LABEL_OPERAND, LABEL_REF_LABEL (x)))
return true;
}
return false;
&& check_for_label_ref (insn))
recorded_label_ref = true;
-#ifdef HAVE_cc0
- if (NONDEBUG_INSN_P (insn))
+ if (HAVE_cc0 && NONDEBUG_INSN_P (insn))
{
/* If the previous insn sets CC0 and this insn no
longer references CC0, delete the previous insn.
prev_insn_cc0_mode = this_insn_cc0_mode;
}
}
-#endif
}
}
record_jump_equiv (insn, taken);
}
-#ifdef HAVE_cc0
/* Clear the CC0-tracking related insns, they can't provide
useful information across basic block boundaries. */
prev_insn_cc0 = 0;
-#endif
}
gcc_assert (next_qty <= max_qty);
set_live_p (rtx set, rtx_insn *insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0. */
int *counts)
{
-#ifdef HAVE_cc0
- rtx tem;
-#endif
+ rtx_insn *tem;
if (set_noop_p (set))
;
-#ifdef HAVE_cc0
else if (GET_CODE (SET_DEST (set)) == CC0
&& !side_effects_p (SET_SRC (set))
&& ((tem = next_nonnote_nondebug_insn (insn)) == NULL_RTX
|| !INSN_P (tem)
|| !reg_referenced_p (cc0_rtx, PATTERN (tem))))
return false;
-#endif
else if (!is_dead_reg (SET_DEST (set), counts)
|| side_effects_p (SET_SRC (set)))
return true;
/* If no debug insns can be present, COUNTS is just an array
which counts how many times each pseudo is used. */
}
+ /* Pseudo PIC register should be considered as used due to possible
+ new usages generated. */
+ if (!reload_completed
+ && pic_offset_table_rtx
+ && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER)
+ counts[REGNO (pic_offset_table_rtx)]++;
/* Go from the last insn to the first and delete insns that only set unused
registers or copy a register to itself. As we delete an insn, remove
usage counts for registers it uses.
static void
cse_change_cc_mode (subrtx_ptr_iterator::array_type &array,
- rtx *loc, rtx insn, rtx newreg)
+ rtx *loc, rtx_insn *insn, rtx newreg)
{
FOR_EACH_SUBRTX_PTR (iter, array, loc, NONCONST)
{
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
+static machine_mode
cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
bool can_change_mode)
{
bool found_equiv;
- enum machine_mode mode;
+ machine_mode mode;
unsigned int insn_count;
edge e;
rtx_insn *insns[2];
- enum machine_mode modes[2];
+ machine_mode modes[2];
rtx_insn *last_insns[2];
unsigned int i;
rtx newreg;
&& REGNO (SET_DEST (set)) == REGNO (cc_reg))
{
bool found;
- enum machine_mode set_mode;
- enum machine_mode comp_mode;
+ machine_mode set_mode;
+ machine_mode comp_mode;
found = false;
set_mode = GET_MODE (SET_SRC (set));
further blocks and this block. */
if (insn == end)
{
- enum machine_mode submode;
+ machine_mode submode;
submode = cse_cc_succs (e->dest, orig_bb, cc_reg, cc_src, false);
if (submode != VOIDmode)
rtx_insn *insn;
rtx_insn *cc_src_insn;
rtx cc_src;
- enum machine_mode mode;
- enum machine_mode orig_mode;
+ machine_mode mode;
+ 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