Subversion Repositories Kolibri OS

Rev

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