/* Global constant/copy propagation for RTL.
- Copyright (C) 1997-2015 Free Software Foundation, Inc.
+ Copyright (C) 1997-2019 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
-#include "diagnostic-core.h"
-#include "toplev.h"
+#include "backend.h"
#include "rtl.h"
-#include "hash-set.h"
-#include "vec.h"
-#include "input.h"
-#include "alias.h"
-#include "symtab.h"
-#include "inchash.h"
-#include "tree.h"
-#include "tm_p.h"
-#include "regs.h"
-#include "hard-reg-set.h"
-#include "flags.h"
+#include "cfghooks.h"
+#include "df.h"
#include "insn-config.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
#include "recog.h"
-#include "predict.h"
-#include "hashtab.h"
-#include "function.h"
-#include "dominance.h"
-#include "cfg.h"
+#include "diagnostic-core.h"
+#include "toplev.h"
#include "cfgrtl.h"
#include "cfganal.h"
#include "lcm.h"
#include "cfgcleanup.h"
-#include "basic-block.h"
-#include "statistics.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 "except.h"
#include "params.h"
-#include "alloc-pool.h"
#include "cselib.h"
#include "intl.h"
-#include "obstack.h"
#include "tree-pass.h"
-#include "df.h"
#include "dbgcnt.h"
-#include "target.h"
#include "cfgloop.h"
+#include "gcse.h"
\f
/* An obstack for our working variables. */
rtx_insn *insn;
};
-typedef struct cprop_occr *occr_t;
-
/* Hash table entry for assignment expressions. */
struct cprop_expr
bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
int old_cost = set ? set_rtx_cost (set, speed) : 0;
- if ((note != 0
- && REG_NOTE_KIND (note) == REG_EQUAL
- && (GET_CODE (XEXP (note, 0)) == CONST
- || CONSTANT_P (XEXP (note, 0))))
- || (set && CONSTANT_P (SET_SRC (set))))
+ if (!set
+ || CONSTANT_P (SET_SRC (set))
+ || (note != 0
+ && REG_NOTE_KIND (note) == REG_EQUAL
+ && (GET_CODE (XEXP (note, 0)) == CONST
+ || CONSTANT_P (XEXP (note, 0)))))
check_rtx_costs = false;
/* Usually we substitute easy stuff, so we won't copy everything.
if (check_rtx_costs
&& CONSTANT_P (to)
- && (set_rtx_cost (set, speed) > old_cost))
+ && set_rtx_cost (set, speed) > old_cost)
{
cancel_changes (0);
return false;
(set (reg X) (reg Y))
(set (reg Y) (reg X))
- This can not happen since the set of (reg Y) would have killed the
+ This cannot happen since the set of (reg Y) would have killed the
set of (reg X) making it unavailable at the start of this block. */
while (1)
{
if (dump_file != NULL)
{
fprintf (dump_file,
- "GLOBAL CONST-PROP: Replacing reg %d in jump_insn %d with"
+ "GLOBAL CONST-PROP: Replacing reg %d in jump_insn %d with "
"constant ", REGNO (from), INSN_UID (jump));
print_rtl (dump_file, src);
fprintf (dump_file, "\n");
return;
case SUBREG:
- /* Setting a subreg of a register larger than word_mode leaves
- the non-written words unchanged. */
- if (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) > BITS_PER_WORD)
+ if (read_modify_subreg_p (x))
return;
break;
bool changed = false;
unsigned i;
+ auto_vec<rtx_insn *> uncond_traps;
+
cselib_init (0);
FOR_EACH_BB_FN (bb, cfun)
{
{
if (INSN_P (insn))
{
+ bool was_uncond_trap
+ = (GET_CODE (PATTERN (insn)) == TRAP_IF
+ && XEXP (PATTERN (insn), 0) == const1_rtx);
rtx note = find_reg_equal_equiv_note (insn);
do
{
break;
}
}
+ if (!was_uncond_trap
+ && GET_CODE (PATTERN (insn)) == TRAP_IF
+ && XEXP (PATTERN (insn), 0) == const1_rtx)
+ {
+ uncond_traps.safe_push (insn);
+ break;
+ }
if (insn->deleted ())
break;
}
cselib_finish ();
+ while (!uncond_traps.is_empty ())
+ {
+ rtx_insn *insn = uncond_traps.pop ();
+ basic_block to_split = BLOCK_FOR_INSN (insn);
+ remove_edge (split_block (to_split, insn));
+ emit_barrier_after_bb (to_split);
+ }
+
return changed;
}
the optimization can't be performed. */
/* ??? The complex and vector checks are not implemented yet. We just
always return zero for them. */
- if (CONST_DOUBLE_AS_FLOAT_P (cst))
- {
- REAL_VALUE_TYPE d;
- REAL_VALUE_FROM_CONST_DOUBLE (d, cst);
- if (REAL_VALUES_EQUAL (d, dconst0))
- return 0;
- }
+ if (CONST_DOUBLE_AS_FLOAT_P (cst)
+ && real_equal (CONST_DOUBLE_REAL_VALUE (cst), &dconst0))
+ return 0;
else
return 0;
}
if (ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
return 0;
- bypass_last_basic_block = last_basic_block_for_fn (cfun);
mark_dfs_back_edges ();
changed = 0;
return changed;
}
\f
-/* Return true if the graph is too expensive to optimize. PASS is the
- optimization about to be performed. */
-
-static bool
-is_too_expensive (const char *pass)
-{
- /* Trying to perform global optimizations on flow graphs which have
- a high connectivity will take a long time and is unlikely to be
- particularly useful.
-
- In normal circumstances a cfg should have about twice as many
- edges as blocks. But we do not want to punish small functions
- which have a couple switch statements. Rather than simply
- threshold the number of blocks, uses something with a more
- graceful degradation. */
- if (n_edges_for_fn (cfun) > 20000 + n_basic_blocks_for_fn (cfun) * 4)
- {
- warning (OPT_Wdisabled_optimization,
- "%s: %d basic blocks and %d edges/basic block",
- pass, n_basic_blocks_for_fn (cfun),
- n_edges_for_fn (cfun) / n_basic_blocks_for_fn (cfun));
-
- return true;
- }
-
- /* If allocating memory for the cprop bitmap would take up too much
- storage it's better just to disable the optimization. */
- if ((n_basic_blocks_for_fn (cfun)
- * SBITMAP_SET_SIZE (max_reg_num ())
- * sizeof (SBITMAP_ELT_TYPE)) > MAX_GCSE_MEMORY)
- {
- warning (OPT_Wdisabled_optimization,
- "%s: %d basic blocks and %d registers",
- pass, n_basic_blocks_for_fn (cfun), max_reg_num ());
-
- return true;
- }
-
- return false;
-}
-\f
/* Main function for the CPROP pass. */
static int
/* Return if there's nothing to do, or it is too expensive. */
if (n_basic_blocks_for_fn (cfun) <= NUM_FIXED_BLOCKS + 1
- || is_too_expensive (_ ("const/copy propagation disabled")))
+ || gcse_or_cprop_is_too_expensive (_ ("const/copy propagation disabled")))
return 0;
global_const_prop_count = local_const_prop_count = 0;
if (set_hash_table.n_elems > 0)
{
basic_block bb;
- rtx_insn *insn;
+ auto_vec<rtx_insn *> uncond_traps;
alloc_cprop_mem (last_basic_block_for_fn (cfun),
set_hash_table.n_elems);
EXIT_BLOCK_PTR_FOR_FN (cfun),
next_bb)
{
+ bool seen_uncond_trap = false;
+ rtx_insn *insn;
+
/* Reset tables used to keep track of what's still valid [since
the start of the block]. */
reset_opr_set_tables ();
FOR_BB_INSNS (bb, insn)
if (INSN_P (insn))
{
+ bool was_uncond_trap
+ = (GET_CODE (PATTERN (insn)) == TRAP_IF
+ && XEXP (PATTERN (insn), 0) == const1_rtx);
+
changed |= cprop_insn (insn);
/* Keep track of everything modified by this insn. */
insn into a NOTE, or deleted the insn. */
if (! NOTE_P (insn) && ! insn->deleted ())
mark_oprs_set (insn);
+
+ if (!was_uncond_trap
+ && GET_CODE (PATTERN (insn)) == TRAP_IF
+ && XEXP (PATTERN (insn), 0) == const1_rtx)
+ {
+ /* If we have already seen an unconditional trap
+ earlier, the rest of the bb is going to be removed
+ as unreachable. Just turn it into a note, so that
+ RTL verification doesn't complain about it before
+ it is finally removed. */
+ if (seen_uncond_trap)
+ set_insn_deleted (insn);
+ else
+ {
+ seen_uncond_trap = true;
+ uncond_traps.safe_push (insn);
+ }
+ }
}
}
+ /* Make sure bypass_conditional_jumps will ignore not just its new
+ basic blocks, but also the ones after unconditional traps (those are
+ unreachable and will be eventually removed as such). */
+ bypass_last_basic_block = last_basic_block_for_fn (cfun);
+
+ while (!uncond_traps.is_empty ())
+ {
+ rtx_insn *insn = uncond_traps.pop ();
+ basic_block to_split = BLOCK_FOR_INSN (insn);
+ remove_edge (split_block (to_split, insn));
+ emit_barrier_after_bb (to_split);
+ }
+
changed |= bypass_conditional_jumps ();
FREE_REG_SET (reg_set_bitmap);