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
27 /** @file brw_fs_peephole_predicated_break.cpp
29 * Loops are often structured as
39 * This peephole pass removes the IF and ENDIF instructions and predicates the
40 * BREAK, dropping two instructions from the loop body.
42 * If the loop was a DO { ... } WHILE loop, it looks like
52 * and we can remove the BREAK instruction and predicate the WHILE.
56 fs_visitor::opt_peephole_predicated_break()
58 bool progress
= false;
60 foreach_block (block
, cfg
) {
61 if (block
->start_ip
!= block
->end_ip
)
64 /* BREAK and CONTINUE instructions, by definition, can only be found at
65 * the ends of basic blocks.
67 fs_inst
*jump_inst
= (fs_inst
*)block
->end();
68 if (jump_inst
->opcode
!= BRW_OPCODE_BREAK
&&
69 jump_inst
->opcode
!= BRW_OPCODE_CONTINUE
)
72 fs_inst
*if_inst
= (fs_inst
*)block
->prev()->end();
73 if (if_inst
->opcode
!= BRW_OPCODE_IF
)
76 fs_inst
*endif_inst
= (fs_inst
*)block
->next()->start();
77 if (endif_inst
->opcode
!= BRW_OPCODE_ENDIF
)
80 bblock_t
*jump_block
= block
;
81 bblock_t
*if_block
= jump_block
->prev();
82 bblock_t
*endif_block
= jump_block
->next();
84 /* For Sandybridge with IF with embedded comparison we need to emit an
85 * instruction to set the flag register.
87 if (devinfo
->gen
== 6 && if_inst
->conditional_mod
) {
88 bld
.at(if_block
, if_inst
)
89 .CMP(bld
.null_reg_d(), if_inst
->src
[0], if_inst
->src
[1],
90 if_inst
->conditional_mod
);
91 jump_inst
->predicate
= BRW_PREDICATE_NORMAL
;
93 jump_inst
->predicate
= if_inst
->predicate
;
94 jump_inst
->predicate_inverse
= if_inst
->predicate_inverse
;
97 bblock_t
*earlier_block
= if_block
;
98 if (if_block
->start_ip
== if_block
->end_ip
) {
99 earlier_block
= if_block
->prev();
102 if_inst
->remove(if_block
);
104 bblock_t
*later_block
= endif_block
;
105 if (endif_block
->start_ip
== endif_block
->end_ip
) {
106 later_block
= endif_block
->next();
108 endif_inst
->remove(endif_block
);
110 if (!earlier_block
->ends_with_control_flow()) {
111 earlier_block
->children
.make_empty();
112 earlier_block
->add_successor(cfg
->mem_ctx
, jump_block
);
115 if (!later_block
->starts_with_control_flow()) {
116 later_block
->parents
.make_empty();
118 jump_block
->add_successor(cfg
->mem_ctx
, later_block
);
120 if (earlier_block
->can_combine_with(jump_block
)) {
121 earlier_block
->combine_with(jump_block
);
123 block
= earlier_block
;
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.
130 bblock_t
*while_block
= earlier_block
->next();
131 fs_inst
*while_inst
= (fs_inst
*)while_block
->start();
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
;
140 earlier_block
->children
.make_empty();
141 earlier_block
->add_successor(cfg
->mem_ctx
, while_block
);
143 assert(earlier_block
->can_combine_with(while_block
));
144 earlier_block
->combine_with(while_block
);
146 earlier_block
->next()->parents
.make_empty();
147 earlier_block
->add_successor(cfg
->mem_ctx
, earlier_block
->next());
154 invalidate_live_intervals();