Subversion Repositories Kolibri OS

Rev

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

  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_mat_op_to_vec.cpp
  26.  *
  27.  * Breaks matrix operation expressions down to a series of vector operations.
  28.  *
  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
  31.  * column or row.
  32.  */
  33.  
  34. #include "ir.h"
  35. #include "ir_expression_flattening.h"
  36. #include "glsl_types.h"
  37.  
  38. class ir_mat_op_to_vec_visitor : public ir_hierarchical_visitor {
  39. public:
  40.    ir_mat_op_to_vec_visitor()
  41.    {
  42.       this->made_progress = false;
  43.       this->mem_ctx = NULL;
  44.    }
  45.  
  46.    ir_visitor_status visit_leave(ir_assignment *);
  47.  
  48.    ir_dereference *get_column(ir_dereference *val, int col);
  49.    ir_rvalue *get_element(ir_dereference *val, int col, int row);
  50.  
  51.    void do_mul_mat_mat(ir_dereference *result,
  52.                        ir_dereference *a, ir_dereference *b);
  53.    void do_mul_mat_vec(ir_dereference *result,
  54.                        ir_dereference *a, ir_dereference *b);
  55.    void do_mul_vec_mat(ir_dereference *result,
  56.                        ir_dereference *a, ir_dereference *b);
  57.    void do_mul_mat_scalar(ir_dereference *result,
  58.                           ir_dereference *a, ir_dereference *b);
  59.    void do_equal_mat_mat(ir_dereference *result, ir_dereference *a,
  60.                          ir_dereference *b, bool test_equal);
  61.  
  62.    void *mem_ctx;
  63.    bool made_progress;
  64. };
  65.  
  66. static bool
  67. mat_op_to_vec_predicate(ir_instruction *ir)
  68. {
  69.    ir_expression *expr = ir->as_expression();
  70.    unsigned int i;
  71.  
  72.    if (!expr)
  73.       return false;
  74.  
  75.    for (i = 0; i < expr->get_num_operands(); i++) {
  76.       if (expr->operands[i]->type->is_matrix())
  77.          return true;
  78.    }
  79.  
  80.    return false;
  81. }
  82.  
  83. bool
  84. do_mat_op_to_vec(exec_list *instructions)
  85. {
  86.    ir_mat_op_to_vec_visitor v;
  87.  
  88.    /* Pull out any matrix expression to a separate assignment to a
  89.     * temp.  This will make our handling of the breakdown to
  90.     * operations on the matrix's vector components much easier.
  91.     */
  92.    do_expression_flattening(instructions, mat_op_to_vec_predicate);
  93.  
  94.    visit_list_elements(&v, instructions);
  95.  
  96.    return v.made_progress;
  97. }
  98.  
  99. ir_rvalue *
  100. ir_mat_op_to_vec_visitor::get_element(ir_dereference *val, int col, int row)
  101. {
  102.    val = get_column(val, col);
  103.  
  104.    return new(mem_ctx) ir_swizzle(val, row, 0, 0, 0, 1);
  105. }
  106.  
  107. ir_dereference *
  108. ir_mat_op_to_vec_visitor::get_column(ir_dereference *val, int row)
  109. {
  110.    val = val->clone(mem_ctx, NULL);
  111.  
  112.    if (val->type->is_matrix()) {
  113.       val = new(mem_ctx) ir_dereference_array(val,
  114.                                               new(mem_ctx) ir_constant(row));
  115.    }
  116.  
  117.    return val;
  118. }
  119.  
  120. void
  121. ir_mat_op_to_vec_visitor::do_mul_mat_mat(ir_dereference *result,
  122.                                          ir_dereference *a,
  123.                                          ir_dereference *b)
  124. {
  125.    unsigned b_col, i;
  126.    ir_assignment *assign;
  127.    ir_expression *expr;
  128.  
  129.    for (b_col = 0; b_col < b->type->matrix_columns; b_col++) {
  130.       /* first column */
  131.       expr = new(mem_ctx) ir_expression(ir_binop_mul,
  132.                                         get_column(a, 0),
  133.                                         get_element(b, b_col, 0));
  134.  
  135.       /* following columns */
  136.       for (i = 1; i < a->type->matrix_columns; i++) {
  137.          ir_expression *mul_expr;
  138.  
  139.          mul_expr = new(mem_ctx) ir_expression(ir_binop_mul,
  140.                                                get_column(a, i),
  141.                                                get_element(b, b_col, i));
  142.          expr = new(mem_ctx) ir_expression(ir_binop_add,
  143.                                            expr,
  144.                                            mul_expr);
  145.       }
  146.  
  147.       assign = new(mem_ctx) ir_assignment(get_column(result, b_col), expr);
  148.       base_ir->insert_before(assign);
  149.    }
  150. }
  151.  
  152. void
  153. ir_mat_op_to_vec_visitor::do_mul_mat_vec(ir_dereference *result,
  154.                                          ir_dereference *a,
  155.                                          ir_dereference *b)
  156. {
  157.    unsigned i;
  158.    ir_assignment *assign;
  159.    ir_expression *expr;
  160.  
  161.    /* first column */
  162.    expr = new(mem_ctx) ir_expression(ir_binop_mul,
  163.                                      get_column(a, 0),
  164.                                      get_element(b, 0, 0));
  165.  
  166.    /* following columns */
  167.    for (i = 1; i < a->type->matrix_columns; i++) {
  168.       ir_expression *mul_expr;
  169.  
  170.       mul_expr = new(mem_ctx) ir_expression(ir_binop_mul,
  171.                                             get_column(a, i),
  172.                                             get_element(b, 0, i));
  173.       expr = new(mem_ctx) ir_expression(ir_binop_add, expr, mul_expr);
  174.    }
  175.  
  176.    result = result->clone(mem_ctx, NULL);
  177.    assign = new(mem_ctx) ir_assignment(result, expr);
  178.    base_ir->insert_before(assign);
  179. }
  180.  
  181. void
  182. ir_mat_op_to_vec_visitor::do_mul_vec_mat(ir_dereference *result,
  183.                                          ir_dereference *a,
  184.                                          ir_dereference *b)
  185. {
  186.    unsigned i;
  187.  
  188.    for (i = 0; i < b->type->matrix_columns; i++) {
  189.       ir_rvalue *column_result;
  190.       ir_expression *column_expr;
  191.       ir_assignment *column_assign;
  192.  
  193.       column_result = result->clone(mem_ctx, NULL);
  194.       column_result = new(mem_ctx) ir_swizzle(column_result, i, 0, 0, 0, 1);
  195.  
  196.       column_expr = new(mem_ctx) ir_expression(ir_binop_dot,
  197.                                                a->clone(mem_ctx, NULL),
  198.                                                get_column(b, i));
  199.  
  200.       column_assign = new(mem_ctx) ir_assignment(column_result,
  201.                                                  column_expr);
  202.       base_ir->insert_before(column_assign);
  203.    }
  204. }
  205.  
  206. void
  207. ir_mat_op_to_vec_visitor::do_mul_mat_scalar(ir_dereference *result,
  208.                                             ir_dereference *a,
  209.                                             ir_dereference *b)
  210. {
  211.    unsigned i;
  212.  
  213.    for (i = 0; i < a->type->matrix_columns; i++) {
  214.       ir_expression *column_expr;
  215.       ir_assignment *column_assign;
  216.  
  217.       column_expr = new(mem_ctx) ir_expression(ir_binop_mul,
  218.                                                get_column(a, i),
  219.                                                b->clone(mem_ctx, NULL));
  220.  
  221.       column_assign = new(mem_ctx) ir_assignment(get_column(result, i),
  222.                                                  column_expr);
  223.       base_ir->insert_before(column_assign);
  224.    }
  225. }
  226.  
  227. void
  228. ir_mat_op_to_vec_visitor::do_equal_mat_mat(ir_dereference *result,
  229.                                            ir_dereference *a,
  230.                                            ir_dereference *b,
  231.                                            bool test_equal)
  232. {
  233.    /* This essentially implements the following GLSL:
  234.     *
  235.     * bool equal(mat4 a, mat4 b)
  236.     * {
  237.     *   return !any(bvec4(a[0] != b[0],
  238.     *                     a[1] != b[1],
  239.     *                     a[2] != b[2],
  240.     *                     a[3] != b[3]);
  241.     * }
  242.     *
  243.     * bool nequal(mat4 a, mat4 b)
  244.     * {
  245.     *   return any(bvec4(a[0] != b[0],
  246.     *                    a[1] != b[1],
  247.     *                    a[2] != b[2],
  248.     *                    a[3] != b[3]);
  249.     * }
  250.     */
  251.    const unsigned columns = a->type->matrix_columns;
  252.    const glsl_type *const bvec_type =
  253.       glsl_type::get_instance(GLSL_TYPE_BOOL, columns, 1);
  254.  
  255.    ir_variable *const tmp_bvec =
  256.       new(this->mem_ctx) ir_variable(bvec_type, "mat_cmp_bvec",
  257.                                      ir_var_temporary);
  258.    this->base_ir->insert_before(tmp_bvec);
  259.  
  260.    for (unsigned i = 0; i < columns; i++) {
  261.       ir_expression *const cmp =
  262.          new(this->mem_ctx) ir_expression(ir_binop_any_nequal,
  263.                                           get_column(a, i),
  264.                                           get_column(b, i));
  265.  
  266.       ir_dereference *const lhs =
  267.          new(this->mem_ctx) ir_dereference_variable(tmp_bvec);
  268.  
  269.       ir_assignment *const assign =
  270.          new(this->mem_ctx) ir_assignment(lhs, cmp, NULL, (1U << i));
  271.  
  272.       this->base_ir->insert_before(assign);
  273.    }
  274.  
  275.    ir_rvalue *const val = new(this->mem_ctx) ir_dereference_variable(tmp_bvec);
  276.    ir_expression *any = new(this->mem_ctx) ir_expression(ir_unop_any, val);
  277.  
  278.    if (test_equal)
  279.       any = new(this->mem_ctx) ir_expression(ir_unop_logic_not, any);
  280.  
  281.    ir_assignment *const assign =
  282.       new(mem_ctx) ir_assignment(result->clone(mem_ctx, NULL), any);
  283.    base_ir->insert_before(assign);
  284. }
  285.  
  286. static bool
  287. has_matrix_operand(const ir_expression *expr, unsigned &columns)
  288. {
  289.    for (unsigned i = 0; i < expr->get_num_operands(); i++) {
  290.       if (expr->operands[i]->type->is_matrix()) {
  291.          columns = expr->operands[i]->type->matrix_columns;
  292.          return true;
  293.       }
  294.    }
  295.  
  296.    return false;
  297. }
  298.  
  299.  
  300. ir_visitor_status
  301. ir_mat_op_to_vec_visitor::visit_leave(ir_assignment *orig_assign)
  302. {
  303.    ir_expression *orig_expr = orig_assign->rhs->as_expression();
  304.    unsigned int i, matrix_columns = 1;
  305.    ir_dereference *op[2];
  306.  
  307.    if (!orig_expr)
  308.       return visit_continue;
  309.  
  310.    if (!has_matrix_operand(orig_expr, matrix_columns))
  311.       return visit_continue;
  312.  
  313.    assert(orig_expr->get_num_operands() <= 2);
  314.  
  315.    mem_ctx = ralloc_parent(orig_assign);
  316.  
  317.    ir_dereference_variable *result =
  318.       orig_assign->lhs->as_dereference_variable();
  319.    assert(result);
  320.  
  321.    /* Store the expression operands in temps so we can use them
  322.     * multiple times.
  323.     */
  324.    for (i = 0; i < orig_expr->get_num_operands(); i++) {
  325.       ir_assignment *assign;
  326.       ir_dereference *deref = orig_expr->operands[i]->as_dereference();
  327.  
  328.       /* Avoid making a temporary if we don't need to to avoid aliasing. */
  329.       if (deref &&
  330.           deref->variable_referenced() != result->variable_referenced()) {
  331.          op[i] = deref;
  332.          continue;
  333.       }
  334.  
  335.       /* Otherwise, store the operand in a temporary generally if it's
  336.        * not a dereference.
  337.        */
  338.       ir_variable *var = new(mem_ctx) ir_variable(orig_expr->operands[i]->type,
  339.                                                   "mat_op_to_vec",
  340.                                                   ir_var_temporary);
  341.       base_ir->insert_before(var);
  342.  
  343.       /* Note that we use this dereference for the assignment.  That means
  344.        * that others that want to use op[i] have to clone the deref.
  345.        */
  346.       op[i] = new(mem_ctx) ir_dereference_variable(var);
  347.       assign = new(mem_ctx) ir_assignment(op[i], orig_expr->operands[i]);
  348.       base_ir->insert_before(assign);
  349.    }
  350.  
  351.    /* OK, time to break down this matrix operation. */
  352.    switch (orig_expr->operation) {
  353.    case ir_unop_neg: {
  354.       /* Apply the operation to each column.*/
  355.       for (i = 0; i < matrix_columns; i++) {
  356.          ir_expression *column_expr;
  357.          ir_assignment *column_assign;
  358.  
  359.          column_expr = new(mem_ctx) ir_expression(orig_expr->operation,
  360.                                                   get_column(op[0], i));
  361.  
  362.          column_assign = new(mem_ctx) ir_assignment(get_column(result, i),
  363.                                                     column_expr);
  364.          assert(column_assign->write_mask != 0);
  365.          base_ir->insert_before(column_assign);
  366.       }
  367.       break;
  368.    }
  369.    case ir_binop_add:
  370.    case ir_binop_sub:
  371.    case ir_binop_div:
  372.    case ir_binop_mod: {
  373.       /* For most operations, the matrix version is just going
  374.        * column-wise through and applying the operation to each column
  375.        * if available.
  376.        */
  377.       for (i = 0; i < matrix_columns; i++) {
  378.          ir_expression *column_expr;
  379.          ir_assignment *column_assign;
  380.  
  381.          column_expr = new(mem_ctx) ir_expression(orig_expr->operation,
  382.                                                   get_column(op[0], i),
  383.                                                   get_column(op[1], i));
  384.  
  385.          column_assign = new(mem_ctx) ir_assignment(get_column(result, i),
  386.                                                     column_expr);
  387.          assert(column_assign->write_mask != 0);
  388.          base_ir->insert_before(column_assign);
  389.       }
  390.       break;
  391.    }
  392.    case ir_binop_mul:
  393.       if (op[0]->type->is_matrix()) {
  394.          if (op[1]->type->is_matrix()) {
  395.             do_mul_mat_mat(result, op[0], op[1]);
  396.          } else if (op[1]->type->is_vector()) {
  397.             do_mul_mat_vec(result, op[0], op[1]);
  398.          } else {
  399.             assert(op[1]->type->is_scalar());
  400.             do_mul_mat_scalar(result, op[0], op[1]);
  401.          }
  402.       } else {
  403.          assert(op[1]->type->is_matrix());
  404.          if (op[0]->type->is_vector()) {
  405.             do_mul_vec_mat(result, op[0], op[1]);
  406.          } else {
  407.             assert(op[0]->type->is_scalar());
  408.             do_mul_mat_scalar(result, op[1], op[0]);
  409.          }
  410.       }
  411.       break;
  412.  
  413.    case ir_binop_all_equal:
  414.    case ir_binop_any_nequal:
  415.       do_equal_mat_mat(result, op[1], op[0],
  416.                        (orig_expr->operation == ir_binop_all_equal));
  417.       break;
  418.  
  419.    default:
  420.       printf("FINISHME: Handle matrix operation for %s\n",
  421.              orig_expr->operator_string());
  422.       abort();
  423.    }
  424.    orig_assign->remove();
  425.    this->made_progress = true;
  426.  
  427.    return visit_continue;
  428. }
  429.