• 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 "compiler/glsl_types.h"
43 
44 namespace {
45 
46 /**
47  * Visitor class for replacing expressions with ir_constant values.
48  */
49 
50 class ir_vec_index_to_cond_assign_visitor : public ir_hierarchical_visitor {
51 public:
ir_vec_index_to_cond_assign_visitor()52    ir_vec_index_to_cond_assign_visitor()
53    {
54       progress = false;
55    }
56 
57    ir_rvalue *convert_vec_index_to_cond_assign(void *mem_ctx,
58                                                ir_rvalue *orig_vector,
59                                                ir_rvalue *orig_index,
60                                                const glsl_type *type);
61 
62    ir_rvalue *convert_vector_extract_to_cond_assign(ir_rvalue *ir);
63 
64    virtual ir_visitor_status visit_enter(ir_expression *);
65    virtual ir_visitor_status visit_enter(ir_swizzle *);
66    virtual ir_visitor_status visit_leave(ir_assignment *);
67    virtual ir_visitor_status visit_enter(ir_return *);
68    virtual ir_visitor_status visit_enter(ir_call *);
69    virtual ir_visitor_status visit_enter(ir_if *);
70 
71    bool progress;
72 };
73 
74 } /* anonymous namespace */
75 
76 ir_rvalue *
convert_vec_index_to_cond_assign(void * mem_ctx,ir_rvalue * orig_vector,ir_rvalue * orig_index,const glsl_type * type)77 ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(void *mem_ctx,
78                                                                       ir_rvalue *orig_vector,
79                                                                       ir_rvalue *orig_index,
80                                                                       const glsl_type *type)
81 {
82    ir_assignment *assign, *value_assign;
83    ir_variable *index, *var, *value;
84    ir_dereference *deref, *deref_value;
85    unsigned i;
86 
87 
88    exec_list list;
89 
90    /* Store the index to a temporary to avoid reusing its tree. */
91    assert(orig_index->type == glsl_type::int_type ||
92           orig_index->type == glsl_type::uint_type);
93    index = new(base_ir) ir_variable(orig_index->type,
94 				    "vec_index_tmp_i",
95 				    ir_var_temporary);
96    list.push_tail(index);
97    deref = new(base_ir) ir_dereference_variable(index);
98    assign = new(base_ir) ir_assignment(deref, orig_index, NULL);
99    list.push_tail(assign);
100 
101    /* Store the value inside a temp, thus avoiding matrixes duplication */
102    value = new(base_ir) ir_variable(orig_vector->type, "vec_value_tmp",
103                                     ir_var_temporary);
104    list.push_tail(value);
105    deref_value = new(base_ir) ir_dereference_variable(value);
106    value_assign = new(base_ir) ir_assignment(deref_value, orig_vector);
107    list.push_tail(value_assign);
108 
109    /* Temporary where we store whichever value we swizzle out. */
110    var = new(base_ir) ir_variable(type, "vec_index_tmp_v",
111 				  ir_var_temporary);
112    list.push_tail(var);
113 
114    /* Generate a single comparison condition "mask" for all of the components
115     * in the vector.
116     */
117    ir_rvalue *const cond_deref =
118       compare_index_block(&list, index, 0,
119                           orig_vector->type->vector_elements,
120 			  mem_ctx);
121 
122    /* Generate a conditional move of each vector element to the temp. */
123    for (i = 0; i < orig_vector->type->vector_elements; i++) {
124       ir_rvalue *condition_swizzle =
125          new(base_ir) ir_swizzle(cond_deref->clone(mem_ctx, NULL),
126                                  i, 0, 0, 0, 1);
127 
128       /* Just clone the rest of the deref chain when trying to get at the
129        * underlying variable.
130        */
131       ir_rvalue *swizzle =
132 	 new(base_ir) ir_swizzle(deref_value->clone(mem_ctx, NULL),
133 				 i, 0, 0, 0, 1);
134 
135       deref = new(base_ir) ir_dereference_variable(var);
136       assign = new(base_ir) ir_assignment(deref, swizzle, condition_swizzle);
137       list.push_tail(assign);
138    }
139 
140    /* Put all of the new instructions in the IR stream before the old
141     * instruction.
142     */
143    base_ir->insert_before(&list);
144 
145    this->progress = true;
146    return new(base_ir) ir_dereference_variable(var);
147 }
148 
149 ir_rvalue *
convert_vector_extract_to_cond_assign(ir_rvalue * ir)150 ir_vec_index_to_cond_assign_visitor::convert_vector_extract_to_cond_assign(ir_rvalue *ir)
151 {
152    ir_expression *const expr = ir->as_expression();
153 
154    if (expr == NULL || expr->operation != ir_binop_vector_extract)
155       return ir;
156 
157    return convert_vec_index_to_cond_assign(ralloc_parent(ir),
158                                            expr->operands[0],
159                                            expr->operands[1],
160                                            ir->type);
161 }
162 
163 ir_visitor_status
visit_enter(ir_expression * ir)164 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_expression *ir)
165 {
166    unsigned int i;
167 
168    for (i = 0; i < ir->get_num_operands(); i++) {
169       ir->operands[i] = convert_vector_extract_to_cond_assign(ir->operands[i]);
170    }
171 
172    return visit_continue;
173 }
174 
175 ir_visitor_status
visit_enter(ir_swizzle * ir)176 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_swizzle *ir)
177 {
178    /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which
179     * the result of indexing a vector is.  But maybe at some point we'll end up
180     * using swizzling of scalars for vector construction.
181     */
182    ir->val = convert_vector_extract_to_cond_assign(ir->val);
183 
184    return visit_continue;
185 }
186 
187 ir_visitor_status
visit_leave(ir_assignment * ir)188 ir_vec_index_to_cond_assign_visitor::visit_leave(ir_assignment *ir)
189 {
190    ir->rhs = convert_vector_extract_to_cond_assign(ir->rhs);
191 
192    if (ir->condition) {
193       ir->condition = convert_vector_extract_to_cond_assign(ir->condition);
194    }
195 
196    return visit_continue;
197 }
198 
199 ir_visitor_status
visit_enter(ir_call * ir)200 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_call *ir)
201 {
202    foreach_in_list_safe(ir_rvalue, param, &ir->actual_parameters) {
203       ir_rvalue *new_param = convert_vector_extract_to_cond_assign(param);
204 
205       if (new_param != param) {
206 	 param->replace_with(new_param);
207       }
208    }
209 
210    return visit_continue;
211 }
212 
213 ir_visitor_status
visit_enter(ir_return * ir)214 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_return *ir)
215 {
216    if (ir->value) {
217       ir->value = convert_vector_extract_to_cond_assign(ir->value);
218    }
219 
220    return visit_continue;
221 }
222 
223 ir_visitor_status
visit_enter(ir_if * ir)224 ir_vec_index_to_cond_assign_visitor::visit_enter(ir_if *ir)
225 {
226    ir->condition = convert_vector_extract_to_cond_assign(ir->condition);
227 
228    return visit_continue;
229 }
230 
231 bool
do_vec_index_to_cond_assign(exec_list * instructions)232 do_vec_index_to_cond_assign(exec_list *instructions)
233 {
234    ir_vec_index_to_cond_assign_visitor v;
235 
236    visit_list_elements(&v, instructions);
237 
238    return v.progress;
239 }
240