i965/fs: New peephole optimization to flatten IF/BREAK/ENDIF.
[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 cfg_t cfg(&instructions);
49
50 for (int b = 0; b < cfg.num_blocks; b++) {
51 bblock_t *block = cfg.blocks[b];
52
53 /* BREAK and CONTINUE instructions, by definition, can only be found at
54 * the ends of basic blocks.
55 */
56 fs_inst *inst = (fs_inst *) block->end;
57 if (inst->opcode != BRW_OPCODE_BREAK && inst->opcode != BRW_OPCODE_CONTINUE)
58 continue;
59
60 fs_inst *if_inst = (fs_inst *) inst->prev;
61 if (if_inst->opcode != BRW_OPCODE_IF)
62 continue;
63
64 fs_inst *endif_inst = (fs_inst *) inst->next;
65 if (endif_inst->opcode != BRW_OPCODE_ENDIF)
66 continue;
67
68 /* For Sandybridge with IF with embedded comparison we need to emit an
69 * instruction to set the flag register.
70 */
71 if (brw->gen == 6 && if_inst->conditional_mod) {
72 fs_inst *cmp_inst = CMP(reg_null_d, if_inst->src[0], if_inst->src[1],
73 if_inst->conditional_mod);
74 if_inst->insert_before(cmp_inst);
75 inst->predicate = BRW_PREDICATE_NORMAL;
76 } else {
77 inst->predicate = if_inst->predicate;
78 inst->predicate_inverse = if_inst->predicate_inverse;
79 }
80
81 if_inst->remove();
82 endif_inst->remove();
83
84 /* By removing the ENDIF instruction we removed a basic block. Skip over
85 * it for the next iteration.
86 */
87 b++;
88
89 progress = true;
90 }
91
92 if (progress)
93 invalidate_live_intervals();
94
95 return progress;
96 }