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.  * constant 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, constant, 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 constantright 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 CONSTANTRIGHT 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 opt_constant_propagation.cpp
  26.  *
  27.  * Tracks assignments of constants to channels of variables, and
  28.  * usage of those constant channels with direct usage of the constants.
  29.  *
  30.  * This can lead to constant folding and algebraic optimizations in
  31.  * those later expressions, while causing no increase in instruction
  32.  * count (due to constants being generally free to load from a
  33.  * constant push buffer or as instruction immediate values) and
  34.  * possibly reducing register pressure.
  35.  */
  36.  
  37. #include "ir.h"
  38. #include "ir_visitor.h"
  39. #include "ir_rvalue_visitor.h"
  40. #include "ir_basic_block.h"
  41. #include "ir_optimization.h"
  42. #include "glsl_types.h"
  43.  
  44. namespace {
  45.  
  46. class acp_entry : public exec_node
  47. {
  48. public:
  49.    acp_entry(ir_variable *var, unsigned write_mask, ir_constant *constant)
  50.    {
  51.       assert(var);
  52.       assert(constant);
  53.       this->var = var;
  54.       this->write_mask = write_mask;
  55.       this->constant = constant;
  56.       this->initial_values = write_mask;
  57.    }
  58.  
  59.    acp_entry(const acp_entry *src)
  60.    {
  61.       this->var = src->var;
  62.       this->write_mask = src->write_mask;
  63.       this->constant = src->constant;
  64.       this->initial_values = src->initial_values;
  65.    }
  66.  
  67.    ir_variable *var;
  68.    ir_constant *constant;
  69.    unsigned write_mask;
  70.  
  71.    /** Mask of values initially available in the constant. */
  72.    unsigned initial_values;
  73. };
  74.  
  75.  
  76. class kill_entry : public exec_node
  77. {
  78. public:
  79.    kill_entry(ir_variable *var, unsigned write_mask)
  80.    {
  81.       assert(var);
  82.       this->var = var;
  83.       this->write_mask = write_mask;
  84.    }
  85.  
  86.    ir_variable *var;
  87.    unsigned write_mask;
  88. };
  89.  
  90. class ir_constant_propagation_visitor : public ir_rvalue_visitor {
  91. public:
  92.    ir_constant_propagation_visitor()
  93.    {
  94.       progress = false;
  95.       killed_all = false;
  96.       mem_ctx = ralloc_context(0);
  97.       this->acp = new(mem_ctx) exec_list;
  98.       this->kills = new(mem_ctx) exec_list;
  99.    }
  100.    ~ir_constant_propagation_visitor()
  101.    {
  102.       ralloc_free(mem_ctx);
  103.    }
  104.  
  105.    virtual ir_visitor_status visit_enter(class ir_loop *);
  106.    virtual ir_visitor_status visit_enter(class ir_function_signature *);
  107.    virtual ir_visitor_status visit_enter(class ir_function *);
  108.    virtual ir_visitor_status visit_leave(class ir_assignment *);
  109.    virtual ir_visitor_status visit_enter(class ir_call *);
  110.    virtual ir_visitor_status visit_enter(class ir_if *);
  111.  
  112.    void add_constant(ir_assignment *ir);
  113.    void kill(ir_variable *ir, unsigned write_mask);
  114.    void handle_if_block(exec_list *instructions);
  115.    void handle_rvalue(ir_rvalue **rvalue);
  116.  
  117.    /** List of acp_entry: The available constants to propagate */
  118.    exec_list *acp;
  119.  
  120.    /**
  121.     * List of kill_entry: The masks of variables whose values were
  122.     * killed in this block.
  123.     */
  124.    exec_list *kills;
  125.  
  126.    bool progress;
  127.  
  128.    bool killed_all;
  129.  
  130.    void *mem_ctx;
  131. };
  132.  
  133.  
  134. void
  135. ir_constant_propagation_visitor::handle_rvalue(ir_rvalue **rvalue)
  136. {
  137.    if (this->in_assignee || !*rvalue)
  138.       return;
  139.  
  140.    const glsl_type *type = (*rvalue)->type;
  141.    if (!type->is_scalar() && !type->is_vector())
  142.       return;
  143.  
  144.    ir_swizzle *swiz = NULL;
  145.    ir_dereference_variable *deref = (*rvalue)->as_dereference_variable();
  146.    if (!deref) {
  147.       swiz = (*rvalue)->as_swizzle();
  148.       if (!swiz)
  149.          return;
  150.  
  151.       deref = swiz->val->as_dereference_variable();
  152.       if (!deref)
  153.          return;
  154.    }
  155.  
  156.    ir_constant_data data;
  157.    memset(&data, 0, sizeof(data));
  158.  
  159.    for (unsigned int i = 0; i < type->components(); i++) {
  160.       int channel;
  161.       acp_entry *found = NULL;
  162.  
  163.       if (swiz) {
  164.          switch (i) {
  165.          case 0: channel = swiz->mask.x; break;
  166.          case 1: channel = swiz->mask.y; break;
  167.          case 2: channel = swiz->mask.z; break;
  168.          case 3: channel = swiz->mask.w; break;
  169.          default: assert(!"shouldn't be reached"); channel = 0; break;
  170.          }
  171.       } else {
  172.          channel = i;
  173.       }
  174.  
  175.       foreach_in_list(acp_entry, entry, this->acp) {
  176.          if (entry->var == deref->var && entry->write_mask & (1 << channel)) {
  177.             found = entry;
  178.             break;
  179.          }
  180.       }
  181.  
  182.       if (!found)
  183.          return;
  184.  
  185.       int rhs_channel = 0;
  186.       for (int j = 0; j < 4; j++) {
  187.          if (j == channel)
  188.             break;
  189.          if (found->initial_values & (1 << j))
  190.             rhs_channel++;
  191.       }
  192.  
  193.       switch (type->base_type) {
  194.       case GLSL_TYPE_FLOAT:
  195.          data.f[i] = found->constant->value.f[rhs_channel];
  196.          break;
  197.       case GLSL_TYPE_DOUBLE:
  198.          data.d[i] = found->constant->value.d[rhs_channel];
  199.          break;
  200.       case GLSL_TYPE_INT:
  201.          data.i[i] = found->constant->value.i[rhs_channel];
  202.          break;
  203.       case GLSL_TYPE_UINT:
  204.          data.u[i] = found->constant->value.u[rhs_channel];
  205.          break;
  206.       case GLSL_TYPE_BOOL:
  207.          data.b[i] = found->constant->value.b[rhs_channel];
  208.          break;
  209.       default:
  210.          assert(!"not reached");
  211.          break;
  212.       }
  213.    }
  214.  
  215.    *rvalue = new(ralloc_parent(deref)) ir_constant(type, &data);
  216.    this->progress = true;
  217. }
  218.  
  219. ir_visitor_status
  220. ir_constant_propagation_visitor::visit_enter(ir_function_signature *ir)
  221. {
  222.    /* Treat entry into a function signature as a completely separate
  223.     * block.  Any instructions at global scope will be shuffled into
  224.     * main() at link time, so they're irrelevant to us.
  225.     */
  226.    exec_list *orig_acp = this->acp;
  227.    exec_list *orig_kills = this->kills;
  228.    bool orig_killed_all = this->killed_all;
  229.  
  230.    this->acp = new(mem_ctx) exec_list;
  231.    this->kills = new(mem_ctx) exec_list;
  232.    this->killed_all = false;
  233.  
  234.    visit_list_elements(this, &ir->body);
  235.  
  236.    this->kills = orig_kills;
  237.    this->acp = orig_acp;
  238.    this->killed_all = orig_killed_all;
  239.  
  240.    return visit_continue_with_parent;
  241. }
  242.  
  243. ir_visitor_status
  244. ir_constant_propagation_visitor::visit_leave(ir_assignment *ir)
  245. {
  246.    if (this->in_assignee)
  247.       return visit_continue;
  248.  
  249.    unsigned kill_mask = ir->write_mask;
  250.    if (ir->lhs->as_dereference_array()) {
  251.       /* The LHS of the assignment uses an array indexing operator (e.g. v[i]
  252.        * = ...;).  Since we only try to constant propagate vectors and
  253.        * scalars, this means that either (a) array indexing is being used to
  254.        * select a vector component, or (b) the variable in question is neither
  255.        * a scalar or a vector, so we don't care about it.  In the former case,
  256.        * we want to kill the whole vector, since in general we can't predict
  257.        * which vector component will be selected by array indexing.  In the
  258.        * latter case, it doesn't matter what we do, so go ahead and kill the
  259.        * whole variable anyway.
  260.        *
  261.        * Note that if the array index is constant (e.g. v[2] = ...;), we could
  262.        * in principle be smarter, but we don't need to, because a future
  263.        * optimization pass will convert it to a simple assignment with the
  264.        * correct mask.
  265.        */
  266.       kill_mask = ~0;
  267.    }
  268.    kill(ir->lhs->variable_referenced(), kill_mask);
  269.  
  270.    add_constant(ir);
  271.  
  272.    return visit_continue;
  273. }
  274.  
  275. ir_visitor_status
  276. ir_constant_propagation_visitor::visit_enter(ir_function *ir)
  277. {
  278.    (void) ir;
  279.    return visit_continue;
  280. }
  281.  
  282. ir_visitor_status
  283. ir_constant_propagation_visitor::visit_enter(ir_call *ir)
  284. {
  285.    /* Do constant propagation on call parameters, but skip any out params */
  286.    foreach_two_lists(formal_node, &ir->callee->parameters,
  287.                      actual_node, &ir->actual_parameters) {
  288.       ir_variable *sig_param = (ir_variable *) formal_node;
  289.       ir_rvalue *param = (ir_rvalue *) actual_node;
  290.       if (sig_param->data.mode != ir_var_function_out
  291.           && sig_param->data.mode != ir_var_function_inout) {
  292.          ir_rvalue *new_param = param;
  293.          handle_rvalue(&new_param);
  294.          if (new_param != param)
  295.             param->replace_with(new_param);
  296.          else
  297.             param->accept(this);
  298.       }
  299.    }
  300.  
  301.    /* Since we're unlinked, we don't (necssarily) know the side effects of
  302.     * this call.  So kill all copies.
  303.     */
  304.    acp->make_empty();
  305.    this->killed_all = true;
  306.  
  307.    return visit_continue_with_parent;
  308. }
  309.  
  310. void
  311. ir_constant_propagation_visitor::handle_if_block(exec_list *instructions)
  312. {
  313.    exec_list *orig_acp = this->acp;
  314.    exec_list *orig_kills = this->kills;
  315.    bool orig_killed_all = this->killed_all;
  316.  
  317.    this->acp = new(mem_ctx) exec_list;
  318.    this->kills = new(mem_ctx) exec_list;
  319.    this->killed_all = false;
  320.  
  321.    /* Populate the initial acp with a constant of the original */
  322.    foreach_in_list(acp_entry, a, orig_acp) {
  323.       this->acp->push_tail(new(this->mem_ctx) acp_entry(a));
  324.    }
  325.  
  326.    visit_list_elements(this, instructions);
  327.  
  328.    if (this->killed_all) {
  329.       orig_acp->make_empty();
  330.    }
  331.  
  332.    exec_list *new_kills = this->kills;
  333.    this->kills = orig_kills;
  334.    this->acp = orig_acp;
  335.    this->killed_all = this->killed_all || orig_killed_all;
  336.  
  337.    foreach_in_list(kill_entry, k, new_kills) {
  338.       kill(k->var, k->write_mask);
  339.    }
  340. }
  341.  
  342. ir_visitor_status
  343. ir_constant_propagation_visitor::visit_enter(ir_if *ir)
  344. {
  345.    ir->condition->accept(this);
  346.    handle_rvalue(&ir->condition);
  347.  
  348.    handle_if_block(&ir->then_instructions);
  349.    handle_if_block(&ir->else_instructions);
  350.  
  351.    /* handle_if_block() already descended into the children. */
  352.    return visit_continue_with_parent;
  353. }
  354.  
  355. ir_visitor_status
  356. ir_constant_propagation_visitor::visit_enter(ir_loop *ir)
  357. {
  358.    exec_list *orig_acp = this->acp;
  359.    exec_list *orig_kills = this->kills;
  360.    bool orig_killed_all = this->killed_all;
  361.  
  362.    /* FINISHME: For now, the initial acp for loops is totally empty.
  363.     * We could go through once, then go through again with the acp
  364.     * cloned minus the killed entries after the first run through.
  365.     */
  366.    this->acp = new(mem_ctx) exec_list;
  367.    this->kills = new(mem_ctx) exec_list;
  368.    this->killed_all = false;
  369.  
  370.    visit_list_elements(this, &ir->body_instructions);
  371.  
  372.    if (this->killed_all) {
  373.       orig_acp->make_empty();
  374.    }
  375.  
  376.    exec_list *new_kills = this->kills;
  377.    this->kills = orig_kills;
  378.    this->acp = orig_acp;
  379.    this->killed_all = this->killed_all || orig_killed_all;
  380.  
  381.    foreach_in_list(kill_entry, k, new_kills) {
  382.       kill(k->var, k->write_mask);
  383.    }
  384.  
  385.    /* already descended into the children. */
  386.    return visit_continue_with_parent;
  387. }
  388.  
  389. void
  390. ir_constant_propagation_visitor::kill(ir_variable *var, unsigned write_mask)
  391. {
  392.    assert(var != NULL);
  393.  
  394.    /* We don't track non-vectors. */
  395.    if (!var->type->is_vector() && !var->type->is_scalar())
  396.       return;
  397.  
  398.    /* Remove any entries currently in the ACP for this kill. */
  399.    foreach_in_list_safe(acp_entry, entry, this->acp) {
  400.       if (entry->var == var) {
  401.          entry->write_mask &= ~write_mask;
  402.          if (entry->write_mask == 0)
  403.             entry->remove();
  404.       }
  405.    }
  406.  
  407.    /* Add this writemask of the variable to the list of killed
  408.     * variables in this block.
  409.     */
  410.    foreach_in_list(kill_entry, entry, this->kills) {
  411.       if (entry->var == var) {
  412.          entry->write_mask |= write_mask;
  413.          return;
  414.       }
  415.    }
  416.    /* Not already in the list.  Make new entry. */
  417.    this->kills->push_tail(new(this->mem_ctx) kill_entry(var, write_mask));
  418. }
  419.  
  420. /**
  421.  * Adds an entry to the available constant list if it's a plain assignment
  422.  * of a variable to a variable.
  423.  */
  424. void
  425. ir_constant_propagation_visitor::add_constant(ir_assignment *ir)
  426. {
  427.    acp_entry *entry;
  428.  
  429.    if (ir->condition)
  430.       return;
  431.  
  432.    if (!ir->write_mask)
  433.       return;
  434.  
  435.    ir_dereference_variable *deref = ir->lhs->as_dereference_variable();
  436.    ir_constant *constant = ir->rhs->as_constant();
  437.  
  438.    if (!deref || !constant)
  439.       return;
  440.  
  441.    /* Only do constant propagation on vectors.  Constant matrices,
  442.     * arrays, or structures would require more work elsewhere.
  443.     */
  444.    if (!deref->var->type->is_vector() && !deref->var->type->is_scalar())
  445.       return;
  446.  
  447.    entry = new(this->mem_ctx) acp_entry(deref->var, ir->write_mask, constant);
  448.    this->acp->push_tail(entry);
  449. }
  450.  
  451. } /* unnamed namespace */
  452.  
  453. /**
  454.  * Does a constant propagation pass on the code present in the instruction stream.
  455.  */
  456. bool
  457. do_constant_propagation(exec_list *instructions)
  458. {
  459.    ir_constant_propagation_visitor v;
  460.  
  461.    visit_list_elements(&v, instructions);
  462.  
  463.    return v.progress;
  464. }
  465.