2 * Copyright © 2013 Intel Corporation
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:
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
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
28 /** @file brw_predicated_break.cpp
30 * Loops are often structured as
40 * This peephole pass removes the IF and ENDIF instructions and predicates the
41 * BREAK, dropping two instructions from the loop body.
43 * If the loop was a DO { ... } WHILE loop, it looks like
53 * and we can remove the BREAK instruction and predicate the WHILE.
57 opt_predicated_break(backend_shader
*s
)
59 bool progress
= false;
61 foreach_block (block
, s
->cfg
) {
62 if (block
->start_ip
!= block
->end_ip
)
65 /* BREAK and CONTINUE instructions, by definition, can only be found at
66 * the ends of basic blocks.
68 backend_instruction
*jump_inst
= block
->end();
69 if (jump_inst
->opcode
!= BRW_OPCODE_BREAK
&&
70 jump_inst
->opcode
!= BRW_OPCODE_CONTINUE
)
73 backend_instruction
*if_inst
= block
->prev()->end();
74 if (if_inst
->opcode
!= BRW_OPCODE_IF
)
77 backend_instruction
*endif_inst
= block
->next()->start();
78 if (endif_inst
->opcode
!= BRW_OPCODE_ENDIF
)
81 bblock_t
*jump_block
= block
;
82 bblock_t
*if_block
= jump_block
->prev();
83 bblock_t
*endif_block
= jump_block
->next();
85 jump_inst
->predicate
= if_inst
->predicate
;
86 jump_inst
->predicate_inverse
= if_inst
->predicate_inverse
;
88 bblock_t
*earlier_block
= if_block
;
89 if (if_block
->start_ip
== if_block
->end_ip
) {
90 earlier_block
= if_block
->prev();
93 if_inst
->remove(if_block
);
95 bblock_t
*later_block
= endif_block
;
96 if (endif_block
->start_ip
== endif_block
->end_ip
) {
97 later_block
= endif_block
->next();
99 endif_inst
->remove(endif_block
);
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
);
106 if (!later_block
->starts_with_control_flow()) {
107 later_block
->parents
.make_empty();
109 jump_block
->add_successor(s
->cfg
->mem_ctx
, later_block
);
111 if (earlier_block
->can_combine_with(jump_block
)) {
112 earlier_block
->combine_with(jump_block
);
114 block
= earlier_block
;
117 /* Now look at the first instruction of the block following the BREAK. If
118 * it's a WHILE, we can delete the break, predicate the WHILE, and join
119 * the two basic blocks.
121 bblock_t
*while_block
= earlier_block
->next();
122 backend_instruction
*while_inst
= while_block
->start();
124 if (jump_inst
->opcode
== BRW_OPCODE_BREAK
&&
125 while_inst
->opcode
== BRW_OPCODE_WHILE
&&
126 while_inst
->predicate
== BRW_PREDICATE_NONE
) {
127 jump_inst
->remove(earlier_block
);
128 while_inst
->predicate
= jump_inst
->predicate
;
129 while_inst
->predicate_inverse
= !jump_inst
->predicate_inverse
;
131 earlier_block
->children
.make_empty();
132 earlier_block
->add_successor(s
->cfg
->mem_ctx
, while_block
);
134 assert(earlier_block
->can_combine_with(while_block
));
135 earlier_block
->combine_with(while_block
);
137 earlier_block
->next()->parents
.make_empty();
138 earlier_block
->add_successor(s
->cfg
->mem_ctx
, earlier_block
->next());
145 s
->invalidate_live_intervals();