[PATCH, 2/2] shrink wrap a function with a single loop: split live_edge
Zhenqiang Chen
zhenqiang.chen@arm.com
Tue Sep 16 06:55:00 GMT 2014
> -----Original Message-----
> From: gcc-patches-owner@gcc.gnu.org [mailto:gcc-patches-
> owner@gcc.gnu.org] On Behalf Of Jiong Wang
> Sent: Monday, September 15, 2014 11:28 PM
> To: Zhenqiang Chen
> Cc: gcc-patches@gcc.gnu.org; Jeff Law
> Subject: Re: [PATCH, 2/2] shrink wrap a function with a single loop: split
> live_edge
>
> On 08/05/14 09:07, Zhenqiang Chen wrote:
> > static bool
> > move_insn_for_shrink_wrap (basic_block bb, rtx insn,
> > const HARD_REG_SET uses,
> > const HARD_REG_SET defs,
> > - HARD_REG_SET *last_uses)
> > + HARD_REG_SET *last_uses,
> > + 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);
> > @@ -5582,17 +5589,31 @@ move_insn_for_shrink_wrap (basic_block bb,
> rtx insn,
> > || overlaps_hard_reg_set_p (defs, GET_MODE (dest), dregno))
> > 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 = next_block_for_reg (bb, dregno, end_dregno); if
> > + (!live_edge)
> > return false;
> >
> > + next_block = live_edge->dest;
> > +
> > /* If the destination register is referred in later insn,
> > try to forward it. */
> > if (overlaps_hard_reg_set_p (*last_uses, GET_MODE (dest), dregno)
> > && !try_copy_prop (bb, insn, src, dest, last_uses))
> > return false;
> >
> > + /* 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));
>
> (re-sent, looks like the first send not received by the server...)
>
> for the function "_IO_wdefault_xsputn" in glibc wgenops.c (.dot file
> attached)
>
> 174: NOTE_INSN_BASIC_BLOCK 21 are the new created basic block because
> of the sink of move instruction "ax:DI = 0" and split edge.
>
> but the live_in of this BB is copied from live_out of BB 2 which is too big, and
> actually prevent the later sink of "16: r12:DI=dx:DI".
>
> Should it be better to copy live_in from "next_block->next_bb" instead of
> live_out from "bb", as it will model what's needed more accurately?
According to the algorithm, next_block->next_bb (which is live_edge->dest) should have two predecessors. Live_in of next_block->next_bb would include live_out of the other edge, which is not necessary accurately. To be more accurate, you may need an intersection of df_get_live_out (bb) and df_get_live_in (next_block->next_bb).
Thanks!
-Zhenqiang
> + bitmap_copy (df_get_live_in (next_block), df_get_live_in
> + (next_block->next_bb));
>
> After this modification, pass x86-64 bootstrap, and this function could be
> shrink-wrapped.
>
> -- Jiong
>
> > + 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
> > @@ -5610,7 +5631,10 @@ 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); @@ -5621,7 +5645,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); @@ -5650,21 +5675,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 = next_block_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);
> > @@ -5684,6 +5719,7 @@ prepare_shrink_wrap (basic_block entry_block)
> > rtx insn, curr, x;
> > HARD_REG_SET uses, defs, last_uses;
> > df_ref *ref;
> > + bool split_p = false;
> >
> > if (!JUMP_P (BB_END (entry_block)))
> > return;
> > @@ -5693,7 +5729,7 @@ prepare_shrink_wrap (basic_block entry_block)
> > FOR_BB_INSNS_REVERSE_SAFE (entry_block, insn, curr)
> > if (NONDEBUG_INSN_P (insn)
> > && !move_insn_for_shrink_wrap (entry_block, insn, uses, defs,
> > - &last_uses))
> > + &last_uses, &split_p))
> > {
> > /* Add all defined registers to DEFs. */
> > for (ref = DF_INSN_DEFS (insn); *ref; ref++)
> >
More information about the Gcc-patches
mailing list