[Mesa-dev] [PATCH 17/20] i965: Preserve CFG when deleting dead control flow.

Pohjolainen, Topi topi.pohjolainen at intel.com
Tue Aug 19 12:36:54 PDT 2014


On Tue, Aug 19, 2014 at 12:03:01PM -0700, Matt Turner wrote:
> On Tue, Aug 19, 2014 at 12:49 AM, Pohjolainen, Topi
> <topi.pohjolainen at intel.com> wrote:
> > On Thu, Jul 24, 2014 at 07:54:24PM -0700, Matt Turner wrote:
> >> This pass deletes an IF/ELSE/ENDIF or IF/ENDIF sequence, or the ELSE in
> >> an ELSE/ENDIF sequence.
> >>
> >> In the typical case (where IF and ENDIF) aren't the only instructions in
> >> their basic blocks, we can simply remove the instructions (implicitly
> >> deleting the block containing only the ELSE), and attempt to merge
> >> blocks B0 and B2 together.
> >>
> >> B0: ...
> >>     (+f0) if(8)
> >> B1: else(8)
> >> B2: endif(8)
> >>     ...
> >>
> >> If the IF or ENDIF instructions are the only instructions in their
> >> respective basic blocks (which are deleted by the removal of the
> >> instructions), we'll want to instead merge the next blocks.
> >>
> >> Both B0 and B2 are possibly removed by the removal of if & endif.
> >> Same situation for if/endif. E.g., in the following example we'd remove
> >> blocks B1 and B2, and then attempt to combine B0 and B3.
> >>
> >> B0: ...
> >> B1: (+f0) if(8)
> >> B2: endif(8)
> >> B3: ...
> >> ---
> >>  .../drivers/dri/i965/brw_dead_control_flow.cpp     | 44 ++++++++++++++++++----
> >>  1 file changed, 36 insertions(+), 8 deletions(-)
> >>
> >> diff --git a/src/mesa/drivers/dri/i965/brw_dead_control_flow.cpp b/src/mesa/drivers/dri/i965/brw_dead_control_flow.cpp
> >> index e6ace5c..56dc79e 100644
> >> --- a/src/mesa/drivers/dri/i965/brw_dead_control_flow.cpp
> >> +++ b/src/mesa/drivers/dri/i965/brw_dead_control_flow.cpp
> >> @@ -42,7 +42,8 @@ dead_control_flow_eliminate(backend_visitor *v)
> >>
> >>     v->calculate_cfg();
> >>
> >> -   foreach_block (block, v->cfg) {
> >> +   foreach_block_safe (block, v->cfg) {
> >> +      bblock_t *if_block = NULL, *else_block = NULL, *endif_block = block;
> >>        bool found = false;
> >>
> >>        /* ENDIF instructions, by definition, can only be found at the start of
> >> @@ -56,6 +57,7 @@ dead_control_flow_eliminate(backend_visitor *v)
> >>        backend_instruction *prev_inst = (backend_instruction *) endif_inst->prev;
> >>        if (prev_inst->opcode == BRW_OPCODE_ELSE) {
> >>           else_inst = prev_inst;
> >> +         else_block = (bblock_t *)endif_block->link.prev;
> >>           found = true;
> >>
> >>           prev_inst = (backend_instruction *) prev_inst->prev;
> >> @@ -63,6 +65,8 @@ dead_control_flow_eliminate(backend_visitor *v)
> >>
> >>        if (prev_inst->opcode == BRW_OPCODE_IF) {
> >>           if_inst = prev_inst;
> >> +         if_block = else_block != NULL ? (bblock_t *)else_block->link.prev
> >> +                                       : (bblock_t *)endif_block->link.prev;
> >>           found = true;
> >>        } else {
> >>           /* Don't remove the ENDIF if we didn't find a dead IF. */
> >> @@ -70,18 +74,42 @@ dead_control_flow_eliminate(backend_visitor *v)
> >>        }
> >>
> >>        if (found) {
> >> -         if (if_inst)
> >> -            if_inst->remove();
> >> -         if (else_inst)
> >> -            else_inst->remove();
> >> -         if (endif_inst)
> >> -            endif_inst->remove();
> >> +         bblock_t *earlier_block = NULL, *later_block = NULL;
> >> +
> >> +         if (if_inst) {
> >> +            if (if_block->start_ip == if_block->end_ip) {
> >> +               earlier_block = (bblock_t *)if_block->link.prev;
> >> +            } else {
> >> +               earlier_block = if_block;
> >> +            }
> >> +            if_inst->remove(if_block);
> >> +         }
> >> +
> >> +         if (else_inst) {
> >> +            else_block->if_block->else_block = NULL;
> >> +            else_inst->remove(else_block);
> >> +         }
> >> +
> >> +         if (endif_inst) {
> >> +            if (endif_block->start_ip == endif_block->end_ip) {
> >> +               later_block = (bblock_t *)endif_block->link.next;
> >> +            } else {
> >> +               later_block = endif_block;
> >> +            }
> >> +            endif_inst->remove(endif_block);
> >> +         }
> >> +
> >> +         assert((earlier_block == NULL) == (later_block == NULL));
> >> +         if (earlier_block && earlier_block->can_combine_with(later_block)) {
> >> +            earlier_block->combine_with(later_block);
> >
> > Now that we are using foreach_block_safe(), isn't next pointing to later_block
> > which gets removed here when its merged into earlier_block? I could be missing
> > something as I had some difficulty with the documentation in the previous
> > patch.
> 
> Good find. You're exactly right. Take this for example:
> 
>     B0: ...
>         (+f0) if(8)
>     B1: endif(8)            <- block
>     B2: ...                 <- next
> 
> After deleting if/endif (and therefore the endif block B1)
> 
>     B0: ...
>     B2: ...                 <- next
>                             <- block points to dead block
> 
> After combining B0 and B2:
> 
>     B0: ...
>                             <- next points to dead block
>                             <- block points to dead block
> 
> I'll add this:
> 
>    /* If ENDIF was in its own block, then we've now deleted it and
>     * merged the two surrounding blocks, the latter of which the
>     * __next block pointer was pointing to.
>     */
>    if (endif_block != later_block) {
>       __next = (bblock_t *)earlier_block->link.next;
>    }
> 
> immediately after earlier_block->combine_with(later_block).
> 
> By the way, I committed the first 6 patches of the series (the one
> touching the generators had started to rot). I think other than 16 and
> 17, the only ones missing review are the patches that add the
> insertion and removal methods. I sent new versions of them based on
> your feedback a few days ago.

Oh, so sorry Matt, I somehow forgot to send my r-b, they are just fine.



More information about the mesa-dev mailing list