summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/config/arc/arc.c116
2 files changed, 125 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e53a9950822..5cb07b7882f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,14 @@
2013-11-16 Joern Rennecke <joern.rennecke@embecosm.com>
+ * config/arc/arc.c (arc_predicate_delay_insns): New function.
+ (pass_data_arc_predicate_delay_insns): New pass_data instance.
+ (pass_arc_predicate_delay_insns): New subclass of rtl_opt_class.
+ (make_pass_arc_predicate_delay_insns): New function.
+ (arc_init): Register pass_arc_predicate_delay_insns if
+ flag_delayed_branch is active.
+
+2013-11-16 Joern Rennecke <joern.rennecke@embecosm.com>
+
* config/arc/constraints.md (Rcq): Simplify register number test.
2013-11-15 Aldy Hernandez <aldyh@redhat.com>
diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index 7b1853b7f9b..f813c90763d 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -632,6 +632,44 @@ make_pass_arc_ifcvt (gcc::context *ctxt)
return new pass_arc_ifcvt (ctxt);
}
+static unsigned arc_predicate_delay_insns (void);
+
+namespace {
+
+const pass_data pass_data_arc_predicate_delay_insns =
+{
+ RTL_PASS,
+ "arc_predicate_delay_insns", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ false, /* has_gate */
+ true, /* has_execute */
+ TV_IFCVT2, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_df_finish /* todo_flags_finish */
+};
+
+class pass_arc_predicate_delay_insns : public rtl_opt_pass
+{
+public:
+ pass_arc_predicate_delay_insns(gcc::context *ctxt)
+ : rtl_opt_pass(pass_data_arc_predicate_delay_insns, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ unsigned int execute () { return arc_predicate_delay_insns (); }
+};
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_arc_predicate_delay_insns (gcc::context *ctxt)
+{
+ return new pass_arc_predicate_delay_insns (ctxt);
+}
+
/* Called by OVERRIDE_OPTIONS to initialize various things. */
void
@@ -752,6 +790,16 @@ arc_init (void)
register_pass (&arc_ifcvt4_info);
register_pass (&arc_ifcvt5_info);
}
+
+ if (flag_delayed_branch)
+ {
+ opt_pass *pass_arc_predicate_delay_insns
+ = make_pass_arc_predicate_delay_insns (g);
+ struct register_pass_info arc_predicate_delay_info
+ = { pass_arc_predicate_delay_insns, "dbr", 1, PASS_POS_INSERT_AFTER };
+
+ register_pass (&arc_predicate_delay_info);
+ }
}
/* Check ARC options, generate derived target attributes. */
@@ -8297,6 +8345,74 @@ arc_ifcvt (void)
return 0;
}
+/* Find annulled delay insns and convert them to use the appropriate predicate.
+ This allows branch shortening to size up these insns properly. */
+
+static unsigned
+arc_predicate_delay_insns (void)
+{
+ for (rtx insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ rtx pat, jump, dlay, src, cond, *patp;
+ int reverse;
+
+ if (!NONJUMP_INSN_P (insn)
+ || GET_CODE (pat = PATTERN (insn)) != SEQUENCE)
+ continue;
+ jump = XVECEXP (pat, 0, 0);
+ dlay = XVECEXP (pat, 0, 1);
+ if (!JUMP_P (jump) || !INSN_ANNULLED_BRANCH_P (jump))
+ continue;
+ /* If the branch insn does the annulling, leave the delay insn alone. */
+ if (!TARGET_AT_DBR_CONDEXEC && !INSN_FROM_TARGET_P (dlay))
+ continue;
+ /* ??? Could also leave DLAY un-conditionalized if its target is dead
+ on the other path. */
+ gcc_assert (GET_CODE (PATTERN (jump)) == SET);
+ gcc_assert (SET_DEST (PATTERN (jump)) == pc_rtx);
+ src = SET_SRC (PATTERN (jump));
+ gcc_assert (GET_CODE (src) == IF_THEN_ELSE);
+ cond = XEXP (src, 0);
+ if (XEXP (src, 2) == pc_rtx)
+ reverse = 0;
+ else if (XEXP (src, 1) == pc_rtx)
+ reverse = 1;
+ else
+ gcc_unreachable ();
+ if (!INSN_FROM_TARGET_P (dlay) != reverse)
+ {
+ enum machine_mode ccm = GET_MODE (XEXP (cond, 0));
+ enum rtx_code code = reverse_condition (GET_CODE (cond));
+ if (code == UNKNOWN || ccm == CC_FP_GTmode || ccm == CC_FP_GEmode)
+ code = reverse_condition_maybe_unordered (GET_CODE (cond));
+
+ cond = gen_rtx_fmt_ee (code, GET_MODE (cond),
+ copy_rtx (XEXP (cond, 0)),
+ copy_rtx (XEXP (cond, 1)));
+ }
+ else
+ cond = copy_rtx (cond);
+ patp = &PATTERN (dlay);
+ pat = *patp;
+ /* dwarf2out.c:dwarf2out_frame_debug_expr doesn't know
+ what to do with COND_EXEC. */
+ if (RTX_FRAME_RELATED_P (dlay))
+ {
+ /* As this is the delay slot insn of an anulled branch,
+ dwarf2out.c:scan_trace understands the anulling semantics
+ without the COND_EXEC. */
+ rtx note = alloc_reg_note (REG_FRAME_RELATED_EXPR, pat,
+ REG_NOTES (dlay));
+ validate_change (dlay, &REG_NOTES (dlay), note, 1);
+ }
+ pat = gen_rtx_COND_EXEC (VOIDmode, cond, pat);
+ validate_change (dlay, patp, pat, 1);
+ if (!apply_change_group ())
+ gcc_unreachable ();
+ }
+ return 0;
+}
+
/* For ARC600: If a write to a core reg >=32 appears in a delay slot
(other than of a forward brcc), it creates a hazard when there is a read
of the same register at the branch target. We can't know what is at the