• 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 lower_vec_index_to_cond_assign.cpp
26  *
27  * Turns indexing into vector types to a series of conditional moves
28  * of each channel's swizzle into a temporary.
29  *
30  * Most GPUs don't have a native way to do this operation, and this
31  * works around that.  For drivers using both this pass and
32  * ir_vec_index_to_swizzle, there's a risk that this pass will happen
33  * before sufficient constant folding to find that the array index is
34  * constant.  However, we hope that other optimization passes,
35  * particularly constant folding of assignment conditions and copy
36  * propagation, will result in the same code in the end.
37  */
38 
39 #include "ir.h"
40 #include "ir_visitor.h"
41 #include "ir_optimization.h"
42 #include "glsl_types.h"
43 
44 /**
45  * Visitor class for replacing expressions with ir_constant values.
46  */
47 
48 class ir_vec_index_to_cond_assign_visitor : public ir_hierarchical_visitor {
49 public:
ir_vec_index_to_cond_assign_visitor()50    ir_vec_index_to_cond_assign_visitor()
51    {
52       progress = false;
53    }
54 
55    ir_rvalue *convert_vec_index_to_cond_assign(ir_rvalue *val);
56 
57    virtual ir_visitor_status visit_enter(ir_expression *);
58    virtual ir_visitor_status visit_enter(ir_swizzle *);
59    virtual ir_visitor_status visit_leave(ir_assignment *);
60    virtual ir_visitor_status visit_enter(ir_return *);
61    virtual ir_visitor_status visit_enter(ir_call *);
62    virtual ir_visitor_status visit_enter(ir_if *);
63 
64    bool progress;
65 };
66 
67 ir_rvalue *
convert_vec_index_to_cond_assign(ir_rvalue * ir)68 ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(ir_rvalue *ir)
69 {
70    ir_dereference_array *orig_deref = ir->as_dereference_array();
71    ir_assignment *assign;
72    ir_variable *index, *var;
73    ir_dereference *deref;
74    ir_expression *condition;
75    ir_swizzle *swizzle;
76    int i;
77 
78    if (!orig_deref)
79       return ir;
80 
81    if (orig_deref->array->type->is_matrix() ||
82        orig_deref->array->type->is_array())
83       return ir;
84 
85    void *mem_ctx = hieralloc_parent(ir);
86 
87    assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);
88 
89    /* Store the index to a temporary to avoid reusing its tree. */
90    index = new(base_ir) ir_variable(glsl_type::int_type,
91 				    "vec_index_tmp_i",
92 				    ir_var_temporary);
93    base_ir->insert_before(index);
94    deref = new(base_ir) ir_dereference_variable(index);
95    assign = new(base_ir) ir_assignment(deref, orig_deref->array_index, NULL);
96    base_ir->insert_before(assign);
97 
98    /* Temporary where we store whichever value we swizzle out. */
99    var = new(base_ir) ir_variable(ir->type, "vec_index_tmp_v",
100 				  ir_var_temporary);
101    base_ir->insert_before(var);
102 
103    /* Generate a conditional move of each vector element to the temp. */
104    for (i = 0; i < orig_deref->array->type->vector_elements; i++) {
105       deref = new(base_ir) ir_dereference_variable(index);
106       condition = new(base_ir) ir_expression(ir_binop_equal,
107 					     glsl_type::bool_type,
108 					     deref,
109 					     new(base_ir) ir_constant(i));
110 
111       /* Just clone the rest of the deref chain when trying to get at the
112        * underlying variable.
113        */
114       swizzle = new(base_ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL),
115 					i, 0, 0, 0, 1);
116 
117       deref = new(base_ir) ir_dereference_variable(var);
118       assign = new(base_ir) ir_assignment(deref, swizzle, condition);
119       base_ir->insert_before(assign);
120    }
121 
122    this->progress = true;
123    return new(base_ir) ir_dereference_variable(var);
124 }
125 
126 ir_visitor_status
visit_enter(ir_expression * ir)127 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_expression *ir)
128 {
129    unsigned int i;
130 
131    for (i = 0; i < ir->get_num_operands(); i++) {
132       ir->operands[i] = convert_vec_index_to_cond_assign(ir->operands[i]);
133    }
134 
135    return visit_continue;
136 }
137 
138 ir_visitor_status
visit_enter(ir_swizzle * ir)139 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_swizzle *ir)
140 {
141    /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which
142     * the result of indexing a vector is.  But maybe at some point we'll end up
143     * using swizzling of scalars for vector construction.
144     */
145    ir->val = convert_vec_index_to_cond_assign(ir->val);
146 
147    return visit_continue;
148 }
149 
150 ir_visitor_status
visit_leave(ir_assignment * ir)151 ir_vec_index_to_cond_assign_visitor::visit_leave(ir_assignment *ir)
152 {
153    ir_variable *index, *var;
154    ir_dereference_variable *deref;
155    ir_assignment *assign;
156    int i;
157 
158    ir->rhs = convert_vec_index_to_cond_assign(ir->rhs);
159    if (ir->condition)
160       ir->condition = convert_vec_index_to_cond_assign(ir->condition);
161 
162    /* Last, handle the LHS */
163    ir_dereference_array *orig_deref = ir->lhs->as_dereference_array();
164 
165    if (!orig_deref ||
166        orig_deref->array->type->is_matrix() ||
167        orig_deref->array->type->is_array())
168       return visit_continue;
169 
170    void *mem_ctx = hieralloc_parent(ir);
171 
172    assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT);
173 
174    /* Store the index to a temporary to avoid reusing its tree. */
175    index = new(ir) ir_variable(glsl_type::int_type, "vec_index_tmp_i",
176 			       ir_var_temporary);
177    ir->insert_before(index);
178    deref = new(ir) ir_dereference_variable(index);
179    assign = new(ir) ir_assignment(deref, orig_deref->array_index, NULL);
180    ir->insert_before(assign);
181 
182    /* Store the RHS to a temporary to avoid reusing its tree. */
183    var = new(ir) ir_variable(ir->rhs->type, "vec_index_tmp_v",
184 			     ir_var_temporary);
185    ir->insert_before(var);
186    deref = new(ir) ir_dereference_variable(var);
187    assign = new(ir) ir_assignment(deref, ir->rhs, NULL);
188    ir->insert_before(assign);
189 
190    /* Generate a conditional move of each vector element to the temp. */
191    for (i = 0; i < orig_deref->array->type->vector_elements; i++) {
192       ir_rvalue *condition, *swizzle;
193 
194       deref = new(ir) ir_dereference_variable(index);
195       condition = new(ir) ir_expression(ir_binop_equal,
196 					glsl_type::bool_type,
197 					deref,
198 					new(ir) ir_constant(i));
199 
200       /* Just clone the rest of the deref chain when trying to get at the
201        * underlying variable.
202        */
203       swizzle = new(ir) ir_swizzle(orig_deref->array->clone(mem_ctx, NULL),
204 				   i, 0, 0, 0, 1);
205 
206       deref = new(ir) ir_dereference_variable(var);
207       assign = new(ir) ir_assignment(swizzle, deref, condition);
208       ir->insert_before(assign);
209    }
210    ir->remove();
211 
212    this->progress = true;
213 
214    return visit_continue;
215 }
216 
217 ir_visitor_status
visit_enter(ir_call * ir)218 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_call *ir)
219 {
220    foreach_iter(exec_list_iterator, iter, *ir) {
221       ir_rvalue *param = (ir_rvalue *)iter.get();
222       ir_rvalue *new_param = convert_vec_index_to_cond_assign(param);
223 
224       if (new_param != param) {
225 	 param->replace_with(new_param);
226       }
227    }
228 
229    return visit_continue;
230 }
231 
232 ir_visitor_status
visit_enter(ir_return * ir)233 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_return *ir)
234 {
235    if (ir->value) {
236       ir->value = convert_vec_index_to_cond_assign(ir->value);
237    }
238 
239    return visit_continue;
240 }
241 
242 ir_visitor_status
visit_enter(ir_if * ir)243 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_if *ir)
244 {
245    ir->condition = convert_vec_index_to_cond_assign(ir->condition);
246 
247    return visit_continue;
248 }
249 
250 bool
do_vec_index_to_cond_assign(exec_list * instructions)251 do_vec_index_to_cond_assign(exec_list *instructions)
252 {
253    ir_vec_index_to_cond_assign_visitor v;
254 
255    visit_list_elements(&v, instructions);
256 
257    return v.progress;
258 }
259