ir_visitor_status ir_mat_op_to_vec_visitor::visit_leave(ir_assignment *orig_assign) { ir_expression *orig_expr = orig_assign->rhs->as_expression(); unsigned int i, matrix_columns = 1; ir_dereference *op[2]; if (!orig_expr) return visit_continue; if (!has_matrix_operand(orig_expr, matrix_columns)) return visit_continue; check(orig_expr->get_num_operands() <= 2); mem_ctx = ralloc_parent(orig_assign); ir_dereference_variable *result = orig_assign->lhs->as_dereference_variable(); check(result); /* Store the expression operands in temps so we can use them * multiple times. */ for (i = 0; i < orig_expr->get_num_operands(); i++) { ir_assignment *assign; ir_dereference *deref = orig_expr->operands[i]->as_dereference(); /* Avoid making a temporary if we don't need to to avoid aliasing. */ if (deref && deref->variable_referenced() != result->variable_referenced()) { op[i] = deref; continue; } /* Otherwise, store the operand in a temporary generally if it's * not a dereference. */ ir_variable *var = new(mem_ctx)ir_variable(orig_expr->operands[i]->type, "mat_op_to_vec", ir_var_temporary); base_ir->insert_before(var); /* Note that we use this dereference for the assignment. That means * that others that want to use op[i] have to clone the deref. */ op[i] = new(mem_ctx)ir_dereference_variable(var); assign = new(mem_ctx)ir_assignment(op[i], orig_expr->operands[i]); base_ir->insert_before(assign); } /* OK, time to break down this matrix operation. */ switch (orig_expr->operation) { case ir_unop_neg: { /* Apply the operation to each column.*/ for (i = 0; i < matrix_columns; i++) { ir_expression *column_expr; ir_assignment *column_assign; check(op[0]); column_expr = new(mem_ctx)ir_expression(orig_expr->operation, get_column(op[0], i)); column_assign = new(mem_ctx)ir_assignment(get_column(result, i), column_expr); check(column_assign->write_mask != 0); base_ir->insert_before(column_assign); } break; } case ir_binop_add: case ir_binop_sub: case ir_binop_div: case ir_binop_mod: { /* For most operations, the matrix version is just going * column-wise through and applying the operation to each column * if available. */ for (i = 0; i < matrix_columns; i++) { ir_expression *column_expr; ir_assignment *column_assign; check(op[0] && op[1]); column_expr = new(mem_ctx)ir_expression(orig_expr->operation, get_column(op[0], i), get_column(op[1], i)); column_assign = new(mem_ctx)ir_assignment(get_column(result, i), column_expr); check(column_assign->write_mask != 0); base_ir->insert_before(column_assign); } break; } case ir_binop_mul: check(op[0] && op[1]); if (op[0]->type->is_matrix()) { if (op[1]->type->is_matrix()) { do_mul_mat_mat(result, op[0], op[1]); } else if (op[1]->type->is_vector()) { do_mul_mat_vec(result, op[0], op[1]); } else { check(op[1]->type->is_scalar()); do_mul_mat_scalar(result, op[0], op[1]); } } else { check(op[1]->type->is_matrix()); if (op[0]->type->is_vector()) { do_mul_vec_mat(result, op[0], op[1]); } else { check(op[0]->type->is_scalar()); do_mul_mat_scalar(result, op[1], op[0]); } } break; case ir_binop_all_equal: case ir_binop_any_nequal: check(op[0] && op[1]); do_equal_mat_mat(result, op[1], op[0], (orig_expr->operation == ir_binop_all_equal)); break; default: printf("FINISHME: Handle matrix operation for %s\n", orig_expr->operator_string()); abort(); } orig_assign->remove(); this->made_progress = true; return visit_continue; }
ir_visitor_status ir_mat_op_to_vec_visitor::visit_leave(ir_assignment *orig_assign) { ir_expression *orig_expr = orig_assign->rhs->as_expression(); unsigned int i, matrix_columns = 1; ir_variable *op_var[2]; if (!orig_expr) return visit_continue; if (!has_matrix_operand(orig_expr, matrix_columns)) return visit_continue; assert(orig_expr->get_num_operands() <= 2); mem_ctx = ralloc_parent(orig_assign); ir_dereference_variable *lhs_deref = orig_assign->lhs->as_dereference_variable(); assert(lhs_deref); ir_variable *result_var = lhs_deref->var; /* Store the expression operands in temps so we can use them * multiple times. */ for (i = 0; i < orig_expr->get_num_operands(); i++) { ir_assignment *assign; op_var[i] = new(mem_ctx) ir_variable(orig_expr->operands[i]->type, "mat_op_to_vec", ir_var_temporary); base_ir->insert_before(op_var[i]); lhs_deref = new(mem_ctx) ir_dereference_variable(op_var[i]); assign = new(mem_ctx) ir_assignment(lhs_deref, orig_expr->operands[i], NULL); base_ir->insert_before(assign); } /* OK, time to break down this matrix operation. */ switch (orig_expr->operation) { case ir_unop_neg: { const unsigned mask = (1U << result_var->type->vector_elements) - 1; /* Apply the operation to each column.*/ for (i = 0; i < matrix_columns; i++) { ir_rvalue *op0 = get_column(op_var[0], i); ir_dereference *result = get_column(result_var, i); ir_expression *column_expr; ir_assignment *column_assign; column_expr = new(mem_ctx) ir_expression(orig_expr->operation, result->type, op0, NULL); column_assign = new(mem_ctx) ir_assignment(result, column_expr, NULL, mask); assert(column_assign->write_mask != 0); base_ir->insert_before(column_assign); } break; } case ir_binop_add: case ir_binop_sub: case ir_binop_div: case ir_binop_mod: { const unsigned mask = (1U << result_var->type->vector_elements) - 1; /* For most operations, the matrix version is just going * column-wise through and applying the operation to each column * if available. */ for (i = 0; i < matrix_columns; i++) { ir_rvalue *op0 = get_column(op_var[0], i); ir_rvalue *op1 = get_column(op_var[1], i); ir_dereference *result = get_column(result_var, i); ir_expression *column_expr; ir_assignment *column_assign; column_expr = new(mem_ctx) ir_expression(orig_expr->operation, result->type, op0, op1); column_assign = new(mem_ctx) ir_assignment(result, column_expr, NULL, mask); assert(column_assign->write_mask != 0); base_ir->insert_before(column_assign); } break; } case ir_binop_mul: if (op_var[0]->type->is_matrix()) { if (op_var[1]->type->is_matrix()) { do_mul_mat_mat(result_var, op_var[0], op_var[1]); } else if (op_var[1]->type->is_vector()) { do_mul_mat_vec(result_var, op_var[0], op_var[1]); } else { assert(op_var[1]->type->is_scalar()); do_mul_mat_scalar(result_var, op_var[0], op_var[1]); } } else { assert(op_var[1]->type->is_matrix()); if (op_var[0]->type->is_vector()) { do_mul_vec_mat(result_var, op_var[0], op_var[1]); } else { assert(op_var[0]->type->is_scalar()); do_mul_mat_scalar(result_var, op_var[1], op_var[0]); } } break; case ir_binop_all_equal: case ir_binop_any_nequal: do_equal_mat_mat(result_var, op_var[1], op_var[0], (orig_expr->operation == ir_binop_all_equal)); break; default: printf("FINISHME: Handle matrix operation for %s\n", orig_expr->operator_string()); abort(); } orig_assign->remove(); this->made_progress = true; return visit_continue; }