Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | 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. class acp_entry : public exec_node
  45. {
  46. public:
  47.    acp_entry(ir_variable *var, unsigned write_mask, ir_constant *constant)
  48.    {
  49.       assert(var);
  50.       assert(constant);
  51.       this->var = var;
  52.       this->write_mask = write_mask;
  53.       this->constant = constant;
  54.    }
  55.  
  56.    ir_variable *var;
  57.    ir_constant *constant;
  58.    unsigned write_mask;
  59. };
  60.  
  61.  
  62. class kill_entry : public exec_node
  63. {
  64. public:
  65.    kill_entry(ir_variable *var, unsigned write_mask)
  66.    {
  67.       assert(var);
  68.       this->var = var;
  69.       this->write_mask = write_mask;
  70.    }
  71.  
  72.    ir_variable *var;
  73.    unsigned write_mask;
  74. };
  75.  
  76. class ir_constant_propagation_visitor : public ir_rvalue_visitor {
  77. public:
  78.    ir_constant_propagation_visitor()
  79.    {
  80.       progress = false;
  81.       mem_ctx = ralloc_context(0);
  82.       this->acp = new(mem_ctx) exec_list;
  83.       this->kills = new(mem_ctx) exec_list;
  84.    }
  85.    ~ir_constant_propagation_visitor()
  86.    {
  87.       ralloc_free(mem_ctx);
  88.    }
  89.  
  90.    virtual ir_visitor_status visit_enter(class ir_loop *);
  91.    virtual ir_visitor_status visit_enter(class ir_function_signature *);
  92.    virtual ir_visitor_status visit_enter(class ir_function *);
  93.    virtual ir_visitor_status visit_leave(class ir_assignment *);
  94.    virtual ir_visitor_status visit_enter(class ir_call *);
  95.    virtual ir_visitor_status visit_enter(class ir_if *);
  96.  
  97.    void add_constant(ir_assignment *ir);
  98.    void kill(ir_variable *ir, unsigned write_mask);
  99.    void handle_if_block(exec_list *instructions);
  100.    void handle_rvalue(ir_rvalue **rvalue);
  101.  
  102.    /** List of acp_entry: The available constants to propagate */
  103.    exec_list *acp;
  104.  
  105.    /**
  106.     * List of kill_entry: The masks of variables whose values were
  107.     * killed in this block.
  108.     */
  109.    exec_list *kills;
  110.  
  111.    bool progress;
  112.  
  113.    bool killed_all;
  114.  
  115.    void *mem_ctx;
  116. };
  117.  
  118.  
  119. void
  120. ir_constant_propagation_visitor::handle_rvalue(ir_rvalue **rvalue)
  121. {
  122.    if (this->in_assignee || !*rvalue)
  123.       return;
  124.  
  125.    const glsl_type *type = (*rvalue)->type;
  126.    if (!type->is_scalar() && !type->is_vector())
  127.       return;
  128.  
  129.    ir_swizzle *swiz = NULL;
  130.    ir_dereference_variable *deref = (*rvalue)->as_dereference_variable();
  131.    if (!deref) {
  132.       swiz = (*rvalue)->as_swizzle();
  133.       if (!swiz)
  134.          return;
  135.  
  136.       deref = swiz->val->as_dereference_variable();
  137.       if (!deref)
  138.          return;
  139.    }
  140.  
  141.    ir_constant_data data;
  142.    memset(&data, 0, sizeof(data));
  143.  
  144.    for (unsigned int i = 0; i < type->components(); i++) {
  145.       int channel;
  146.       acp_entry *found = NULL;
  147.  
  148.       if (swiz) {
  149.          switch (i) {
  150.          case 0: channel = swiz->mask.x; break;
  151.          case 1: channel = swiz->mask.y; break;
  152.          case 2: channel = swiz->mask.z; break;
  153.          case 3: channel = swiz->mask.w; break;
  154.          default: assert(!"shouldn't be reached"); channel = 0; break;
  155.          }
  156.       } else {
  157.          channel = i;
  158.       }
  159.  
  160.       foreach_iter(exec_list_iterator, iter, *this->acp) {
  161.          acp_entry *entry = (acp_entry *)iter.get();
  162.          if (entry->var == deref->var && entry->write_mask & (1 << channel)) {
  163.             found = entry;
  164.             break;
  165.          }
  166.       }
  167.  
  168.       if (!found)
  169.          return;
  170.  
  171.       int rhs_channel = 0;
  172.       for (int j = 0; j < 4; j++) {
  173.          if (j == channel)
  174.             break;
  175.          if (found->write_mask & (1 << j))
  176.             rhs_channel++;
  177.       }
  178.  
  179.       switch (type->base_type) {
  180.       case GLSL_TYPE_FLOAT:
  181.          data.f[i] = found->constant->value.f[rhs_channel];
  182.          break;
  183.       case GLSL_TYPE_INT:
  184.          data.i[i] = found->constant->value.i[rhs_channel];
  185.          break;
  186.       case GLSL_TYPE_UINT:
  187.          data.u[i] = found->constant->value.u[rhs_channel];
  188.          break;
  189.       case GLSL_TYPE_BOOL:
  190.          data.b[i] = found->constant->value.b[rhs_channel];
  191.          break;
  192.       default:
  193.          assert(!"not reached");
  194.          break;
  195.       }
  196.    }
  197.  
  198.    *rvalue = new(ralloc_parent(deref)) ir_constant(type, &data);
  199.    this->progress = true;
  200. }
  201.  
  202. ir_visitor_status
  203. ir_constant_propagation_visitor::visit_enter(ir_function_signature *ir)
  204. {
  205.    /* Treat entry into a function signature as a completely separate
  206.     * block.  Any instructions at global scope will be shuffled into
  207.     * main() at link time, so they're irrelevant to us.
  208.     */
  209.    exec_list *orig_acp = this->acp;
  210.    exec_list *orig_kills = this->kills;
  211.    bool orig_killed_all = this->killed_all;
  212.  
  213.    this->acp = new(mem_ctx) exec_list;
  214.    this->kills = new(mem_ctx) exec_list;
  215.    this->killed_all = false;
  216.  
  217.    visit_list_elements(this, &ir->body);
  218.  
  219.    this->kills = orig_kills;
  220.    this->acp = orig_acp;
  221.    this->killed_all = orig_killed_all;
  222.  
  223.    return visit_continue_with_parent;
  224. }
  225.  
  226. ir_visitor_status
  227. ir_constant_propagation_visitor::visit_leave(ir_assignment *ir)
  228. {
  229.    if (this->in_assignee)
  230.       return visit_continue;
  231.  
  232.    kill(ir->lhs->variable_referenced(), ir->write_mask);
  233.  
  234.    add_constant(ir);
  235.  
  236.    return visit_continue;
  237. }
  238.  
  239. ir_visitor_status
  240. ir_constant_propagation_visitor::visit_enter(ir_function *ir)
  241. {
  242.    (void) ir;
  243.    return visit_continue;
  244. }
  245.  
  246. ir_visitor_status
  247. ir_constant_propagation_visitor::visit_enter(ir_call *ir)
  248. {
  249.    /* Do constant propagation on call parameters, but skip any out params */
  250.    exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator();
  251.    foreach_iter(exec_list_iterator, iter, ir->actual_parameters) {
  252.       ir_variable *sig_param = (ir_variable *)sig_param_iter.get();
  253.       ir_rvalue *param = (ir_rvalue *)iter.get();
  254.       if (sig_param->mode != ir_var_out && sig_param->mode != ir_var_inout) {
  255.          ir_rvalue *new_param = param;
  256.          handle_rvalue(&new_param);
  257.          if (new_param != param)
  258.             param->replace_with(new_param);
  259.          else
  260.             param->accept(this);
  261.       }
  262.       sig_param_iter.next();
  263.    }
  264.  
  265.    /* Since we're unlinked, we don't (necssarily) know the side effects of
  266.     * this call.  So kill all copies.
  267.     */
  268.    acp->make_empty();
  269.    this->killed_all = true;
  270.  
  271.    return visit_continue_with_parent;
  272. }
  273.  
  274. void
  275. ir_constant_propagation_visitor::handle_if_block(exec_list *instructions)
  276. {
  277.    exec_list *orig_acp = this->acp;
  278.    exec_list *orig_kills = this->kills;
  279.    bool orig_killed_all = this->killed_all;
  280.  
  281.    this->acp = new(mem_ctx) exec_list;
  282.    this->kills = new(mem_ctx) exec_list;
  283.    this->killed_all = false;
  284.  
  285.    /* Populate the initial acp with a constant of the original */
  286.    foreach_iter(exec_list_iterator, iter, *orig_acp) {
  287.       acp_entry *a = (acp_entry *)iter.get();
  288.       this->acp->push_tail(new(this->mem_ctx) acp_entry(a->var, a->write_mask,
  289.                                                         a->constant));
  290.    }
  291.  
  292.    visit_list_elements(this, instructions);
  293.  
  294.    if (this->killed_all) {
  295.       orig_acp->make_empty();
  296.    }
  297.  
  298.    exec_list *new_kills = this->kills;
  299.    this->kills = orig_kills;
  300.    this->acp = orig_acp;
  301.    this->killed_all = this->killed_all || orig_killed_all;
  302.  
  303.    foreach_iter(exec_list_iterator, iter, *new_kills) {
  304.       kill_entry *k = (kill_entry *)iter.get();
  305.       kill(k->var, k->write_mask);
  306.    }
  307. }
  308.  
  309. ir_visitor_status
  310. ir_constant_propagation_visitor::visit_enter(ir_if *ir)
  311. {
  312.    ir->condition->accept(this);
  313.    handle_rvalue(&ir->condition);
  314.  
  315.    handle_if_block(&ir->then_instructions);
  316.    handle_if_block(&ir->else_instructions);
  317.  
  318.    /* handle_if_block() already descended into the children. */
  319.    return visit_continue_with_parent;
  320. }
  321.  
  322. ir_visitor_status
  323. ir_constant_propagation_visitor::visit_enter(ir_loop *ir)
  324. {
  325.    exec_list *orig_acp = this->acp;
  326.    exec_list *orig_kills = this->kills;
  327.    bool orig_killed_all = this->killed_all;
  328.  
  329.    /* FINISHME: For now, the initial acp for loops is totally empty.
  330.     * We could go through once, then go through again with the acp
  331.     * cloned minus the killed entries after the first run through.
  332.     */
  333.    this->acp = new(mem_ctx) exec_list;
  334.    this->kills = new(mem_ctx) exec_list;
  335.    this->killed_all = false;
  336.  
  337.    visit_list_elements(this, &ir->body_instructions);
  338.  
  339.    if (this->killed_all) {
  340.       orig_acp->make_empty();
  341.    }
  342.  
  343.    exec_list *new_kills = this->kills;
  344.    this->kills = orig_kills;
  345.    this->acp = orig_acp;
  346.    this->killed_all = this->killed_all || orig_killed_all;
  347.  
  348.    foreach_iter(exec_list_iterator, iter, *new_kills) {
  349.       kill_entry *k = (kill_entry *)iter.get();
  350.       kill(k->var, k->write_mask);
  351.    }
  352.  
  353.    /* already descended into the children. */
  354.    return visit_continue_with_parent;
  355. }
  356.  
  357. void
  358. ir_constant_propagation_visitor::kill(ir_variable *var, unsigned write_mask)
  359. {
  360.    assert(var != NULL);
  361.  
  362.    /* We don't track non-vectors. */
  363.    if (!var->type->is_vector() && !var->type->is_scalar())
  364.       return;
  365.  
  366.    /* Remove any entries currently in the ACP for this kill. */
  367.    foreach_iter(exec_list_iterator, iter, *this->acp) {
  368.       acp_entry *entry = (acp_entry *)iter.get();
  369.  
  370.       if (entry->var == var) {
  371.          entry->write_mask &= ~write_mask;
  372.          if (entry->write_mask == 0)
  373.             entry->remove();
  374.       }
  375.    }
  376.  
  377.    /* Add this writemask of the variable to the list of killed
  378.     * variables in this block.
  379.     */
  380.    foreach_iter(exec_list_iterator, iter, *this->kills) {
  381.       kill_entry *entry = (kill_entry *)iter.get();
  382.  
  383.       if (entry->var == var) {
  384.          entry->write_mask |= write_mask;
  385.          return;
  386.       }
  387.    }
  388.    /* Not already in the list.  Make new entry. */
  389.    this->kills->push_tail(new(this->mem_ctx) kill_entry(var, write_mask));
  390. }
  391.  
  392. /**
  393.  * Adds an entry to the available constant list if it's a plain assignment
  394.  * of a variable to a variable.
  395.  */
  396. void
  397. ir_constant_propagation_visitor::add_constant(ir_assignment *ir)
  398. {
  399.    acp_entry *entry;
  400.  
  401.    if (ir->condition) {
  402.       ir_constant *condition = ir->condition->as_constant();
  403.       if (!condition || !condition->value.b[0])
  404.          return;
  405.    }
  406.  
  407.    if (!ir->write_mask)
  408.       return;
  409.  
  410.    ir_dereference_variable *deref = ir->lhs->as_dereference_variable();
  411.    ir_constant *constant = ir->rhs->as_constant();
  412.  
  413.    if (!deref || !constant)
  414.       return;
  415.  
  416.    /* Only do constant propagation on vectors.  Constant matrices,
  417.     * arrays, or structures would require more work elsewhere.
  418.     */
  419.    if (!deref->var->type->is_vector() && !deref->var->type->is_scalar())
  420.       return;
  421.  
  422.    entry = new(this->mem_ctx) acp_entry(deref->var, ir->write_mask, constant);
  423.    this->acp->push_tail(entry);
  424. }
  425.  
  426. /**
  427.  * Does a constant propagation pass on the code present in the instruction stream.
  428.  */
  429. bool
  430. do_constant_propagation(exec_list *instructions)
  431. {
  432.    ir_constant_propagation_visitor v;
  433.  
  434.    visit_list_elements(&v, instructions);
  435.  
  436.    return v.progress;
  437. }
  438.