<http://www.gnu.org/licenses/>. */
#include "config.h"
-/* stdio.h must precede rtl.h for FFS. */
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "regs.h"
#include "basic-block.h"
#include "flags.h"
-#include "real.h"
#include "insn-config.h"
#include "recog.h"
#include "function.h"
#include "expr.h"
+#include "diagnostic-core.h"
#include "toplev.h"
#include "output.h"
#include "ggc.h"
{
if (regno < FIRST_PSEUDO_REGISTER)
{
- if (SMALL_REGISTER_CLASSES)
+ if (targetm.small_register_classes_for_mode_p (GET_MODE (x)))
return 1;
*cost_p += 2;
}
return hash;
}
-/* Same as hash_rtx, but call CB on each rtx if it is not NULL.
+/* Same as hash_rtx, but call CB on each rtx if it is not NULL.
When the callback returns true, we continue with the new rtx. */
unsigned
return hash;
/* Invoke the callback first. */
- if (cb != NULL
+ if (cb != NULL
&& ((*cb) (x, mode, &newx, &newmode)))
{
hash += hash_rtx_cb (newx, newmode, do_not_record_p,
record = true;
else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_CC)
record = true;
- else if (SMALL_REGISTER_CLASSES)
+ else if (targetm.small_register_classes_for_mode_p (GET_MODE (x)))
record = false;
else if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (regno)))
record = false;
{
elt = CONST_VECTOR_ELT (x, i);
hash += hash_rtx_cb (elt, GET_MODE (elt),
- do_not_record_p, hash_arg_in_memory_p,
+ do_not_record_p, hash_arg_in_memory_p,
have_reg_qty, cb);
}
x = XEXP (x, i);
goto repeat;
}
-
+
hash += hash_rtx_cb (XEXP (x, i), VOIDmode, do_not_record_p,
hash_arg_in_memory_p,
have_reg_qty, cb);
if (GET_MODE (x) != GET_MODE (y))
return 0;
+ /* MEMs refering to different address space are not equivalent. */
+ if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y))
+ return 0;
+
switch (code)
{
case PC:
case MEM:
if (for_gcse)
{
+ /* Can't merge two expressions in different alias sets, since we
+ can decide that the expression is transparent in a block when
+ it isn't, due to it being set with the different alias set. */
+ if (MEM_ALIAS_SET (x) != MEM_ALIAS_SET (y))
+ return 0;
+
/* A volatile mem should not be considered equivalent to any
other. */
if (MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
return 0;
-
- /* Can't merge two expressions in different alias sets, since we
- can decide that the expression is transparent in a block when
- it isn't, due to it being set with the different alias set.
-
- Also, can't merge two expressions with different MEM_ATTRS.
- They could e.g. be two different entities allocated into the
- same space on the stack (see e.g. PR25130). In that case, the
- MEM addresses can be the same, even though the two MEMs are
- absolutely not equivalent.
-
- But because really all MEM attributes should be the same for
- equivalent MEMs, we just use the invariant that MEMs that have
- the same attributes share the same mem_attrs data structure. */
- if (MEM_ATTRS (x) != MEM_ATTRS (y))
- return 0;
}
break;
constant through simplifications. */
p = lookup (folded_arg0, SAFE_HASH (folded_arg0, mode_arg0),
mode_arg0);
-
+
if (p != NULL)
{
cheapest_simplification = x;
for (i = 0; i < n_sets; i++)
{
+ bool repeat = false;
rtx src, dest;
rtx src_folded;
struct table_elt *elt = 0, *p;
dest = canon_rtx (SET_DEST (sets[i].rtl));
if (!MEM_P (src) || !MEM_P (dest)
- || !nonoverlapping_memrefs_p (src, dest))
+ || !nonoverlapping_memrefs_p (src, dest, false))
break;
}
+ /* Try to optimize
+ (set (reg:M N) (const_int A))
+ (set (reg:M2 O) (const_int B))
+ (set (zero_extract:M2 (reg:M N) (const_int C) (const_int D))
+ (reg:M2 O)). */
+ if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT
+ && CONST_INT_P (trial)
+ && CONST_INT_P (XEXP (SET_DEST (sets[i].rtl), 1))
+ && CONST_INT_P (XEXP (SET_DEST (sets[i].rtl), 2))
+ && REG_P (XEXP (SET_DEST (sets[i].rtl), 0))
+ && (GET_MODE_BITSIZE (GET_MODE (SET_DEST (sets[i].rtl)))
+ >= INTVAL (XEXP (SET_DEST (sets[i].rtl), 1)))
+ && ((unsigned) INTVAL (XEXP (SET_DEST (sets[i].rtl), 1))
+ + (unsigned) INTVAL (XEXP (SET_DEST (sets[i].rtl), 2))
+ <= HOST_BITS_PER_WIDE_INT))
+ {
+ rtx dest_reg = XEXP (SET_DEST (sets[i].rtl), 0);
+ rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
+ rtx pos = XEXP (SET_DEST (sets[i].rtl), 2);
+ unsigned int dest_hash = HASH (dest_reg, GET_MODE (dest_reg));
+ struct table_elt *dest_elt
+ = lookup (dest_reg, dest_hash, GET_MODE (dest_reg));
+ rtx dest_cst = NULL;
+
+ if (dest_elt)
+ for (p = dest_elt->first_same_value; p; p = p->next_same_value)
+ if (p->is_const && CONST_INT_P (p->exp))
+ {
+ dest_cst = p->exp;
+ break;
+ }
+ if (dest_cst)
+ {
+ HOST_WIDE_INT val = INTVAL (dest_cst);
+ HOST_WIDE_INT mask;
+ unsigned int shift;
+ if (BITS_BIG_ENDIAN)
+ shift = GET_MODE_BITSIZE (GET_MODE (dest_reg))
+ - INTVAL (pos) - INTVAL (width);
+ else
+ shift = INTVAL (pos);
+ if (INTVAL (width) == HOST_BITS_PER_WIDE_INT)
+ mask = ~(HOST_WIDE_INT) 0;
+ else
+ mask = ((HOST_WIDE_INT) 1 << INTVAL (width)) - 1;
+ val &= ~(mask << shift);
+ val |= (INTVAL (trial) & mask) << shift;
+ val = trunc_int_for_mode (val, GET_MODE (dest_reg));
+ validate_unshare_change (insn, &SET_DEST (sets[i].rtl),
+ dest_reg, 1);
+ validate_unshare_change (insn, &SET_SRC (sets[i].rtl),
+ GEN_INT (val), 1);
+ if (apply_change_group ())
+ {
+ rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+ if (note)
+ {
+ remove_note (insn, note);
+ df_notes_rescan (insn);
+ }
+ src_eqv = NULL_RTX;
+ src_eqv_elt = NULL;
+ src_eqv_volatile = 0;
+ src_eqv_in_memory = 0;
+ src_eqv_hash = 0;
+ repeat = true;
+ break;
+ }
+ }
+ }
+
/* We don't normally have an insn matching (set (pc) (pc)), so
check for this separately here. We will delete such an
insn below.
}
}
+ /* If we changed the insn too much, handle this set from scratch. */
+ if (repeat)
+ {
+ i--;
+ continue;
+ }
+
src = SET_SRC (sets[i].rtl);
/* In general, it is good to have a SET with SET_SRC == SET_DEST.
describe the path.
It is filled with a queue of basic blocks, starting with FIRST_BB
and following a trace through the CFG.
-
+
If all paths starting at FIRST_BB have been followed, or no new path
starting at FIRST_BB can be constructed, this function returns FALSE.
Otherwise, DATA->path is filled and the function returns TRUE indicating
basic_block bb;
edge e;
int path_size;
-
+
SET_BIT (cse_visited_basic_blocks, first_bb->index);
/* See if there is a previous path. */
int path_entry;
/* Scan to end of each basic block in the path. */
- for (path_entry = 0; path_entry < path_size; path_entry++)
+ for (path_entry = 0; path_entry < path_size; path_entry++)
{
basic_block bb;
rtx insn;
}
}
+ optimize_this_for_speed_p = optimize_bb_for_speed_p (bb);
FOR_BB_INSNS (bb, insn)
{
- optimize_this_for_speed_p = optimize_bb_for_speed_p (bb);
/* If we have processed 1,000 insns, flush the hash table to
avoid extreme quadratic behavior. We must not include NOTEs
in the count since there may be more of them when generating
/* With non-call exceptions, we are not always able to update
the CFG properly inside cse_insn. So clean up possibly
redundant EH edges here. */
- if (flag_non_call_exceptions && have_eh_succ_edges (bb))
+ if (cfun->can_throw_non_call_exceptions && have_eh_succ_edges (bb))
cse_cfg_altered |= purge_dead_edges (bb);
/* If we changed a conditional jump, we may have terminated
case CALL_INSN:
case INSN:
case JUMP_INSN:
- /* We expect dest to be NULL_RTX here. If the insn may trap, mark
- this fact by setting DEST to pc_rtx. */
- if (flag_non_call_exceptions && may_trap_p (PATTERN (x)))
+ /* We expect dest to be NULL_RTX here. If the insn may trap, mark
+ this fact by setting DEST to pc_rtx. */
+ if (insn_could_throw_p (x))
dest = pc_rtx;
if (code == CALL_INSN)
count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, dest, incr);
insn_live_p (rtx insn, int *counts)
{
int i;
- if (flag_non_call_exceptions && may_trap_p (PATTERN (insn)))
+ if (insn_could_throw_p (insn))
return true;
else if (GET_CODE (PATTERN (insn)) == SET)
return set_live_p (PATTERN (insn), insn, counts);
&& GET_MODE (*loc) != GET_MODE (args->newreg))
{
validate_change (args->insn, loc, args->newreg, 1);
-
+
return -1;
}
return 0;
args.insn = insn;
args.newreg = newreg;
-
+
for_each_rtx (&PATTERN (insn), cse_change_cc_mode, &args);
for_each_rtx (®_NOTES (insn), cse_change_cc_mode, &args);
-
+
/* If the following assertion was triggered, there is most probably
something wrong with the cc_modes_compatible back end function.
CC modes only can be considered compatible if the insn - with the mode
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
{
RTL_PASS,
"cse1", /* name */
- gate_handle_cse, /* gate */
- rest_of_handle_cse, /* execute */
+ gate_handle_cse, /* gate */
+ rest_of_handle_cse, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
{
RTL_PASS,
"cse2", /* name */
- gate_handle_cse2, /* gate */
- rest_of_handle_cse2, /* execute */
+ gate_handle_cse2, /* gate */
+ rest_of_handle_cse2, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
{
RTL_PASS,
"cse_local", /* name */
- gate_handle_cse_after_global_opts, /* gate */
- rest_of_handle_cse_after_global_opts, /* execute */
+ gate_handle_cse_after_global_opts, /* gate */
+ rest_of_handle_cse_after_global_opts, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */