/* High-level loop manipulation functions.
- Copyright (C) 2004-2017 Free Software Foundation, Inc.
+ Copyright (C) 2004-2020 Free Software Foundation, Inc.
This file is part of GCC.
#include "tree-ssa.h"
#include "cfgloop.h"
#include "tree-scalar-evolution.h"
-#include "params.h"
#include "tree-inline.h"
/* All bitmaps for rewriting into loop-closed SSA go on this obstack,
VAR_AFTER (unless they are NULL). */
void
-create_iv (tree base, tree step, tree var, struct loop *loop,
+create_iv (tree base, tree step, tree var, class loop *loop,
gimple_stmt_iterator *incr_pos, bool after,
tree *var_before, tree *var_after)
{
gsi_insert_seq_on_edge_immediate (pe, stmts);
stmt = gimple_build_assign (va, incr_op, vb, step);
+ /* Prevent the increment from inheriting a bogus location if it is not put
+ immediately after a statement whose location is known. */
if (after)
- gsi_insert_after (incr_pos, stmt, GSI_NEW_STMT);
+ {
+ if (gsi_end_p (*incr_pos)
+ || (is_gimple_debug (gsi_stmt (*incr_pos))
+ && gsi_bb (*incr_pos)
+ && gsi_end_p (gsi_last_nondebug_bb (gsi_bb (*incr_pos)))))
+ {
+ edge e = single_succ_edge (gsi_bb (*incr_pos));
+ gimple_set_location (stmt, e->goto_locus);
+ }
+ gsi_insert_after (incr_pos, stmt, GSI_NEW_STMT);
+ }
else
- gsi_insert_before (incr_pos, stmt, GSI_NEW_STMT);
+ {
+ gimple_stmt_iterator gsi = *incr_pos;
+ if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi)))
+ gsi_next_nondebug (&gsi);
+ if (!gsi_end_p (gsi))
+ gimple_set_location (stmt, gimple_location (gsi_stmt (gsi)));
+ gsi_insert_before (incr_pos, stmt, GSI_NEW_STMT);
+ }
initial = force_gimple_operand (base, &stmts, true, var);
if (stmts)
/* Return the innermost superloop LOOP of USE_LOOP that is a superloop of
both DEF_LOOP and USE_LOOP. */
-static inline struct loop *
-find_sibling_superloop (struct loop *use_loop, struct loop *def_loop)
+static inline class loop *
+find_sibling_superloop (class loop *use_loop, class loop *def_loop)
{
unsigned ud = loop_depth (use_loop);
unsigned dd = loop_depth (def_loop);
{
unsigned i;
bitmap_iterator bi;
- struct loop *def_loop = def_bb->loop_father;
+ class loop *def_loop = def_bb->loop_father;
unsigned def_loop_depth = loop_depth (def_loop);
bitmap def_loop_exits;
EXECUTE_IF_SET_IN_BITMAP (use_blocks, 0, i, bi)
{
basic_block use_bb = BASIC_BLOCK_FOR_FN (cfun, i);
- struct loop *use_loop = use_bb->loop_father;
+ class loop *use_loop = use_bb->loop_father;
gcc_checking_assert (def_loop != use_loop
&& ! flow_loop_nested_p (def_loop, use_loop));
if (! flow_loop_nested_p (use_loop, def_loop))
FOR_EACH_EDGE (e, ei, bb->preds)
{
basic_block pred = e->src;
- struct loop *pred_loop = pred->loop_father;
+ class loop *pred_loop = pred->loop_father;
unsigned pred_loop_depth = loop_depth (pred_loop);
bool pred_visited;
}
def_loop_exits = BITMAP_ALLOC (&loop_renamer_obstack);
- for (struct loop *loop = def_loop;
+ for (class loop *loop = def_loop;
loop != current_loops->tree_root;
loop = loop_outer (loop))
bitmap_ior_into (def_loop_exits, loop_exits[loop->num]);
basic_block def_bb = gimple_bb (def_stmt);
FOR_EACH_EDGE (e, ei, exit->preds)
{
- struct loop *aloop = find_common_loop (def_bb->loop_father,
+ class loop *aloop = find_common_loop (def_bb->loop_father,
e->src->loop_father);
if (!flow_bb_inside_loop_p (aloop, e->dest))
break;
static void
get_loops_exits (bitmap *loop_exits)
{
- struct loop *loop;
+ class loop *loop;
unsigned j;
edge e;
FOR_EACH_LOOP (loop, 0)
{
- vec<edge> exit_edges = get_loop_exit_edges (loop);
+ auto_vec<edge> exit_edges = get_loop_exit_edges (loop);
loop_exits[loop->num] = BITMAP_ALLOC (&loop_renamer_obstack);
FOR_EACH_VEC_ELT (exit_edges, j, e)
bitmap_set_bit (loop_exits[loop->num], e->dest->index);
- exit_edges.release ();
}
}
{
unsigned ver;
basic_block def_bb;
- struct loop *def_loop;
+ class loop *def_loop;
if (TREE_CODE (use) != SSA_NAME)
return;
USE_BLOCKS. Record the SSA names that will need exit PHIs in NEED_PHIS. */
static void
-find_uses_to_rename_in_loop (struct loop *loop, bitmap *use_blocks,
+find_uses_to_rename_in_loop (class loop *loop, bitmap *use_blocks,
bitmap need_phis, int use_flags)
{
bool do_virtuals = (use_flags & SSA_OP_VIRTUAL_USES) != 0;
void
rewrite_into_loop_closed_ssa_1 (bitmap changed_bbs, unsigned update_flag,
- int use_flags, struct loop *loop)
+ int use_flags, class loop *loop)
{
bitmap *use_blocks;
bitmap names_to_rename;
form. */
void
-rewrite_virtuals_into_loop_closed_ssa (struct loop *loop)
+rewrite_virtuals_into_loop_closed_ssa (class loop *loop)
{
rewrite_into_loop_closed_ssa_1 (NULL, 0, SSA_OP_VIRTUAL_USES, loop);
}
if LOOP is NULL, otherwise, only LOOP is checked. */
DEBUG_FUNCTION void
-verify_loop_closed_ssa (bool verify_ssa_p, struct loop *loop)
+verify_loop_closed_ssa (bool verify_ssa_p, class loop *loop)
{
if (number_of_loops (cfun) <= 1)
return;
}
/* Split loop exit edge EXIT. The things are a bit complicated by a need to
- preserve the loop closed ssa form. The newly created block is returned. */
+ preserve the loop closed ssa form. If COPY_CONSTANTS_P is true then
+ forwarder PHIs are also created for constant arguments.
+ The newly created block is returned. */
basic_block
-split_loop_exit_edge (edge exit)
+split_loop_exit_edge (edge exit, bool copy_constants_p)
{
basic_block dest = exit->dest;
basic_block bb = split_edge (exit);
tree new_name, name;
use_operand_p op_p;
gphi_iterator psi;
- source_location locus;
+ location_t locus;
for (psi = gsi_start_phis (dest); !gsi_end_p (psi); gsi_next (&psi))
{
/* If the argument of the PHI node is a constant, we do not need
to keep it inside loop. */
- if (TREE_CODE (name) != SSA_NAME)
+ if (TREE_CODE (name) != SSA_NAME
+ && !copy_constants_p)
continue;
/* Otherwise create an auxiliary phi node that will copy the value
of the SSA name out of the loop. */
- new_name = duplicate_ssa_name (name, NULL);
+ new_name = duplicate_ssa_name (PHI_RESULT (phi), NULL);
new_phi = create_phi_node (new_name, bb);
add_phi_arg (new_phi, name, exit, locus);
SET_USE (op_p, new_name);
variables incremented at the end of the LOOP. */
basic_block
-ip_end_pos (struct loop *loop)
+ip_end_pos (class loop *loop)
{
return loop->latch;
}
variables incremented just before exit condition of a LOOP. */
basic_block
-ip_normal_pos (struct loop *loop)
+ip_normal_pos (class loop *loop)
{
gimple *last;
basic_block bb;
the increment should be inserted after *BSI. */
void
-standard_iv_increment_position (struct loop *loop, gimple_stmt_iterator *bsi,
+standard_iv_increment_position (class loop *loop, gimple_stmt_iterator *bsi,
bool *insert_after)
{
basic_block bb = ip_normal_pos (loop), latch = ip_end_pos (loop);
after the loop has been duplicated. */
bool
-gimple_duplicate_loop_to_header_edge (struct loop *loop, edge e,
+gimple_duplicate_loop_to_header_edge (class loop *loop, edge e,
unsigned int ndupl, sbitmap wont_exit,
edge orig, vec<edge> *to_remove,
int flags)
of iterations of the loop is returned in NITER. */
bool
-can_unroll_loop_p (struct loop *loop, unsigned factor,
- struct tree_niter_desc *niter)
+can_unroll_loop_p (class loop *loop, unsigned factor,
+ class tree_niter_desc *niter)
{
edge exit;
/* The final loop should be small enough. */
if (tree_num_loop_insns (loop, &eni_size_weights) * factor
- > (unsigned) PARAM_VALUE (PARAM_MAX_UNROLLED_INSNS))
+ > (unsigned) param_max_unrolled_insns)
return false;
return true;
how the exit from the unrolled loop should be controlled. */
static void
-determine_exit_conditions (struct loop *loop, struct tree_niter_desc *desc,
+determine_exit_conditions (class loop *loop, class tree_niter_desc *desc,
unsigned factor, tree *enter_cond,
tree *exit_base, tree *exit_step,
enum tree_code *exit_cmp, tree *exit_bound)
dominated by BB by NUM/DEN. */
static void
-scale_dominated_blocks_in_loop (struct loop *loop, basic_block bb,
+scale_dominated_blocks_in_loop (class loop *loop, basic_block bb,
profile_count num, profile_count den)
{
basic_block son;
/* Return estimated niter for LOOP after unrolling by FACTOR times. */
gcov_type
-niter_for_unrolled_loop (struct loop *loop, unsigned factor)
+niter_for_unrolled_loop (class loop *loop, unsigned factor)
{
gcc_assert (factor != 0);
bool profile_p = false;
#define PROB_UNROLLED_LOOP_ENTERED 90
void
-tree_transform_and_unroll_loop (struct loop *loop, unsigned factor,
- edge exit, struct tree_niter_desc *desc,
+tree_transform_and_unroll_loop (class loop *loop, unsigned factor,
+ edge exit, class tree_niter_desc *desc,
transform_callback transform,
void *data)
{
gphi *phi_old_loop, *phi_new_loop, *phi_rest;
gphi_iterator psi_old_loop, psi_new_loop;
tree init, next, new_init;
- struct loop *new_loop;
+ class loop *new_loop;
basic_block rest, exit_bb;
edge old_entry, new_entry, old_latch, precond_edge, new_exit;
edge new_nonexit, e;
{
/* Avoid dropping loop body profile counter to 0 because of zero count
in loop's preheader. */
- freq_e = freq_e.force_nonzero ();
+ if (freq_h.nonzero_p () && !(freq_e == profile_count::zero ()))
+ freq_e = freq_e.force_nonzero ();
scale_loop_frequencies (loop, freq_e.probability_in (freq_h));
}
of the arguments is the same as for tree_transform_and_unroll_loop. */
void
-tree_unroll_loop (struct loop *loop, unsigned factor,
- edge exit, struct tree_niter_desc *desc)
+tree_unroll_loop (class loop *loop, unsigned factor,
+ edge exit, class tree_niter_desc *desc)
{
tree_transform_and_unroll_loop (loop, factor, exit, desc,
NULL, NULL);
created. */
tree
-canonicalize_loop_ivs (struct loop *loop, tree *nit, bool bump_in_latch)
+canonicalize_loop_ivs (class loop *loop, tree *nit, bool bump_in_latch)
{
unsigned precision = TYPE_PRECISION (TREE_TYPE (*nit));
unsigned original_precision = precision;
precision = GET_MODE_PRECISION (mode);
type = build_nonstandard_integer_type (precision, unsigned_p);
- if (original_precision != precision)
+ if (original_precision != precision
+ || TYPE_UNSIGNED (TREE_TYPE (*nit)) != unsigned_p)
{
*nit = fold_convert (type, *nit);
*nit = force_gimple_operand (*nit, &stmts, true, NULL_TREE);