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
29 /** @file brw_fs_peephole_predicated_break.cpp
31 * Loops are often structured as
41 * This peephole pass removes the IF and ENDIF instructions and predicates the
42 * BREAK, dropping two instructions from the loop body.
44 * If the loop was a DO { ... } WHILE loop, it looks like
54 * and we can remove the BREAK instruction and predicate the WHILE.
58 fs_visitor::opt_peephole_predicated_break()
60 bool progress
= false;
62 foreach_block (block
, cfg
) {
63 if (block
->start_ip
!= block
->end_ip
)
66 /* BREAK and CONTINUE instructions, by definition, can only be found at
67 * the ends of basic blocks.
69 fs_inst
*jump_inst
= (fs_inst
*)block
->end();
70 if (jump_inst
->opcode
!= BRW_OPCODE_BREAK
&&
71 jump_inst
->opcode
!= BRW_OPCODE_CONTINUE
)
74 fs_inst
*if_inst
= (fs_inst
*)block
->prev()->end();
75 if (if_inst
->opcode
!= BRW_OPCODE_IF
)
78 fs_inst
*endif_inst
= (fs_inst
*)block
->next()->start();
79 if (endif_inst
->opcode
!= BRW_OPCODE_ENDIF
)
82 bblock_t
*jump_block
= block
;
83 bblock_t
*if_block
= jump_block
->prev();
84 bblock_t
*endif_block
= jump_block
->next();
86 /* For Sandybridge with IF with embedded comparison we need to emit an
87 * instruction to set the flag register.
89 if (devinfo
->gen
== 6 && if_inst
->conditional_mod
) {
90 const fs_builder
ibld(this, if_block
, if_inst
);
91 ibld
.CMP(ibld
.null_reg_d(), if_inst
->src
[0], if_inst
->src
[1],
92 if_inst
->conditional_mod
);
93 jump_inst
->predicate
= BRW_PREDICATE_NORMAL
;
95 jump_inst
->predicate
= if_inst
->predicate
;
96 jump_inst
->predicate_inverse
= if_inst
->predicate_inverse
;
99 bblock_t
*earlier_block
= if_block
;
100 if (if_block
->start_ip
== if_block
->end_ip
) {
101 earlier_block
= if_block
->prev();
104 if_inst
->remove(if_block
);
106 bblock_t
*later_block
= endif_block
;
107 if (endif_block
->start_ip
== endif_block
->end_ip
) {
108 later_block
= endif_block
->next();
110 endif_inst
->remove(endif_block
);
112 if (!earlier_block
->ends_with_control_flow()) {
113 earlier_block
->children
.make_empty();
114 earlier_block
->add_successor(cfg
->mem_ctx
, jump_block
);
117 if (!later_block
->starts_with_control_flow()) {
118 later_block
->parents
.make_empty();
120 jump_block
->add_successor(cfg
->mem_ctx
, later_block
);
122 if (earlier_block
->can_combine_with(jump_block
)) {
123 earlier_block
->combine_with(jump_block
);
125 block
= earlier_block
;
128 /* Now look at the first instruction of the block following the BREAK. If
129 * it's a WHILE, we can delete the break, predicate the WHILE, and join
130 * the two basic blocks.
132 bblock_t
*while_block
= earlier_block
->next();
133 fs_inst
*while_inst
= (fs_inst
*)while_block
->start();
135 if (jump_inst
->opcode
== BRW_OPCODE_BREAK
&&
136 while_inst
->opcode
== BRW_OPCODE_WHILE
&&
137 while_inst
->predicate
== BRW_PREDICATE_NONE
) {
138 jump_inst
->remove(earlier_block
);
139 while_inst
->predicate
= jump_inst
->predicate
;
140 while_inst
->predicate_inverse
= !jump_inst
->predicate_inverse
;
142 earlier_block
->children
.make_empty();
143 earlier_block
->add_successor(cfg
->mem_ctx
, while_block
);
145 assert(earlier_block
->can_combine_with(while_block
));
146 earlier_block
->combine_with(while_block
);
148 earlier_block
->next()->parents
.make_empty();
149 earlier_block
->add_successor(cfg
->mem_ctx
, earlier_block
->next());
156 invalidate_live_intervals();