[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