/* Rtl-level induction variable analysis.
- Copyright (C) 2004-2019 Free Software Foundation, Inc.
+ Copyright (C) 2004-2020 Free Software Foundation, Inc.
This file is part of GCC.
#include "dumpfile.h"
#include "rtl-iter.h"
#include "tree-ssa-loop-niter.h"
+#include "regs.h"
+#include "function-abi.h"
/* Possible return values of iv_get_reaching_def. */
/* Information about a biv. */
-struct biv_entry
+class biv_entry
{
+public:
unsigned regno; /* The register of the biv. */
- struct rtx_iv iv; /* Value of the biv. */
+ class rtx_iv iv; /* Value of the biv. */
};
static bool clean_slate = true;
static unsigned int iv_ref_table_size = 0;
/* Table of rtx_ivs indexed by the df_ref uid field. */
-static struct rtx_iv ** iv_ref_table;
+static class rtx_iv ** iv_ref_table;
/* Induction variable stored at the reference. */
#define DF_REF_IV(REF) iv_ref_table[DF_REF_ID (REF)]
/* The current loop. */
-static struct loop *current_loop;
+static class loop *current_loop;
/* Hashtable helper. */
static hash_table<biv_entry_hasher> *bivs;
-static bool iv_analyze_op (rtx_insn *, scalar_int_mode, rtx, struct rtx_iv *);
+static bool iv_analyze_op (rtx_insn *, scalar_int_mode, rtx, class rtx_iv *);
/* Return the RTX code corresponding to the IV extend code EXTEND. */
static inline enum rtx_code
/* Dumps information about IV to FILE. */
-extern void dump_iv_info (FILE *, struct rtx_iv *);
+extern void dump_iv_info (FILE *, class rtx_iv *);
void
-dump_iv_info (FILE *file, struct rtx_iv *iv)
+dump_iv_info (FILE *file, class rtx_iv *iv)
{
if (!iv->base)
{
if (iv_ref_table_size < DF_DEFS_TABLE_SIZE ())
{
unsigned int new_size = DF_DEFS_TABLE_SIZE () + (DF_DEFS_TABLE_SIZE () / 4);
- iv_ref_table = XRESIZEVEC (struct rtx_iv *, iv_ref_table, new_size);
+ iv_ref_table = XRESIZEVEC (class rtx_iv *, iv_ref_table, new_size);
memset (&iv_ref_table[iv_ref_table_size], 0,
- (new_size - iv_ref_table_size) * sizeof (struct rtx_iv *));
+ (new_size - iv_ref_table_size) * sizeof (class rtx_iv *));
iv_ref_table_size = new_size;
}
}
clear_iv_info (void)
{
unsigned i, n_defs = DF_DEFS_TABLE_SIZE ();
- struct rtx_iv *iv;
+ class rtx_iv *iv;
check_iv_ref_table_size ();
for (i = 0; i < n_defs; i++)
/* Prepare the data for an induction variable analysis of a LOOP. */
void
-iv_analysis_loop_init (struct loop *loop)
+iv_analysis_loop_init (class loop *loop)
{
current_loop = loop;
{
df_ref single_rd = NULL, adef;
unsigned regno = REGNO (reg);
- struct df_rd_bb_info *bb_info = DF_RD_BB_INFO (current_loop->latch);
+ class df_rd_bb_info *bb_info = DF_RD_BB_INFO (current_loop->latch);
for (adef = DF_REG_DEF_CHAIN (regno); adef; adef = DF_REF_NEXT_REG (adef))
{
consistency with other iv manipulation functions that may fail). */
static bool
-iv_constant (struct rtx_iv *iv, scalar_int_mode mode, rtx cst)
+iv_constant (class rtx_iv *iv, scalar_int_mode mode, rtx cst)
{
iv->mode = mode;
iv->base = cst;
/* Evaluates application of subreg to MODE on IV. */
static bool
-iv_subreg (struct rtx_iv *iv, scalar_int_mode mode)
+iv_subreg (class rtx_iv *iv, scalar_int_mode mode)
{
/* If iv is invariant, just calculate the new value. */
if (iv->step == const0_rtx
/* Evaluates application of EXTEND to MODE on IV. */
static bool
-iv_extend (struct rtx_iv *iv, enum iv_extend_code extend, scalar_int_mode mode)
+iv_extend (class rtx_iv *iv, enum iv_extend_code extend, scalar_int_mode mode)
{
/* If iv is invariant, just calculate the new value. */
if (iv->step == const0_rtx
/* Evaluates negation of IV. */
static bool
-iv_neg (struct rtx_iv *iv)
+iv_neg (class rtx_iv *iv)
{
if (iv->extend == IV_UNKNOWN_EXTEND)
{
/* Evaluates addition or subtraction (according to OP) of IV1 to IV0. */
static bool
-iv_add (struct rtx_iv *iv0, struct rtx_iv *iv1, enum rtx_code op)
+iv_add (class rtx_iv *iv0, class rtx_iv *iv1, enum rtx_code op)
{
scalar_int_mode mode;
rtx arg;
/* Evaluates multiplication of IV by constant CST. */
static bool
-iv_mult (struct rtx_iv *iv, rtx mby)
+iv_mult (class rtx_iv *iv, rtx mby)
{
scalar_int_mode mode = iv->extend_mode;
/* Evaluates shift of IV by constant CST. */
static bool
-iv_shift (struct rtx_iv *iv, rtx mby)
+iv_shift (class rtx_iv *iv, rtx mby)
{
scalar_int_mode mode = iv->extend_mode;
/* Records information that DEF is induction variable IV. */
static void
-record_iv (df_ref def, struct rtx_iv *iv)
+record_iv (df_ref def, class rtx_iv *iv)
{
- struct rtx_iv *recorded_iv = XNEW (struct rtx_iv);
+ class rtx_iv *recorded_iv = XNEW (class rtx_iv);
*recorded_iv = *iv;
check_iv_ref_table_size ();
IV and return true. Otherwise return false. */
static bool
-analyzed_for_bivness_p (rtx def, struct rtx_iv *iv)
+analyzed_for_bivness_p (rtx def, class rtx_iv *iv)
{
- struct biv_entry *biv = bivs->find_with_hash (def, REGNO (def));
+ class biv_entry *biv = bivs->find_with_hash (def, REGNO (def));
if (!biv)
return false;
}
static void
-record_biv (rtx def, struct rtx_iv *iv)
+record_biv (rtx def, class rtx_iv *iv)
{
- struct biv_entry *biv = XNEW (struct biv_entry);
+ class biv_entry *biv = XNEW (class biv_entry);
biv_entry **slot = bivs->find_slot_with_hash (def, REGNO (def), INSERT);
biv->regno = REGNO (def);
to *IV. OUTER_MODE is the mode of DEF. */
static bool
-iv_analyze_biv (scalar_int_mode outer_mode, rtx def, struct rtx_iv *iv)
+iv_analyze_biv (scalar_int_mode outer_mode, rtx def, class rtx_iv *iv)
{
rtx inner_step, outer_step;
scalar_int_mode inner_mode;
bool
iv_analyze_expr (rtx_insn *insn, scalar_int_mode mode, rtx rhs,
- struct rtx_iv *iv)
+ class rtx_iv *iv)
{
rtx mby = NULL_RTX;
rtx op0 = NULL_RTX, op1 = NULL_RTX;
- struct rtx_iv iv0, iv1;
+ class rtx_iv iv0, iv1;
enum rtx_code code = GET_CODE (rhs);
scalar_int_mode omode = mode;
/* Analyzes iv DEF and stores the result to *IV. */
static bool
-iv_analyze_def (df_ref def, struct rtx_iv *iv)
+iv_analyze_def (df_ref def, class rtx_iv *iv)
{
rtx_insn *insn = DF_REF_INSN (def);
rtx reg = DF_REF_REG (def);
mode of OP. */
static bool
-iv_analyze_op (rtx_insn *insn, scalar_int_mode mode, rtx op, struct rtx_iv *iv)
+iv_analyze_op (rtx_insn *insn, scalar_int_mode mode, rtx op, class rtx_iv *iv)
{
df_ref def = NULL;
enum iv_grd_result res;
mode of VAL. */
bool
-iv_analyze (rtx_insn *insn, scalar_int_mode mode, rtx val, struct rtx_iv *iv)
+iv_analyze (rtx_insn *insn, scalar_int_mode mode, rtx val, class rtx_iv *iv)
{
rtx reg;
/* Analyzes definition of DEF in INSN and stores the result to IV. */
bool
-iv_analyze_result (rtx_insn *insn, rtx def, struct rtx_iv *iv)
+iv_analyze_result (rtx_insn *insn, rtx def, class rtx_iv *iv)
{
df_ref adef;
bool
biv_p (rtx_insn *insn, scalar_int_mode mode, rtx reg)
{
- struct rtx_iv iv;
+ class rtx_iv iv;
df_ref def, last_def;
if (!simple_reg_p (reg))
/* Calculates value of IV at ITERATION-th iteration. */
rtx
-get_iv_value (struct rtx_iv *iv, rtx iteration)
+get_iv_value (class rtx_iv *iv, rtx iteration)
{
rtx val;
static rtx
find_single_def_src (unsigned int regno)
{
- df_ref adef;
- rtx set, src;
+ rtx src = NULL_RTX;
- for (;;)
+ /* Don't look through unbounded number of single definition REG copies,
+ there might be loops for sources with uninitialized variables. */
+ for (int cnt = 0; cnt < 128; cnt++)
{
- rtx note;
- adef = DF_REG_DEF_CHAIN (regno);
+ df_ref adef = DF_REG_DEF_CHAIN (regno);
if (adef == NULL || DF_REF_NEXT_REG (adef) != NULL
|| DF_REF_IS_ARTIFICIAL (adef))
return NULL_RTX;
- set = single_set (DF_REF_INSN (adef));
+ rtx set = single_set (DF_REF_INSN (adef));
if (set == NULL || !REG_P (SET_DEST (set))
|| REGNO (SET_DEST (set)) != regno)
return NULL_RTX;
- note = find_reg_equal_equiv_note (DF_REF_INSN (adef));
-
+ rtx note = find_reg_equal_equiv_note (DF_REF_INSN (adef));
if (note && function_invariant_p (XEXP (note, 0)))
{
src = XEXP (note, 0);
is a list, its elements are assumed to be combined using OP. */
static void
-simplify_using_initial_values (struct loop *loop, enum rtx_code op, rtx *expr)
+simplify_using_initial_values (class loop *loop, enum rtx_code op, rtx *expr)
{
bool expression_valid;
rtx head, tail, last_valid_expr;
continue;
CLEAR_REG_SET (this_altered);
- note_stores (PATTERN (insn), mark_altered, this_altered);
+ note_stores (insn, mark_altered, this_altered);
if (CALL_P (insn))
{
- /* Kill all call clobbered registers. */
- unsigned int i;
- hard_reg_set_iterator hrsi;
- EXECUTE_IF_SET_IN_HARD_REG_SET (regs_invalidated_by_call,
- 0, i, hrsi)
- SET_REGNO_REG_SET (this_altered, i);
+ /* Kill all registers that might be clobbered by the call.
+ We don't track modes of hard registers, so we need to be
+ conservative and assume that partial kills are full kills. */
+ function_abi callee_abi = insn_callee_abi (insn);
+ IOR_REG_SET_HRS (this_altered,
+ callee_abi.full_and_partial_reg_clobbers ());
}
if (suitable_set_for_replacement (insn, &dest, &src))
is SIGNED_P to DESC. */
static void
-shorten_into_mode (struct rtx_iv *iv, scalar_int_mode mode,
- enum rtx_code cond, bool signed_p, struct niter_desc *desc)
+shorten_into_mode (class rtx_iv *iv, scalar_int_mode mode,
+ enum rtx_code cond, bool signed_p, class niter_desc *desc)
{
rtx mmin, mmax, cond_over, cond_under;
some assumptions to DESC). */
static bool
-canonicalize_iv_subregs (struct rtx_iv *iv0, struct rtx_iv *iv1,
- enum rtx_code cond, struct niter_desc *desc)
+canonicalize_iv_subregs (class rtx_iv *iv0, class rtx_iv *iv1,
+ enum rtx_code cond, class niter_desc *desc)
{
scalar_int_mode comp_mode;
bool signed_p;
expression for the number of iterations, before we tried to simplify it. */
static uint64_t
-determine_max_iter (struct loop *loop, struct niter_desc *desc, rtx old_niter)
+determine_max_iter (class loop *loop, class niter_desc *desc, rtx old_niter)
{
rtx niter = desc->niter_expr;
rtx mmin, mmax, cmp;
(basically its rtl version), complicated by things like subregs. */
static void
-iv_number_of_iterations (struct loop *loop, rtx_insn *insn, rtx condition,
- struct niter_desc *desc)
+iv_number_of_iterations (class loop *loop, rtx_insn *insn, rtx condition,
+ class niter_desc *desc)
{
rtx op0, op1, delta, step, bound, may_xform, tmp, tmp0, tmp1;
- struct rtx_iv iv0, iv1;
+ class rtx_iv iv0, iv1;
rtx assumption, may_not_xform;
enum rtx_code cond;
machine_mode nonvoid_mode;
into DESC. */
static void
-check_simple_exit (struct loop *loop, edge e, struct niter_desc *desc)
+check_simple_exit (class loop *loop, edge e, class niter_desc *desc)
{
basic_block exit_bb;
rtx condition;
/* Finds a simple exit of LOOP and stores its description into DESC. */
-void
-find_simple_exit (struct loop *loop, struct niter_desc *desc)
+static void
+find_simple_exit (class loop *loop, class niter_desc *desc)
{
unsigned i;
basic_block *body;
edge e;
- struct niter_desc act;
+ class niter_desc act;
bool any = false;
edge_iterator ei;
/* Creates a simple loop description of LOOP if it was not computed
already. */
-struct niter_desc *
-get_simple_loop_desc (struct loop *loop)
+class niter_desc *
+get_simple_loop_desc (class loop *loop)
{
- struct niter_desc *desc = simple_loop_desc (loop);
+ class niter_desc *desc = simple_loop_desc (loop);
if (desc)
return desc;
/* Releases simple loop description for LOOP. */
void
-free_simple_loop_desc (struct loop *loop)
+free_simple_loop_desc (class loop *loop)
{
- struct niter_desc *desc = simple_loop_desc (loop);
+ class niter_desc *desc = simple_loop_desc (loop);
if (!desc)
return;