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

Matt Turner mattst88 at gmail.com
Tue Aug 19 12:03:01 PDT 2014


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.


More information about the mesa-dev mailing list