[Mesa-dev] [PATCH 4/5] i965/fs: Dead code eliminate instructions writing the flag.

Kenneth Graunke kenneth at whitecape.org
Sat Nov 8 21:28:22 PST 2014


On Wednesday, October 29, 2014 02:10:12 PM Matt Turner wrote:
> Most prominently helps Natural Selection 2, which has a surprising
> number shaders that do very complicated things before drawing black.
> 
> instructions in affected programs:     23824 -> 19570 (-17.86%)
> ---
>  .../dri/i965/brw_fs_dead_code_eliminate.cpp        | 23 +++++++++++++++++++---
>  1 file changed, 20 insertions(+), 3 deletions(-)

(requoting the diff to add more context...)

> diff --git a/src/mesa/drivers/dri/i965/brw_fs_dead_code_eliminate.cpp
> b/src/mesa/drivers/dri/i965/brw_fs_dead_code_eliminate.cpp index
> 9cf8d89..c5f5ede 100644
> --- a/src/mesa/drivers/dri/i965/brw_fs_dead_code_eliminate.cpp
> +++ b/src/mesa/drivers/dri/i965/brw_fs_dead_code_eliminate.cpp
> @@ -21,93 +21,111 @@
> 
>   * IN THE SOFTWARE.
>   */
>  
>  #include "brw_fs.h"
>  #include "brw_fs_live_variables.h"
>  #include "brw_cfg.h"
>  
>  /** @file brw_fs_dead_code_eliminate.cpp
>   *
>   * Dataflow-aware dead code elimination.
>   *
>   * Walks the instruction list from the bottom, removing instructions that
>   * have results that both aren't used in later blocks and haven't been read
>   * yet in the tail end of this block.
>   */
>  
>  bool
>  fs_visitor::dead_code_eliminate()
>  {
>  
>     bool progress = false;
>     
>     calculate_live_intervals();
>     
>     int num_vars = live_intervals->num_vars;
>     BITSET_WORD *live = ralloc_array(NULL, BITSET_WORD,
>     BITSET_WORDS(num_vars));
> +   BITSET_WORD *flag_live = ralloc_array(NULL, BITSET_WORD, 1);
> 
>     foreach_block (block, cfg) {    
>        memcpy(live, live_intervals->block_data[block->num].liveout,       
>               sizeof(BITSET_WORD) * BITSET_WORDS(num_vars));
> +      memcpy(flag_live, live_intervals->block_data[block->num].flag_liveout,
> +             sizeof(BITSET_WORD));
> 
>        foreach_inst_in_block_reverse(fs_inst, inst, block) {
> -         if (inst->dst.file == GRF &&
> -             !inst->has_side_effects() &&
> -             !inst->writes_flag()) {
> +         if (inst->dst.file == GRF && !inst->has_side_effects()) {
>              bool result_live = false;

This seems wrong to me.  Instructions handled here must have a destination, but now
can also write the flag...yet...

>              if (inst->regs_written == 1) {
>                 int var = live_intervals->var_from_reg(&inst->dst);
>                 result_live = BITSET_TEST(live, var);
>              } else {
>                 int var = live_intervals->var_from_reg(&inst->dst);
>                 for (int i = 0; i < inst->regs_written; i++) {
>                    result_live = result_live || BITSET_TEST(live, var + i);
>                 }
>              }
>
>              if (!result_live) {
>                 progress = true;
>
>                 if (inst->writes_accumulator) {
>                    inst->dst = fs_reg(retype(brw_null_reg(),
>                    inst->dst.type));
>                 } else {
>                    inst->opcode = BRW_OPCODE_NOP;
>                    continue;

...here you NOP the instruction, without considering whether the flag value is live.

I think you meant to change the (inst->writes_accumulator check to be

   if (inst->writes_accumulator || inst->writes_flags())

that way, you just make the destination NULL, but leave it generating the flag register...

>                 }
>              }
>           }
> 
> +         if (inst->dst.is_null() && inst->writes_flag()) {
> +            if (!BITSET_TEST(flag_live, inst->flag_subreg)) {
> +               inst->opcode = BRW_OPCODE_NOP;
> +               progress = true;
> +               continue;
> +            }
> +         }

...which this code block would clean up, NOP'ing instructions with a NULL destination
and unused flag value.

With that fixed, it looks good to me.
Reviewed-by: Kenneth Graunke <kenneth at whitecape.org>

> +
> 
>           if (inst->dst.file == GRF) {
>              if (!inst->is_partial_write()) {
>                 int var = live_intervals->var_from_reg(&inst->dst);
>                 for (int i = 0; i < inst->regs_written; i++) {
>                    BITSET_CLEAR(live, var + i);
>                 }
>              }
>           }
> 
> +         if (inst->writes_flag()) {
> +            BITSET_CLEAR(flag_live, inst->flag_subreg);
> +         }
> +
> 
>           for (int i = 0; i < inst->sources; i++) {
>              if (inst->src[i].file == GRF) {
>                 int var = live_intervals->var_from_reg(&inst->src[i]);
>                 for (int j = 0; j < inst->regs_read(this, i); j++) {
>                    BITSET_SET(live, var + j);
>                 }
>              }
>           }
> 
> +
> +         if (inst->reads_flag()) {
> +            BITSET_SET(flag_live, inst->flag_subreg);
> +         }
>        }
>     }
>     
>     ralloc_free(live);
> +   ralloc_free(flag_live);
> 
>     if (progress) {
>        foreach_block_and_inst_safe (block, backend_instruction, inst, cfg) {
>           if (inst->opcode == BRW_OPCODE_NOP) {
>              inst->remove(block);
>           }
>        }
>        
>        invalidate_live_intervals();
>     }
>     
>     return progress;
>  }
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.freedesktop.org/archives/mesa-dev/attachments/20141108/2ac54565/attachment-0001.sig>


More information about the mesa-dev mailing list