This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[Committed] [PATCH, 2/2] shrink wrap a function with a single loop: split live_edge
- From: Zhenqiang Chen <zhenqiang dot chen at linaro dot org>
- To: Jeff Law <law at redhat dot com>
- Cc: "gcc-patches at gcc dot gnu dot org" <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 15 May 2014 14:35:53 +0800
- Subject: [Committed] [PATCH, 2/2] shrink wrap a function with a single loop: split live_edge
- Authentication-results: sourceware.org; auth=none
On 15 May 2014 02:03, Jeff Law <law@redhat.com> wrote:
> On 05/13/14 03:49, Zhenqiang Chen wrote:
>>
>> On 9 May 2014 14:08, Jeff Law <law@redhat.com> wrote:
>>>
>>> On 05/08/14 02:07, Zhenqiang Chen wrote:
>>>>
>>>>
>>>> Hi,
>>>>
>>>> The patch splits the live_edge for move_insn_for_shrink_wrap to sink
>>>> the copy out of the entry block.
>>>>
>>>> Bootstrap and no make check regression on X86-64 and ARM.
>>>>
>>>> OK for trunk?
>>>>
>>>> Thanks!
>>>> -Zhenqiang
>>>>
>>>> ChangeLog:
>>>> 2014-05-08 Zhenqiang Chen <zhenqiang.chen@linaro.org>
>>>>
>>>> * function.c (next_block_for_reg): Allow live_edge->dest has
>>>> two
>>>> predecessors.
>>>> (move_insn_for_shrink_wrap): Split live_edge.
>>>> (prepre_shrink_wrap): One more parameter for
>>>> move_insn_for_shrink_wrap.
>
> OK.
Thanks. Committed @210457 with one comment change for shrink-wrap.h
diff --git a/gcc/shrink-wrap.h b/gcc/shrink-wrap.h
index 22b1d5c..bccfb31 100644
--- a/gcc/shrink-wrap.h
+++ b/gcc/shrink-wrap.h
@@ -1,4 +1,4 @@
-/* Structure for saving state for a nested function.
+/* Shrink-wrapping related functions.
Copyright (C) 1989-2014 Free Software Foundation, Inc.
ChangeLog:
2014-05-15 Zhenqiang Chen <zhenqiang.chen@linaro.org>
* shrink-wrap.h: Update comment.
* shrink-wrap.c: Update comment.
(next_block_for_reg): Rename to live_edge_for_reg.
(live_edge_for_reg): Allow live_edge->dest has two predecessors.
(move_insn_for_shrink_wrap): Split live_edge.
(prepre_shrink_wrap): One more parameter for move_insn_for_shrink_wrap.
diff --git a/gcc/shrink-wrap.c b/gcc/shrink-wrap.c
index b302777..6f0cd0c 100644
--- a/gcc/shrink-wrap.c
+++ b/gcc/shrink-wrap.c
@@ -1,4 +1,4 @@
-/* Expands front end tree to back end RTL for GCC.
+/* Shrink-wrapping related optimizations.
Copyright (C) 1987-2014 Free Software Foundation, Inc.
This file is part of GCC.
@@ -110,12 +110,12 @@ requires_stack_frame_p (rtx insn, HARD_REG_SET prologue_used,
return false;
}
-/* See whether BB has a single successor that uses [REGNO, END_REGNO),
- and if BB is its only predecessor. Return that block if so,
- otherwise return null. */
+/* See whether there has a single live edge from BB, which dest uses
+ [REGNO, END_REGNO). Return the live edge if its dest bb has
+ one or two predecessors. Otherwise return NULL. */
-static basic_block
-next_block_for_reg (basic_block bb, int regno, int end_regno)
+static edge
+live_edge_for_reg (basic_block bb, int regno, int end_regno)
{
edge e, live_edge;
edge_iterator ei;
@@ -148,25 +148,30 @@ next_block_for_reg (basic_block bb, int regno, int end_regno)
if (live_edge->flags & EDGE_ABNORMAL)
return NULL;
- if (EDGE_COUNT (live_edge->dest->preds) > 1)
+ /* When live_edge->dest->preds == 2, we can create a new block on
+ the edge to make it meet the requirement. */
+ if (EDGE_COUNT (live_edge->dest->preds) > 2)
return NULL;
- return live_edge->dest;
+ return live_edge;
}
/* Try to move INSN from BB to a successor. Return true on success.
USES and DEFS are the set of registers that are used and defined
- after INSN in BB. */
+ after INSN in BB. SPLIT_P indicates whether a live edge from BB
+ is splitted or not. */
static bool
move_insn_for_shrink_wrap (basic_block bb, rtx insn,
const HARD_REG_SET uses,
- const HARD_REG_SET defs)
+ const HARD_REG_SET defs,
+ bool *split_p)
{
rtx set, src, dest;
bitmap live_out, live_in, bb_uses, bb_defs;
unsigned int i, dregno, end_dregno, sregno, end_sregno;
basic_block next_block;
+ edge live_edge;
/* Look for a simple register copy. */
set = single_set (insn);
@@ -191,10 +196,24 @@ move_insn_for_shrink_wrap (basic_block bb, rtx insn,
return false;
/* See whether there is a successor block to which we could move INSN. */
- next_block = next_block_for_reg (bb, dregno, end_dregno);
- if (!next_block)
+ live_edge = live_edge_for_reg (bb, dregno, end_dregno);
+ if (!live_edge)
return false;
+ next_block = live_edge->dest;
+ /* Create a new basic block on the edge. */
+ if (EDGE_COUNT (next_block->preds) == 2)
+ {
+ next_block = split_edge (live_edge);
+
+ bitmap_copy (df_get_live_in (next_block), df_get_live_out (bb));
+ df_set_bb_dirty (next_block);
+
+ /* We should not split more than once for a function. */
+ gcc_assert (!(*split_p));
+ *split_p = true;
+ }
+
/* At this point we are committed to moving INSN, but let's try to
move it as far as we can. */
do
@@ -212,7 +231,9 @@ move_insn_for_shrink_wrap (basic_block bb, rtx insn,
{
for (i = dregno; i < end_dregno; i++)
{
- if (REGNO_REG_SET_P (bb_uses, i) || REGNO_REG_SET_P (bb_defs, i)
+ if (*split_p
+ || REGNO_REG_SET_P (bb_uses, i)
+ || REGNO_REG_SET_P (bb_defs, i)
|| REGNO_REG_SET_P (&DF_LIVE_BB_INFO (bb)->gen, i))
next_block = NULL;
CLEAR_REGNO_REG_SET (live_out, i);
@@ -223,7 +244,8 @@ move_insn_for_shrink_wrap (basic_block bb, rtx insn,
Either way, SRC is now live on entry. */
for (i = sregno; i < end_sregno; i++)
{
- if (REGNO_REG_SET_P (bb_defs, i)
+ if (*split_p
+ || REGNO_REG_SET_P (bb_defs, i)
|| REGNO_REG_SET_P (&DF_LIVE_BB_INFO (bb)->gen, i))
next_block = NULL;
SET_REGNO_REG_SET (live_out, i);
@@ -252,21 +274,31 @@ move_insn_for_shrink_wrap (basic_block bb, rtx insn,
/* If we don't need to add the move to BB, look for a single
successor block. */
if (next_block)
- next_block = next_block_for_reg (next_block, dregno, end_dregno);
+ {
+ live_edge = live_edge_for_reg (next_block, dregno, end_dregno);
+ if (!live_edge || EDGE_COUNT (live_edge->dest->preds) > 1)
+ break;
+ next_block = live_edge->dest;
+ }
}
while (next_block);
- /* BB now defines DEST. It only uses the parts of DEST that overlap SRC
- (next loop). */
- for (i = dregno; i < end_dregno; i++)
+ /* For the new created basic block, there is no dataflow info at all.
+ So skip the following dataflow update and check. */
+ if (!(*split_p))
{
- CLEAR_REGNO_REG_SET (bb_uses, i);
- SET_REGNO_REG_SET (bb_defs, i);
- }
+ /* BB now defines DEST. It only uses the parts of DEST that overlap SRC
+ (next loop). */
+ for (i = dregno; i < end_dregno; i++)
+ {
+ CLEAR_REGNO_REG_SET (bb_uses, i);
+ SET_REGNO_REG_SET (bb_defs, i);
+ }
- /* BB now uses SRC. */
- for (i = sregno; i < end_sregno; i++)
- SET_REGNO_REG_SET (bb_uses, i);
+ /* BB now uses SRC. */
+ for (i = sregno; i < end_sregno; i++)
+ SET_REGNO_REG_SET (bb_uses, i);
+ }
emit_insn_after (PATTERN (insn), bb_note (bb));
delete_insn (insn);
@@ -286,12 +318,14 @@ prepare_shrink_wrap (basic_block entry_block)
rtx insn, curr, x;
HARD_REG_SET uses, defs;
df_ref *ref;
+ bool split_p = false;
CLEAR_HARD_REG_SET (uses);
CLEAR_HARD_REG_SET (defs);
FOR_BB_INSNS_REVERSE_SAFE (entry_block, insn, curr)
if (NONDEBUG_INSN_P (insn)
- && !move_insn_for_shrink_wrap (entry_block, insn, uses, defs))
+ && !move_insn_for_shrink_wrap (entry_block, insn, uses, defs,
+ &split_p))
{
/* Add all defined registers to DEFs. */
for (ref = DF_INSN_DEFS (insn); *ref; ref++)
diff --git a/gcc/shrink-wrap.h b/gcc/shrink-wrap.h
index 22b1d5c..bccfb31 100644
--- a/gcc/shrink-wrap.h
+++ b/gcc/shrink-wrap.h
@@ -1,4 +1,4 @@
-/* Structure for saving state for a nested function.
+/* Shrink-wrapping related functions.
Copyright (C) 1989-2014 Free Software Foundation, Inc.
This file is part of GCC.