/* Discovery of auto-inc and auto-dec instructions.
- Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2006-2016 Free Software Foundation, Inc.
Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
-#include "tree.h"
+#include "backend.h"
+#include "target.h"
#include "rtl.h"
-#include "tm_p.h"
-#include "hard-reg-set.h"
-#include "basic-block.h"
+#include "tree.h"
+#include "predict.h"
+#include "df.h"
#include "insn-config.h"
-#include "regs.h"
-#include "flags.h"
-#include "function.h"
-#include "except.h"
-#include "diagnostic-core.h"
+#include "emit-rtl.h"
#include "recog.h"
+#include "cfgrtl.h"
#include "expr.h"
#include "tree-pass.h"
-#include "df.h"
#include "dbgcnt.h"
-#include "target.h"
+#include "print-rtl.h"
/* This pass was originally removed from flow.c. However there is
almost nothing that remains of that code.
before the ref or +c if the increment was after the ref, then if we
can do the combination but switch the pre/post bit. */
-#ifdef AUTO_INC_DEC
enum form
{
static struct inc_insn
{
- rtx insn; /* The insn being parsed. */
+ rtx_insn *insn; /* The insn being parsed. */
rtx pat; /* The pattern of the insn. */
bool reg1_is_const; /* True if reg1 is const, false if reg1 is a reg. */
enum form form;
static struct mem_insn
{
- rtx insn; /* The insn being parsed. */
+ rtx_insn *insn; /* The insn being parsed. */
rtx pat; /* The pattern of the insn. */
rtx *mem_loc; /* The address of the field that holds the mem */
/* that is to be replaced. */
must be compared with the current block.
*/
-static rtx *reg_next_use = NULL;
-static rtx *reg_next_inc_use = NULL;
-static rtx *reg_next_def = NULL;
+static rtx_insn **reg_next_use = NULL;
+static rtx_insn **reg_next_inc_use = NULL;
+static rtx_insn **reg_next_def = NULL;
/* Move dead note that match PATTERN to TO_INSN from FROM_INSN. We do
does not appear that there are any other kinds of relevant notes. */
static void
-move_dead_notes (rtx to_insn, rtx from_insn, rtx pattern)
+move_dead_notes (rtx_insn *to_insn, rtx_insn *from_insn, rtx pattern)
{
rtx note;
rtx next_note;
}
}
-
-/* Create a mov insn DEST_REG <- SRC_REG and insert it before
- NEXT_INSN. */
-
-static rtx
-insert_move_insn_before (rtx next_insn, rtx dest_reg, rtx src_reg)
-{
- rtx insns;
-
- start_sequence ();
- emit_move_insn (dest_reg, src_reg);
- insns = get_insns ();
- end_sequence ();
- emit_insn_before (insns, next_insn);
- return insns;
-}
-
-
/* Change mem_insn.mem_loc so that uses NEW_ADDR which has an
increment of INC_REG. To have reached this point, the change is a
legitimate one from a dataflow point of view. The only questions
handled mov free. */
basic_block bb = BLOCK_FOR_INSN (mem_insn.insn);
- rtx mov_insn = NULL;
+ rtx_insn *mov_insn = NULL;
int regno;
rtx mem = *mem_insn.mem_loc;
- enum machine_mode mode = GET_MODE (mem);
+ machine_mode mode = GET_MODE (mem);
rtx new_mem;
int old_cost = 0;
int new_cost = 0;
PUT_MODE (mem_tmp, mode);
XEXP (mem_tmp, 0) = new_addr;
- old_cost = (set_src_cost (mem, speed)
+ old_cost = (set_src_cost (mem, mode, speed)
+ set_rtx_cost (PATTERN (inc_insn.insn), speed));
- new_cost = set_src_cost (mem_tmp, speed);
+
+ new_cost = set_src_cost (mem_tmp, mode, speed);
+
+ /* In the FORM_PRE_ADD and FORM_POST_ADD cases we emit an extra move
+ whose cost we should account for. */
+ if (inc_insn.form == FORM_PRE_ADD
+ || inc_insn.form == FORM_POST_ADD)
+ {
+ start_sequence ();
+ emit_move_insn (inc_insn.reg_res, inc_insn.reg0);
+ mov_insn = get_insns ();
+ end_sequence ();
+ new_cost += seq_cost (mov_insn, speed);
+ }
/* The first item of business is to see if this is profitable. */
if (old_cost < new_cost)
/* Replace the addition with a move. Do it at the location of
the addition since the operand of the addition may change
before the memory reference. */
- mov_insn = insert_move_insn_before (inc_insn.insn,
- inc_insn.reg_res, inc_insn.reg0);
+ gcc_assert (mov_insn);
+ emit_insn_before (mov_insn, inc_insn.insn);
move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0);
regno = REGNO (inc_insn.reg_res);
break;
case FORM_POST_ADD:
- mov_insn = insert_move_insn_before (mem_insn.insn,
- inc_insn.reg_res, inc_insn.reg0);
+ gcc_assert (mov_insn);
+ emit_insn_before (mov_insn, mem_insn.insn);
move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0);
/* Do not move anything to the mov insn because the instruction
/* The width of the mem being accessed. */
int size = GET_MODE_SIZE (GET_MODE (mem));
- rtx last_insn = NULL;
- enum machine_mode reg_mode = GET_MODE (inc_reg);
+ rtx_insn *last_insn = NULL;
+ machine_mode reg_mode = GET_MODE (inc_reg);
switch (inc_insn.form)
{
NEXT_ARRAY) or defines (if reg_next_def is passed in NEXT_ARRAY)
REGNO in BB. */
-static rtx
-get_next_ref (int regno, basic_block bb, rtx *next_array)
+static rtx_insn *
+get_next_ref (int regno, basic_block bb, rtx_insn **next_array)
{
- rtx insn = next_array[regno];
+ rtx_insn *insn = next_array[regno];
/* Lazy about cleaning out the next_arrays. */
if (insn && BLOCK_FOR_INSN (insn) != bb)
}
-/* Reverse the operands in a mem insn. */
-
-static void
-reverse_mem (void)
-{
- rtx tmp = mem_insn.reg1;
- mem_insn.reg1 = mem_insn.reg0;
- mem_insn.reg0 = tmp;
-}
-
-
-/* Reverse the operands in a inc insn. */
-
-static void
-reverse_inc (void)
-{
- rtx tmp = inc_insn.reg1;
- inc_insn.reg1 = inc_insn.reg0;
- inc_insn.reg0 = tmp;
-}
-
-
/* Return true if INSN is of a form "a = b op c" where a and b are
regs. op is + if c is a reg and +|- if c is a const. Fill in
INC_INSN with what is found.
processed. */
static bool
-parse_add_or_inc (rtx insn, bool before_mem)
+parse_add_or_inc (rtx_insn *insn, bool before_mem)
{
rtx pat = single_set (insn);
if (!pat)
{
/* Reverse the two operands and turn *_ADD into *_INC since
a = c + a. */
- reverse_inc ();
+ std::swap (inc_insn.reg0, inc_insn.reg1);
inc_insn.form = before_mem ? FORM_PRE_INC : FORM_POST_INC;
return true;
}
static bool
find_inc (bool first_try)
{
- rtx insn;
+ rtx_insn *insn;
basic_block bb = BLOCK_FOR_INSN (mem_insn.insn);
- rtx other_insn;
- df_ref *def_rec;
+ rtx_insn *other_insn;
+ df_ref def;
/* Make sure this reg appears only once in this insn. */
if (count_occurrences (PATTERN (mem_insn.insn), mem_insn.reg0, 1) != 1)
find this. Only try it once though. */
if (first_try && !mem_insn.reg1_is_const)
{
- reverse_mem ();
+ std::swap (mem_insn.reg0, mem_insn.reg1);
return find_inc (false);
}
else
/* Need to assure that none of the operands of the inc instruction are
assigned to by the mem insn. */
- for (def_rec = DF_INSN_DEFS (mem_insn.insn); *def_rec; def_rec++)
+ FOR_EACH_INSN_DEF (def, mem_insn.insn)
{
- df_ref def = *def_rec;
unsigned int regno = DF_REF_REGNO (def);
if ((regno == REGNO (inc_insn.reg0))
|| (regno == REGNO (inc_insn.reg_res)))
{
/* Make sure that there is no insn that assigns to inc_insn.res
between the mem_insn and the inc_insn. */
- rtx other_insn = get_next_ref (REGNO (inc_insn.reg_res),
- BLOCK_FOR_INSN (mem_insn.insn),
- reg_next_def);
+ rtx_insn *other_insn = get_next_ref (REGNO (inc_insn.reg_res),
+ BLOCK_FOR_INSN (mem_insn.insn),
+ reg_next_def);
if (other_insn != inc_insn.insn)
{
if (dump_file)
return false;
if (!rtx_equal_p (mem_insn.reg0, inc_insn.reg0))
- reverse_inc ();
+ std::swap (inc_insn.reg0, inc_insn.reg1);
}
other_insn
then we just abandon this. */
int luid = DF_INSN_LUID (inc_insn.insn);
- rtx other_insn;
+ rtx_insn *other_insn;
/* Make sure this reg appears only once in this insn. */
if (count_occurrences (PATTERN (mem_insn.insn), mem_insn.reg1, 1) != 1)
/* See comment above on find_inc (false) call. */
if (first_try)
{
- reverse_mem ();
+ std::swap (mem_insn.reg0, mem_insn.reg1);
return find_inc (false);
}
else
{
/* We know that mem_insn.reg0 must equal inc_insn.reg1
or else we would not have found the inc insn. */
- reverse_mem ();
+ std::swap (mem_insn.reg0, mem_insn.reg1);
if (!rtx_equal_p (mem_insn.reg0, inc_insn.reg0))
{
/* See comment above on find_inc (false) call. */
{
if (first_try)
{
- reverse_mem ();
+ std::swap (mem_insn.reg0, mem_insn.reg1);
return find_inc (false);
}
else
static void
merge_in_block (int max_reg, basic_block bb)
{
- rtx insn;
- rtx curr;
+ rtx_insn *insn;
+ rtx_insn *curr;
int success_in_block = 0;
if (dump_file)
FOR_BB_INSNS_REVERSE_SAFE (bb, insn, curr)
{
- unsigned int uid = INSN_UID (insn);
bool insn_is_add_or_inc = true;
if (!NONDEBUG_INSN_P (insn))
clear of c because the inc insn is going to move
into the mem_insn.insn. */
int luid = DF_INSN_LUID (mem_insn.insn);
- rtx other_insn
+ rtx_insn *other_insn
= get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_use);
if (other_insn && luid > DF_INSN_LUID (other_insn))
/* If the inc insn was merged with a mem, the inc insn is gone
and there is noting to update. */
- if (DF_INSN_UID_GET (uid))
+ if (df_insn_info *insn_info = DF_INSN_INFO_GET (insn))
{
- df_ref *def_rec;
- df_ref *use_rec;
+ df_ref def, use;
+
/* Need to update next use. */
- for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
+ FOR_EACH_INSN_INFO_DEF (def, insn_info)
{
- df_ref def = *def_rec;
reg_next_use[DF_REF_REGNO (def)] = NULL;
reg_next_inc_use[DF_REF_REGNO (def)] = NULL;
reg_next_def[DF_REF_REGNO (def)] = insn;
}
- for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
+ FOR_EACH_INSN_INFO_USE (use, insn_info)
{
- df_ref use = *use_rec;
reg_next_use[DF_REF_REGNO (use)] = insn;
if (insn_is_add_or_inc)
reg_next_inc_use[DF_REF_REGNO (use)] = insn;
}
}
else if (dump_file)
- fprintf (dump_file, "skipping update of deleted insn %d\n", uid);
+ fprintf (dump_file, "skipping update of deleted insn %d\n",
+ INSN_UID (insn));
}
/* If we were successful, try again. There may have been several
{
/* In this case, we must clear these vectors since the trick of
testing if the stale insn in the block will not work. */
- memset (reg_next_use, 0, max_reg * sizeof(rtx));
- memset (reg_next_inc_use, 0, max_reg * sizeof(rtx));
- memset (reg_next_def, 0, max_reg * sizeof(rtx));
+ memset (reg_next_use, 0, max_reg * sizeof (rtx));
+ memset (reg_next_inc_use, 0, max_reg * sizeof (rtx));
+ memset (reg_next_def, 0, max_reg * sizeof (rtx));
df_recompute_luids (bb);
merge_in_block (max_reg, bb);
}
}
-#endif
+/* Discover auto-inc auto-dec instructions. */
+
+namespace {
+
+const pass_data pass_data_inc_dec =
+{
+ RTL_PASS, /* type */
+ "auto_inc_dec", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_AUTO_INC_DEC, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_df_finish, /* todo_flags_finish */
+};
-static unsigned int
-rest_of_handle_auto_inc_dec (void)
+class pass_inc_dec : public rtl_opt_pass
{
-#ifdef AUTO_INC_DEC
+public:
+ pass_inc_dec (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_inc_dec, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *)
+ {
+ if (!AUTO_INC_DEC)
+ return false;
+
+ return (optimize > 0 && flag_auto_inc_dec);
+ }
+
+
+ unsigned int execute (function *);
+
+}; // class pass_inc_dec
+
+unsigned int
+pass_inc_dec::execute (function *fun ATTRIBUTE_UNUSED)
+{
+ if (!AUTO_INC_DEC)
+ return 0;
+
basic_block bb;
int max_reg = max_reg_num ();
df_note_add_problem ();
df_analyze ();
- reg_next_use = XCNEWVEC (rtx, max_reg);
- reg_next_inc_use = XCNEWVEC (rtx, max_reg);
- reg_next_def = XCNEWVEC (rtx, max_reg);
- FOR_EACH_BB (bb)
+ reg_next_use = XCNEWVEC (rtx_insn *, max_reg);
+ reg_next_inc_use = XCNEWVEC (rtx_insn *, max_reg);
+ reg_next_def = XCNEWVEC (rtx_insn *, max_reg);
+ FOR_EACH_BB_FN (bb, fun)
merge_in_block (max_reg, bb);
free (reg_next_use);
free (reg_next_def);
mem_tmp = NULL;
-#endif
+
return 0;
}
+} // anon namespace
-/* Discover auto-inc auto-dec instructions. */
-
-static bool
-gate_auto_inc_dec (void)
+rtl_opt_pass *
+make_pass_inc_dec (gcc::context *ctxt)
{
-#ifdef AUTO_INC_DEC
- return (optimize > 0 && flag_auto_inc_dec);
-#else
- return false;
-#endif
+ return new pass_inc_dec (ctxt);
}
-
-
-struct rtl_opt_pass pass_inc_dec =
-{
- {
- RTL_PASS,
- "auto_inc_dec", /* name */
- gate_auto_inc_dec, /* gate */
- rest_of_handle_auto_inc_dec, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_AUTO_INC_DEC, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_df_finish, /* todo_flags_finish */
- }
-};