2 * Copyright © 2010 Intel Corporation
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:
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
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.
25 * \file ir_mat_op_to_vec.cpp
27 * Breaks matrix operation expressions down to a series of vector operations.
29 * Generally this is how we have to codegen matrix operations for a
30 * GPU, so this gives us the chance to constant fold operations on a
35 #include "ir_expression_flattening.h"
36 #include "glsl_types.h"
38 class ir_mat_op_to_vec_visitor
: public ir_hierarchical_visitor
{
40 ir_mat_op_to_vec_visitor()
42 this->made_progress
= false;
45 ir_visitor_status
visit_leave(ir_assignment
*);
47 ir_dereference
*get_column(ir_variable
*var
, int col
);
48 ir_rvalue
*get_element(ir_variable
*var
, int col
, int row
);
50 void do_mul_mat_mat(ir_variable
*result_var
,
51 ir_variable
*a_var
, ir_variable
*b_var
);
52 void do_mul_mat_vec(ir_variable
*result_var
,
53 ir_variable
*a_var
, ir_variable
*b_var
);
54 void do_mul_vec_mat(ir_variable
*result_var
,
55 ir_variable
*a_var
, ir_variable
*b_var
);
56 void do_mul_mat_scalar(ir_variable
*result_var
,
57 ir_variable
*a_var
, ir_variable
*b_var
);
63 mat_op_to_vec_predicate(ir_instruction
*ir
)
65 ir_expression
*expr
= ir
->as_expression();
71 for (i
= 0; i
< expr
->get_num_operands(); i
++) {
72 if (expr
->operands
[i
]->type
->is_matrix())
80 do_mat_op_to_vec(exec_list
*instructions
)
82 ir_mat_op_to_vec_visitor v
;
84 /* Pull out any matrix expression to a separate assignment to a
85 * temp. This will make our handling of the breakdown to
86 * operations on the matrix's vector components much easier.
88 do_expression_flattening(instructions
, mat_op_to_vec_predicate
);
90 visit_list_elements(&v
, instructions
);
92 return v
.made_progress
;
96 ir_mat_op_to_vec_visitor::get_element(ir_variable
*var
, int col
, int row
)
98 ir_dereference
*deref
;
100 deref
= new(base_ir
) ir_dereference_variable(var
);
102 if (var
->type
->is_matrix()) {
103 deref
= new(base_ir
) ir_dereference_array(var
,
104 new(base_ir
) ir_constant(col
));
109 return new(base_ir
) ir_swizzle(deref
, row
, 0, 0, 0, 1);
113 ir_mat_op_to_vec_visitor::get_column(ir_variable
*var
, int row
)
115 ir_dereference
*deref
;
117 if (!var
->type
->is_matrix()) {
118 deref
= new(base_ir
) ir_dereference_variable(var
);
120 deref
= new(base_ir
) ir_dereference_variable(var
);
121 deref
= new(base_ir
) ir_dereference_array(deref
,
122 new(base_ir
) ir_constant(row
));
129 ir_mat_op_to_vec_visitor::do_mul_mat_mat(ir_variable
*result_var
,
134 ir_assignment
*assign
;
137 for (b_col
= 0; b_col
< b_var
->type
->matrix_columns
; b_col
++) {
138 ir_rvalue
*a
= get_column(a_var
, 0);
139 ir_rvalue
*b
= get_element(b_var
, b_col
, 0);
142 expr
= new(base_ir
) ir_expression(ir_binop_mul
,
147 /* following columns */
148 for (i
= 1; i
< a_var
->type
->matrix_columns
; i
++) {
149 ir_expression
*mul_expr
;
151 a
= get_column(a_var
, i
);
152 b
= get_element(b_var
, b_col
, i
);
154 mul_expr
= new(base_ir
) ir_expression(ir_binop_mul
,
158 expr
= new(base_ir
) ir_expression(ir_binop_add
,
164 ir_rvalue
*result
= get_column(result_var
, b_col
);
165 assign
= new(base_ir
) ir_assignment(result
,
168 base_ir
->insert_before(assign
);
173 ir_mat_op_to_vec_visitor::do_mul_mat_vec(ir_variable
*result_var
,
178 ir_rvalue
*a
= get_column(a_var
, 0);
179 ir_rvalue
*b
= get_element(b_var
, 0, 0);
180 ir_assignment
*assign
;
184 expr
= new(base_ir
) ir_expression(ir_binop_mul
,
189 /* following columns */
190 for (i
= 1; i
< a_var
->type
->matrix_columns
; i
++) {
191 ir_expression
*mul_expr
;
193 a
= get_column(a_var
, i
);
194 b
= get_element(b_var
, 0, i
);
196 mul_expr
= new(base_ir
) ir_expression(ir_binop_mul
,
200 expr
= new(base_ir
) ir_expression(ir_binop_add
,
206 ir_rvalue
*result
= new(base_ir
) ir_dereference_variable(result_var
);
207 assign
= new(base_ir
) ir_assignment(result
,
210 base_ir
->insert_before(assign
);
214 ir_mat_op_to_vec_visitor::do_mul_vec_mat(ir_variable
*result_var
,
220 for (i
= 0; i
< b_var
->type
->matrix_columns
; i
++) {
221 ir_rvalue
*a
= new(base_ir
) ir_dereference_variable(a_var
);
222 ir_rvalue
*b
= get_column(b_var
, i
);
224 ir_expression
*column_expr
;
225 ir_assignment
*column_assign
;
227 result
= new(base_ir
) ir_dereference_variable(result_var
);
228 result
= new(base_ir
) ir_swizzle(result
, i
, 0, 0, 0, 1);
230 column_expr
= new(base_ir
) ir_expression(ir_binop_dot
,
235 column_assign
= new(base_ir
) ir_assignment(result
,
238 base_ir
->insert_before(column_assign
);
243 ir_mat_op_to_vec_visitor::do_mul_mat_scalar(ir_variable
*result_var
,
249 for (i
= 0; i
< a_var
->type
->matrix_columns
; i
++) {
250 ir_rvalue
*a
= get_column(a_var
, i
);
251 ir_rvalue
*b
= new(base_ir
) ir_dereference_variable(b_var
);
252 ir_rvalue
*result
= get_column(result_var
, i
);
253 ir_expression
*column_expr
;
254 ir_assignment
*column_assign
;
256 column_expr
= new(base_ir
) ir_expression(ir_binop_mul
,
261 column_assign
= new(base_ir
) ir_assignment(result
,
264 base_ir
->insert_before(column_assign
);
269 ir_mat_op_to_vec_visitor::visit_leave(ir_assignment
*assign
)
271 ir_expression
*expr
= assign
->rhs
->as_expression();
272 bool found_matrix
= false;
273 unsigned int i
, matrix_columns
= 1;
274 ir_variable
*op_var
[2];
277 return visit_continue
;
279 for (i
= 0; i
< expr
->get_num_operands(); i
++) {
280 if (expr
->operands
[i
]->type
->is_matrix()) {
282 matrix_columns
= expr
->operands
[i
]->type
->matrix_columns
;
287 return visit_continue
;
289 ir_dereference_variable
*lhs_deref
= assign
->lhs
->as_dereference_variable();
292 ir_variable
*result_var
= lhs_deref
->var
;
294 /* Store the expression operands in temps so we can use them
297 for (i
= 0; i
< expr
->get_num_operands(); i
++) {
298 ir_assignment
*assign
;
300 op_var
[i
] = new(base_ir
) ir_variable(expr
->operands
[i
]->type
,
303 base_ir
->insert_before(op_var
[i
]);
305 lhs_deref
= new(base_ir
) ir_dereference_variable(op_var
[i
]);
306 assign
= new(base_ir
) ir_assignment(lhs_deref
,
309 base_ir
->insert_before(assign
);
312 /* OK, time to break down this matrix operation. */
313 switch (expr
->operation
) {
315 const unsigned mask
= (1U << result_var
->type
->vector_elements
) - 1;
317 /* Apply the operation to each column.*/
318 for (i
= 0; i
< matrix_columns
; i
++) {
319 ir_rvalue
*op0
= get_column(op_var
[0], i
);
320 ir_dereference
*result
= get_column(result_var
, i
);
321 ir_expression
*column_expr
;
322 ir_assignment
*column_assign
;
324 column_expr
= new(base_ir
) ir_expression(expr
->operation
,
329 column_assign
= new(base_ir
) ir_assignment(result
,
333 assert(column_assign
->write_mask
!= 0);
334 base_ir
->insert_before(column_assign
);
342 const unsigned mask
= (1U << result_var
->type
->vector_elements
) - 1;
344 /* For most operations, the matrix version is just going
345 * column-wise through and applying the operation to each column
348 for (i
= 0; i
< matrix_columns
; i
++) {
349 ir_rvalue
*op0
= get_column(op_var
[0], i
);
350 ir_rvalue
*op1
= get_column(op_var
[1], i
);
351 ir_dereference
*result
= get_column(result_var
, i
);
352 ir_expression
*column_expr
;
353 ir_assignment
*column_assign
;
355 column_expr
= new(base_ir
) ir_expression(expr
->operation
,
360 column_assign
= new(base_ir
) ir_assignment(result
,
364 assert(column_assign
->write_mask
!= 0);
365 base_ir
->insert_before(column_assign
);
370 if (op_var
[0]->type
->is_matrix()) {
371 if (op_var
[1]->type
->is_matrix()) {
372 do_mul_mat_mat(result_var
, op_var
[0], op_var
[1]);
373 } else if (op_var
[1]->type
->is_vector()) {
374 do_mul_mat_vec(result_var
, op_var
[0], op_var
[1]);
376 assert(op_var
[1]->type
->is_scalar());
377 do_mul_mat_scalar(result_var
, op_var
[0], op_var
[1]);
380 assert(op_var
[1]->type
->is_matrix());
381 if (op_var
[0]->type
->is_vector()) {
382 do_mul_vec_mat(result_var
, op_var
[0], op_var
[1]);
384 assert(op_var
[0]->type
->is_scalar());
385 do_mul_mat_scalar(result_var
, op_var
[1], op_var
[0]);
390 printf("FINISHME: Handle matrix operation for %s\n", expr
->operator_string());
394 this->made_progress
= true;
396 return visit_continue
;