• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
discard_simplifier()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 
99    bool progress;
100 };
101 
102 static ir_discard *
find_unconditional_discard(exec_list & instructions)103 find_unconditional_discard(exec_list &instructions)
104 {
105    foreach_list(n, &instructions) {
106       ir_discard *ir = ((ir_instruction *) n)->as_discard();
107       if (ir != NULL && ir->condition == NULL)
108 	 return ir;
109    }
110    return NULL;
111 }
112 
113 static bool
is_only_instruction(ir_discard * discard)114 is_only_instruction(ir_discard *discard)
115 {
116    return (discard->prev->is_head_sentinel() &&
117 	   discard->next->is_tail_sentinel());
118 }
119 
120 ir_visitor_status
visit_enter(ir_if * ir)121 discard_simplifier::visit_enter(ir_if *ir)
122 {
123    ir_discard *then_discard = find_unconditional_discard(ir->then_instructions);
124    ir_discard *else_discard = find_unconditional_discard(ir->else_instructions);
125 
126    if (then_discard == NULL && else_discard == NULL)
127       return visit_continue;
128 
129    /* If both branches result in discard, replace whole if with discard. */
130    if (then_discard != NULL && else_discard != NULL) {
131       this->progress = true;
132       ir->replace_with(then_discard);
133       return visit_continue_with_parent;
134    }
135 
136    /* Otherwise, one branch has a discard. */
137    if (then_discard != NULL && !is_only_instruction(then_discard)) {
138       this->progress = true;
139       ir->then_instructions.make_empty();
140       ir->then_instructions.push_tail(then_discard);
141    } else if (else_discard != NULL && !is_only_instruction(else_discard)) {
142       this->progress = true;
143       ir->else_instructions.make_empty();
144       ir->else_instructions.push_tail(else_discard);
145    }
146 
147    visit_list_elements(this, &ir->then_instructions);
148    return visit_continue_with_parent;
149 }
150 
151 ir_visitor_status
visit_enter(ir_loop * ir)152 discard_simplifier::visit_enter(ir_loop *ir)
153 {
154    ir_discard *discard = find_unconditional_discard(ir->body_instructions);
155 
156    if (discard) {
157       ir->replace_with(discard);
158       return visit_continue_with_parent;
159    }
160 
161    return visit_continue;
162 }
163 
164 bool
do_discard_simplification(exec_list * instructions)165 do_discard_simplification(exec_list *instructions)
166 {
167    /* Look for a top-level unconditional discard */
168    ir_discard *discard = find_unconditional_discard(*instructions);
169    if (discard != NULL) {
170       instructions->make_empty();
171       instructions->push_tail(discard);
172       return true;
173    }
174 
175    discard_simplifier v;
176 
177    visit_list_elements(&v, instructions);
178 
179    return v.progress;
180 }
181