• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_shader.h"
25 
26 using namespace brw;
27 
28 /** @file brw_predicated_break.cpp
29  *
30  * Loops are often structured as
31  *
32  * loop:
33  *    CMP.f0
34  *    (+f0) IF
35  *    BREAK
36  *    ENDIF
37  *    ...
38  *    WHILE loop
39  *
40  * This peephole pass removes the IF and ENDIF instructions and predicates the
41  * BREAK, dropping two instructions from the loop body.
42  *
43  * If the loop was a DO { ... } WHILE loop, it looks like
44  *
45  * loop:
46  *    ...
47  *    CMP.f0
48  *    (+f0) IF
49  *    BREAK
50  *    ENDIF
51  *    WHILE loop
52  *
53  * and we can remove the BREAK instruction and predicate the WHILE.
54  */
55 
56 bool
opt_predicated_break(backend_shader * s)57 opt_predicated_break(backend_shader *s)
58 {
59    bool progress = false;
60 
61    foreach_block (block, s->cfg) {
62       if (block->start_ip != block->end_ip)
63          continue;
64 
65       /* BREAK and CONTINUE instructions, by definition, can only be found at
66        * the ends of basic blocks.
67        */
68       backend_instruction *jump_inst = block->end();
69       if (jump_inst->opcode != BRW_OPCODE_BREAK &&
70           jump_inst->opcode != BRW_OPCODE_CONTINUE)
71          continue;
72 
73       backend_instruction *if_inst = block->prev()->end();
74       if (if_inst->opcode != BRW_OPCODE_IF)
75          continue;
76 
77       backend_instruction *endif_inst = block->next()->start();
78       if (endif_inst->opcode != BRW_OPCODE_ENDIF)
79          continue;
80 
81       bblock_t *jump_block = block;
82       bblock_t *if_block = jump_block->prev();
83       bblock_t *endif_block = jump_block->next();
84 
85       jump_inst->predicate = if_inst->predicate;
86       jump_inst->predicate_inverse = if_inst->predicate_inverse;
87 
88       bblock_t *earlier_block = if_block;
89       if (if_block->start_ip == if_block->end_ip) {
90          earlier_block = if_block->prev();
91       }
92 
93       if_inst->remove(if_block);
94 
95       bblock_t *later_block = endif_block;
96       if (endif_block->start_ip == endif_block->end_ip) {
97          later_block = endif_block->next();
98       }
99       endif_inst->remove(endif_block);
100 
101       if (!earlier_block->ends_with_control_flow()) {
102          earlier_block->children.make_empty();
103          earlier_block->add_successor(s->cfg->mem_ctx, jump_block,
104                                       bblock_link_logical);
105       }
106 
107       if (!later_block->starts_with_control_flow()) {
108          later_block->parents.make_empty();
109       }
110       jump_block->add_successor(s->cfg->mem_ctx, later_block,
111                                 bblock_link_logical);
112 
113       if (earlier_block->can_combine_with(jump_block)) {
114          earlier_block->combine_with(jump_block);
115 
116          block = earlier_block;
117       }
118 
119       /* Now look at the first instruction of the block following the BREAK. If
120        * it's a WHILE, we can delete the break, predicate the WHILE, and join
121        * the two basic blocks.
122        */
123       bblock_t *while_block = earlier_block->next();
124       backend_instruction *while_inst = while_block->start();
125 
126       if (jump_inst->opcode == BRW_OPCODE_BREAK &&
127           while_inst->opcode == BRW_OPCODE_WHILE &&
128           while_inst->predicate == BRW_PREDICATE_NONE) {
129          jump_inst->remove(earlier_block);
130          while_inst->predicate = jump_inst->predicate;
131          while_inst->predicate_inverse = !jump_inst->predicate_inverse;
132 
133          assert(earlier_block->can_combine_with(while_block));
134          earlier_block->combine_with(while_block);
135       }
136 
137       progress = true;
138    }
139 
140    if (progress)
141       s->invalidate_analysis(DEPENDENCY_BLOCKS | DEPENDENCY_INSTRUCTIONS);
142 
143    return progress;
144 }
145