Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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