Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright © 2013 Intel Corporation
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a
  5.  * copy of this software and associated documentation files (the "Software"),
  6.  * to deal in the Software without restriction, including without limitation
  7.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8.  * and/or sell copies of the Software, and to permit persons to whom the
  9.  * Software is furnished to do so, subject to the following conditions:
  10.  *
  11.  * The above copyright notice and this permission notice (including the next
  12.  * paragraph) shall be included in all copies or substantial portions of the
  13.  * Software.
  14.  *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20.  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21.  * IN THE SOFTWARE.
  22.  */
  23.  
  24. #include "brw_fs.h"
  25. #include "brw_cfg.h"
  26.  
  27. /** @file brw_fs_peephole_predicated_break.cpp
  28.  *
  29.  * Loops are often structured as
  30.  *
  31.  * loop:
  32.  *    CMP.f0
  33.  *    (+f0) IF
  34.  *    BREAK
  35.  *    ENDIF
  36.  *    ...
  37.  *    WHILE loop
  38.  *
  39.  * This peephole pass removes the IF and ENDIF instructions and predicates the
  40.  * BREAK, dropping two instructions from the loop body.
  41.  *
  42.  * If the loop was a DO { ... } WHILE loop, it looks like
  43.  *
  44.  * loop:
  45.  *    ...
  46.  *    CMP.f0
  47.  *    (+f0) IF
  48.  *    BREAK
  49.  *    ENDIF
  50.  *    WHILE loop
  51.  *
  52.  * and we can remove the BREAK instruction and predicate the WHILE.
  53.  */
  54.  
  55. bool
  56. fs_visitor::opt_peephole_predicated_break()
  57. {
  58.    bool progress = false;
  59.  
  60.    foreach_block (block, cfg) {
  61.       if (block->start_ip != block->end_ip)
  62.          continue;
  63.  
  64.       /* BREAK and CONTINUE instructions, by definition, can only be found at
  65.        * the ends of basic blocks.
  66.        */
  67.       fs_inst *jump_inst = (fs_inst *)block->end();
  68.       if (jump_inst->opcode != BRW_OPCODE_BREAK &&
  69.           jump_inst->opcode != BRW_OPCODE_CONTINUE)
  70.          continue;
  71.  
  72.       fs_inst *if_inst = (fs_inst *)block->prev()->end();
  73.       if (if_inst->opcode != BRW_OPCODE_IF)
  74.          continue;
  75.  
  76.       fs_inst *endif_inst = (fs_inst *)block->next()->start();
  77.       if (endif_inst->opcode != BRW_OPCODE_ENDIF)
  78.          continue;
  79.  
  80.       bblock_t *jump_block = block;
  81.       bblock_t *if_block = jump_block->prev();
  82.       bblock_t *endif_block = jump_block->next();
  83.  
  84.       /* For Sandybridge with IF with embedded comparison we need to emit an
  85.        * instruction to set the flag register.
  86.        */
  87.       if (devinfo->gen == 6 && if_inst->conditional_mod) {
  88.          fs_inst *cmp_inst = CMP(reg_null_d, if_inst->src[0], if_inst->src[1],
  89.                                  if_inst->conditional_mod);
  90.          if_inst->insert_before(if_block, cmp_inst);
  91.          jump_inst->predicate = BRW_PREDICATE_NORMAL;
  92.       } else {
  93.          jump_inst->predicate = if_inst->predicate;
  94.          jump_inst->predicate_inverse = if_inst->predicate_inverse;
  95.       }
  96.  
  97.       bblock_t *earlier_block = if_block;
  98.       if (if_block->start_ip == if_block->end_ip) {
  99.          earlier_block = if_block->prev();
  100.       }
  101.  
  102.       if_inst->remove(if_block);
  103.  
  104.       bblock_t *later_block = endif_block;
  105.       if (endif_block->start_ip == endif_block->end_ip) {
  106.          later_block = endif_block->next();
  107.       }
  108.       endif_inst->remove(endif_block);
  109.  
  110.       if (!earlier_block->ends_with_control_flow()) {
  111.          earlier_block->children.make_empty();
  112.          earlier_block->add_successor(cfg->mem_ctx, jump_block);
  113.       }
  114.  
  115.       if (!later_block->starts_with_control_flow()) {
  116.          later_block->parents.make_empty();
  117.       }
  118.       jump_block->add_successor(cfg->mem_ctx, later_block);
  119.  
  120.       if (earlier_block->can_combine_with(jump_block)) {
  121.          earlier_block->combine_with(jump_block);
  122.  
  123.          block = earlier_block;
  124.       }
  125.  
  126.       /* Now look at the first instruction of the block following the BREAK. If
  127.        * it's a WHILE, we can delete the break, predicate the WHILE, and join
  128.        * the two basic blocks.
  129.        */
  130.       bblock_t *while_block = earlier_block->next();
  131.       fs_inst *while_inst = (fs_inst *)while_block->start();
  132.  
  133.       if (jump_inst->opcode == BRW_OPCODE_BREAK &&
  134.           while_inst->opcode == BRW_OPCODE_WHILE &&
  135.           while_inst->predicate == BRW_PREDICATE_NONE) {
  136.          jump_inst->remove(earlier_block);
  137.          while_inst->predicate = jump_inst->predicate;
  138.          while_inst->predicate_inverse = !jump_inst->predicate_inverse;
  139.  
  140.          earlier_block->children.make_empty();
  141.          earlier_block->add_successor(cfg->mem_ctx, while_block);
  142.  
  143.          assert(earlier_block->can_combine_with(while_block));
  144.          earlier_block->combine_with(while_block);
  145.  
  146.          earlier_block->next()->parents.make_empty();
  147.          earlier_block->add_successor(cfg->mem_ctx, earlier_block->next());
  148.       }
  149.  
  150.       progress = true;
  151.    }
  152.  
  153.    if (progress)
  154.       invalidate_live_intervals();
  155.  
  156.    return progress;
  157. }
  158.