Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / glsl / opt_discard_simplification.cpp
1 /*
2  * Copyright © 2010 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
21  * DEALINGS IN THE SOFTWARE.
22  */
23
24 /**
25  * \file opt_discard_simplification.cpp
26  *
27  * This pass simplifies if-statements and loops containing unconditional
28  * discards.
29  *
30  * Case 1: Both branches contain unconditional discards:
31  * -----------------------------------------------------
32  *
33  *    if (cond) {
34  *       s1;
35  *       discard;
36  *       s2;
37  *    } else {
38  *       s3;
39  *       discard;
40  *       s4;
41  *    }
42  *
43  * becomes:
44  *
45  *    discard
46  *
47  * Case 2: The "then" clause contains an unconditional discard:
48  * ------------------------------------------------------------
49  *
50  *    if (cond) {
51  *       s1;
52  *       discard;
53  *       s2;
54  *    } else {
55  *       s3;
56  *    }
57  *
58  * becomes:
59  *
60  *    if (cond) {
61  *       discard;
62  *    } else {
63  *       s3;
64  *    }
65  *
66  * Case 3: The "else" clause contains an unconditional discard:
67  * ------------------------------------------------------------
68  *
69  *    if (cond) {
70  *       s1;
71  *    } else {
72  *       s2;
73  *       discard;
74  *       s3;
75  *    }
76  *
77  * becomes:
78  *
79  *    if (cond) {
80  *       s1;
81  *    } else {
82  *       discard;
83  *    }
84  */
85
86 #include "glsl_types.h"
87 #include "ir.h"
88
89 class discard_simplifier : public ir_hierarchical_visitor {
90 public:
91    discard_simplifier()
92    {
93       this->progress = false;
94    }
95
96    ir_visitor_status visit_enter(ir_if *);
97    ir_visitor_status visit_enter(ir_loop *);
98    ir_visitor_status visit_enter(ir_assignment *);
99
100    bool progress;
101 };
102
103 static ir_discard *
104 find_unconditional_discard(exec_list &instructions)
105 {
106    foreach_list(n, &instructions) {
107       ir_instruction *ir = (ir_instruction *)n;
108
109       if (ir->ir_type == ir_type_return ||
110           ir->ir_type == ir_type_loop_jump)
111          return NULL;
112
113       /* So far, this code doesn't know how to look inside of flow
114        * control to see if a discard later on at this level is
115        * unconditional.
116        */
117       if (ir->ir_type == ir_type_if ||
118           ir->ir_type == ir_type_loop)
119          return NULL;
120
121       ir_discard *discard = ir->as_discard();
122       if (discard != NULL && discard->condition == NULL)
123          return discard;
124    }
125    return NULL;
126 }
127
128 static bool
129 is_only_instruction(ir_discard *discard)
130 {
131    return (discard->prev->is_head_sentinel() &&
132            discard->next->is_tail_sentinel());
133 }
134
135 /* We only care about the top level instructions, so don't descend
136  * into expressions.
137  */
138 ir_visitor_status
139 discard_simplifier::visit_enter(ir_assignment *ir)
140 {
141    return visit_continue_with_parent;
142 }
143
144 ir_visitor_status
145 discard_simplifier::visit_enter(ir_if *ir)
146 {
147    ir_discard *then_discard = find_unconditional_discard(ir->then_instructions);
148    ir_discard *else_discard = find_unconditional_discard(ir->else_instructions);
149
150    if (then_discard == NULL && else_discard == NULL)
151       return visit_continue;
152
153    /* If both branches result in discard, replace whole if with discard. */
154    if (then_discard != NULL && else_discard != NULL) {
155       this->progress = true;
156       ir->replace_with(then_discard);
157       return visit_continue_with_parent;
158    }
159
160    /* Otherwise, one branch has a discard. */
161    if (then_discard != NULL && !is_only_instruction(then_discard)) {
162       this->progress = true;
163       ir->then_instructions.make_empty();
164       ir->then_instructions.push_tail(then_discard);
165    } else if (else_discard != NULL && !is_only_instruction(else_discard)) {
166       this->progress = true;
167       ir->else_instructions.make_empty();
168       ir->else_instructions.push_tail(else_discard);
169    }
170
171    visit_list_elements(this, &ir->then_instructions);
172    return visit_continue_with_parent;
173 }
174
175 ir_visitor_status
176 discard_simplifier::visit_enter(ir_loop *ir)
177 {
178    ir_discard *discard = find_unconditional_discard(ir->body_instructions);
179
180    if (discard) {
181       ir->replace_with(discard);
182       return visit_continue_with_parent;
183    }
184
185    return visit_continue;
186 }
187
188 bool
189 do_discard_simplification(exec_list *instructions)
190 {
191    /* Look for a top-level unconditional discard */
192    ir_discard *discard = find_unconditional_discard(*instructions);
193    if (discard != NULL) {
194       instructions->make_empty();
195       instructions->push_tail(discard);
196       return true;
197    }
198
199    discard_simplifier v;
200
201    visit_list_elements(&v, instructions);
202
203    return v.progress;
204 }