5b4cab5390209d8a09a39a6e6d81e0c394bd6616
[mesa.git] / src / mesa / drivers / dri / i965 / brw_fs_peephole_predicated_break.cpp
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_fs.h"
25 #include "brw_cfg.h"
26
27 /** @file brw_fs_peephole_predicated_break.cpp
28 *
29 * Loops are often structured as
30 *
31 * loop:
32 * CMP.f0
33 * (+f0) IF
34 * BREAK
35 * ENDIF
36 * ...
37 * WHILE loop
38 *
39 * This peephole pass removes the IF and ENDIF instructions and predicates the
40 * BREAK, dropping two instructions from the loop body.
41 */
42
43 bool
44 fs_visitor::opt_peephole_predicated_break()
45 {
46 bool progress = false;
47
48 foreach_block (block, cfg) {
49 if (block->start_ip != block->end_ip)
50 continue;
51
52 /* BREAK and CONTINUE instructions, by definition, can only be found at
53 * the ends of basic blocks.
54 */
55 fs_inst *jump_inst = (fs_inst *)block->end;
56 if (jump_inst->opcode != BRW_OPCODE_BREAK &&
57 jump_inst->opcode != BRW_OPCODE_CONTINUE)
58 continue;
59
60 fs_inst *if_inst = (fs_inst *)((bblock_t *)block->link.prev)->end;
61 if (if_inst->opcode != BRW_OPCODE_IF)
62 continue;
63
64 fs_inst *endif_inst = (fs_inst *)((bblock_t *)block->link.next)->start;
65 if (endif_inst->opcode != BRW_OPCODE_ENDIF)
66 continue;
67
68 bblock_t *jump_block = block;
69 bblock_t *if_block = (bblock_t *)jump_block->link.prev;
70 bblock_t *endif_block = (bblock_t *)jump_block->link.next;
71
72 /* For Sandybridge with IF with embedded comparison we need to emit an
73 * instruction to set the flag register.
74 */
75 if (brw->gen == 6 && if_inst->conditional_mod) {
76 fs_inst *cmp_inst = CMP(reg_null_d, if_inst->src[0], if_inst->src[1],
77 if_inst->conditional_mod);
78 if_inst->insert_before(if_block, cmp_inst);
79 jump_inst->predicate = BRW_PREDICATE_NORMAL;
80 } else {
81 jump_inst->predicate = if_inst->predicate;
82 jump_inst->predicate_inverse = if_inst->predicate_inverse;
83 }
84
85 bblock_t *earlier_block = if_block;
86 if (if_block->start_ip == if_block->end_ip) {
87 earlier_block = (bblock_t *)if_block->link.prev;
88 }
89
90 if_inst->remove(if_block);
91
92 bblock_t *later_block = endif_block;
93 if (endif_block->start_ip == endif_block->end_ip) {
94 later_block = (bblock_t *)endif_block->link.next;
95 }
96 endif_inst->remove(endif_block);
97
98 earlier_block->children.make_empty();
99 later_block->parents.make_empty();
100
101 earlier_block->add_successor(cfg->mem_ctx, jump_block);
102 jump_block->add_successor(cfg->mem_ctx, later_block);
103
104 if (earlier_block->can_combine_with(jump_block)) {
105 earlier_block->combine_with(jump_block);
106
107 block = earlier_block;
108 }
109
110 progress = true;
111 }
112
113 if (progress)
114 invalidate_live_intervals();
115
116 return progress;
117 }