aboutsummaryrefslogtreecommitdiff
path: root/gcc/cfgrtl.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cfgrtl.c')
-rw-r--r--gcc/cfgrtl.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index 569a604..a08d29f 100644
--- a/gcc/cfgrtl.c
+++ b/gcc/cfgrtl.c
@@ -56,6 +56,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "obstack.h"
#include "insn-config.h"
#include "cfglayout.h"
+#include "expr.h"
/* Stubs in case we don't have a return insn. */
#ifndef HAVE_return
@@ -88,6 +89,7 @@ static bool rtl_redirect_edge_and_branch (edge, basic_block);
static edge rtl_split_block (basic_block, void *);
static void rtl_dump_bb (basic_block, FILE *);
static int rtl_verify_flow_info_1 (void);
+static void mark_killed_regs (rtx, rtx, void *);
/* Return true if NOTE is not one of the ones that must be kept paired,
so that we may simply delete it. */
@@ -1305,6 +1307,101 @@ insert_insn_on_edge (rtx pattern, edge e)
end_sequence ();
}
+/* Called from safe_insert_insn_on_edge through note_stores, marks live
+ registers that are killed by the store. */
+static void
+mark_killed_regs (rtx reg, rtx set ATTRIBUTE_UNUSED, void *data)
+{
+ regset killed = data;
+ int regno, i;
+
+ if (GET_CODE (reg) == SUBREG)
+ reg = SUBREG_REG (reg);
+ if (!REG_P (reg))
+ return;
+ regno = REGNO (reg);
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ SET_REGNO_REG_SET (killed, regno);
+ else
+ {
+ for (i = 0; i < HARD_REGNO_NREGS (regno, GET_MODE (reg)); i++)
+ SET_REGNO_REG_SET (killed, regno + i);
+ }
+}
+
+/* Similar to insert_insn_on_edge, tries to put INSN to edge E. Additionally
+ it checks whether this will not clobber the registers that are live on the
+ edge (i.e. it requieres liveness information to be up-to-date) and if there
+ are some, then it tries to save and restore them. Returns true if
+ succesful. */
+bool
+safe_insert_insn_on_edge (rtx insn, edge e)
+{
+ rtx x;
+ regset_head killed_head;
+ regset killed = INITIALIZE_REG_SET (killed_head);
+ rtx save_regs = NULL_RTX;
+ int regno, noccmode;
+ enum machine_mode mode;
+
+#ifdef AVOID_CCMODE_COPIES
+ noccmode = true;
+#else
+ noccmode = false;
+#endif
+
+ for (x = insn; x; x = NEXT_INSN (x))
+ if (INSN_P (x))
+ note_stores (PATTERN (x), mark_killed_regs, killed);
+ bitmap_operation (killed, killed, e->dest->global_live_at_start,
+ BITMAP_AND);
+
+ EXECUTE_IF_SET_IN_REG_SET (killed, 0, regno,
+ {
+ mode = regno < FIRST_PSEUDO_REGISTER
+ ? reg_raw_mode[regno]
+ : GET_MODE (regno_reg_rtx[regno]);
+ if (mode == VOIDmode)
+ return false;
+
+ if (noccmode && mode == CCmode)
+ return false;
+
+ save_regs = alloc_EXPR_LIST (0,
+ alloc_EXPR_LIST (0,
+ gen_reg_rtx (mode),
+ gen_raw_REG (mode, regno)),
+ save_regs);
+ });
+
+ if (save_regs)
+ {
+ rtx from, to;
+
+ start_sequence ();
+ for (x = save_regs; x; x = XEXP (x, 1))
+ {
+ from = XEXP (XEXP (x, 0), 1);
+ to = XEXP (XEXP (x, 0), 0);
+ emit_move_insn (to, from);
+ }
+ emit_insn (insn);
+ for (x = save_regs; x; x = XEXP (x, 1))
+ {
+ from = XEXP (XEXP (x, 0), 0);
+ to = XEXP (XEXP (x, 0), 1);
+ emit_move_insn (to, from);
+ }
+ insn = get_insns ();
+ end_sequence ();
+ free_EXPR_LIST_list (&save_regs);
+ }
+ insert_insn_on_edge (insn, e);
+
+ FREE_REG_SET (killed);
+ return true;
+}
+
/* Update the CFG for the instructions queued on edge E. */
static void