OSDN Git Service

61f25811cb2e51baa3fb1a560183275a3a5ae5ed
[android-x86/external-mesa.git] / src / mesa / drivers / dri / i965 / brw_dead_control_flow.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 /** @file brw_dead_control_flow.cpp
25  *
26  * This file implements the dead control flow elimination optimization pass.
27  */
28
29 #include "brw_shader.h"
30 #include "brw_cfg.h"
31
32 /* Look for and eliminate dead control flow:
33  *
34  *   - if/endif
35  *   . else in else/endif
36  *   - if/else/endif
37  */
38 bool
39 dead_control_flow_eliminate(backend_shader *s)
40 {
41    bool progress = false;
42
43    foreach_block_safe (block, s->cfg) {
44       bblock_t *if_block = NULL, *else_block = NULL, *endif_block = block;
45       bool found = false;
46
47       /* ENDIF instructions, by definition, can only be found at the start of
48        * basic blocks.
49        */
50       backend_instruction *endif_inst = endif_block->start();
51       if (endif_inst->opcode != BRW_OPCODE_ENDIF)
52          continue;
53
54       backend_instruction *if_inst = NULL, *else_inst = NULL;
55       backend_instruction *prev_inst = endif_block->prev()->end();
56       if (prev_inst->opcode == BRW_OPCODE_ELSE) {
57          else_inst = prev_inst;
58          else_block = endif_block->prev();
59          found = true;
60
61          if (else_block->start_ip == else_block->end_ip)
62             prev_inst = else_block->prev()->end();
63       }
64
65       if (prev_inst->opcode == BRW_OPCODE_IF) {
66          if_inst = prev_inst;
67          if_block = else_block != NULL ? else_block->prev()
68                                        : endif_block->prev();
69          found = true;
70       } else {
71          /* Don't remove the ENDIF if we didn't find a dead IF. */
72          endif_inst = NULL;
73       }
74
75       if (found) {
76          bblock_t *earlier_block = NULL, *later_block = NULL;
77
78          if (if_inst) {
79             if (if_block->start_ip == if_block->end_ip) {
80                earlier_block = if_block->prev();
81             } else {
82                earlier_block = if_block;
83             }
84             if_inst->remove(if_block);
85          }
86
87          if (else_inst) {
88             else_inst->remove(else_block);
89          }
90
91          if (endif_inst) {
92             if (endif_block->start_ip == endif_block->end_ip) {
93                later_block = endif_block->next();
94             } else {
95                later_block = endif_block;
96             }
97             endif_inst->remove(endif_block);
98          }
99
100          assert((earlier_block == NULL) == (later_block == NULL));
101          if (earlier_block && earlier_block->can_combine_with(later_block)) {
102             earlier_block->combine_with(later_block);
103
104             /* If ENDIF was in its own block, then we've now deleted it and
105              * merged the two surrounding blocks, the latter of which the
106              * __next block pointer was pointing to.
107              */
108             if (endif_block != later_block) {
109                __next = earlier_block->next();
110             }
111          }
112
113          progress = true;
114       }
115    }
116
117    if (progress)
118       s->invalidate_live_intervals();
119
120    return progress;
121 }