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