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 opt_copy_propagation.cpp
  26.  *
  27.  * Moves usage of recently-copied variables to the previous copy of
  28.  * the variable.
  29.  *
  30.  * This should reduce the number of MOV instructions in the generated
  31.  * programs unless copy propagation is also done on the LIR, and may
  32.  * help anyway by triggering other optimizations that live in the HIR.
  33.  */
  34.  
  35. #include "ir.h"
  36. #include "ir_visitor.h"
  37. #include "ir_basic_block.h"
  38. #include "ir_optimization.h"
  39. #include "glsl_types.h"
  40.  
  41. namespace {
  42.  
  43. class acp_entry : public exec_node
  44. {
  45. public:
  46.    acp_entry(ir_variable *lhs, ir_variable *rhs)
  47.    {
  48.       assert(lhs);
  49.       assert(rhs);
  50.       this->lhs = lhs;
  51.       this->rhs = rhs;
  52.    }
  53.  
  54.    ir_variable *lhs;
  55.    ir_variable *rhs;
  56. };
  57.  
  58.  
  59. class kill_entry : public exec_node
  60. {
  61. public:
  62.    kill_entry(ir_variable *var)
  63.    {
  64.       assert(var);
  65.       this->var = var;
  66.    }
  67.  
  68.    ir_variable *var;
  69. };
  70.  
  71. class ir_copy_propagation_visitor : public ir_hierarchical_visitor {
  72. public:
  73.    ir_copy_propagation_visitor()
  74.    {
  75.       progress = false;
  76.       mem_ctx = ralloc_context(0);
  77.       this->acp = new(mem_ctx) exec_list;
  78.       this->kills = new(mem_ctx) exec_list;
  79.    }
  80.    ~ir_copy_propagation_visitor()
  81.    {
  82.       ralloc_free(mem_ctx);
  83.    }
  84.  
  85.    virtual ir_visitor_status visit(class ir_dereference_variable *);
  86.    virtual ir_visitor_status visit_enter(class ir_loop *);
  87.    virtual ir_visitor_status visit_enter(class ir_function_signature *);
  88.    virtual ir_visitor_status visit_enter(class ir_function *);
  89.    virtual ir_visitor_status visit_leave(class ir_assignment *);
  90.    virtual ir_visitor_status visit_enter(class ir_call *);
  91.    virtual ir_visitor_status visit_enter(class ir_if *);
  92.  
  93.    void add_copy(ir_assignment *ir);
  94.    void kill(ir_variable *ir);
  95.    void handle_if_block(exec_list *instructions);
  96.  
  97.    /** List of acp_entry: The available copies to propagate */
  98.    exec_list *acp;
  99.    /**
  100.     * List of kill_entry: The variables whose values were killed in this
  101.     * block.
  102.     */
  103.    exec_list *kills;
  104.  
  105.    bool progress;
  106.  
  107.    bool killed_all;
  108.  
  109.    void *mem_ctx;
  110. };
  111.  
  112. } /* unnamed namespace */
  113.  
  114. ir_visitor_status
  115. ir_copy_propagation_visitor::visit_enter(ir_function_signature *ir)
  116. {
  117.    /* Treat entry into a function signature as a completely separate
  118.     * block.  Any instructions at global scope will be shuffled into
  119.     * main() at link time, so they're irrelevant to us.
  120.     */
  121.    exec_list *orig_acp = this->acp;
  122.    exec_list *orig_kills = this->kills;
  123.    bool orig_killed_all = this->killed_all;
  124.  
  125.    this->acp = new(mem_ctx) exec_list;
  126.    this->kills = new(mem_ctx) exec_list;
  127.    this->killed_all = false;
  128.  
  129.    visit_list_elements(this, &ir->body);
  130.  
  131.    ralloc_free(this->acp);
  132.    ralloc_free(this->kills);
  133.  
  134.    this->kills = orig_kills;
  135.    this->acp = orig_acp;
  136.    this->killed_all = orig_killed_all;
  137.  
  138.    return visit_continue_with_parent;
  139. }
  140.  
  141. ir_visitor_status
  142. ir_copy_propagation_visitor::visit_leave(ir_assignment *ir)
  143. {
  144.    kill(ir->lhs->variable_referenced());
  145.  
  146.    add_copy(ir);
  147.  
  148.    return visit_continue;
  149. }
  150.  
  151. ir_visitor_status
  152. ir_copy_propagation_visitor::visit_enter(ir_function *ir)
  153. {
  154.    (void) ir;
  155.    return visit_continue;
  156. }
  157.  
  158. /**
  159.  * Replaces dereferences of ACP RHS variables with ACP LHS variables.
  160.  *
  161.  * This is where the actual copy propagation occurs.  Note that the
  162.  * rewriting of ir_dereference means that the ir_dereference instance
  163.  * must not be shared by multiple IR operations!
  164.  */
  165. ir_visitor_status
  166. ir_copy_propagation_visitor::visit(ir_dereference_variable *ir)
  167. {
  168.    if (this->in_assignee)
  169.       return visit_continue;
  170.  
  171.    ir_variable *var = ir->var;
  172.  
  173.    foreach_in_list(acp_entry, entry, this->acp) {
  174.       if (var == entry->lhs) {
  175.          ir->var = entry->rhs;
  176.          this->progress = true;
  177.          break;
  178.       }
  179.    }
  180.  
  181.    return visit_continue;
  182. }
  183.  
  184.  
  185. ir_visitor_status
  186. ir_copy_propagation_visitor::visit_enter(ir_call *ir)
  187. {
  188.    /* Do copy propagation on call parameters, but skip any out params */
  189.    foreach_two_lists(formal_node, &ir->callee->parameters,
  190.                      actual_node, &ir->actual_parameters) {
  191.       ir_variable *sig_param = (ir_variable *) formal_node;
  192.       ir_rvalue *ir = (ir_rvalue *) actual_node;
  193.       if (sig_param->data.mode != ir_var_function_out
  194.           && sig_param->data.mode != ir_var_function_inout) {
  195.          ir->accept(this);
  196.       }
  197.    }
  198.  
  199.    /* Since we're unlinked, we don't (necessarily) know the side effects of
  200.     * this call.  So kill all copies.
  201.     */
  202.    acp->make_empty();
  203.    this->killed_all = true;
  204.  
  205.    return visit_continue_with_parent;
  206. }
  207.  
  208. void
  209. ir_copy_propagation_visitor::handle_if_block(exec_list *instructions)
  210. {
  211.    exec_list *orig_acp = this->acp;
  212.    exec_list *orig_kills = this->kills;
  213.    bool orig_killed_all = this->killed_all;
  214.  
  215.    this->acp = new(mem_ctx) exec_list;
  216.    this->kills = new(mem_ctx) exec_list;
  217.    this->killed_all = false;
  218.  
  219.    /* Populate the initial acp with a copy of the original */
  220.    foreach_in_list(acp_entry, a, orig_acp) {
  221.       this->acp->push_tail(new(this->acp) acp_entry(a->lhs, a->rhs));
  222.    }
  223.  
  224.    visit_list_elements(this, instructions);
  225.  
  226.    if (this->killed_all) {
  227.       orig_acp->make_empty();
  228.    }
  229.  
  230.    exec_list *new_kills = this->kills;
  231.    this->kills = orig_kills;
  232.    ralloc_free(this->acp);
  233.    this->acp = orig_acp;
  234.    this->killed_all = this->killed_all || orig_killed_all;
  235.  
  236.    foreach_in_list(kill_entry, k, new_kills) {
  237.       kill(k->var);
  238.    }
  239.  
  240.    ralloc_free(new_kills);
  241. }
  242.  
  243. ir_visitor_status
  244. ir_copy_propagation_visitor::visit_enter(ir_if *ir)
  245. {
  246.    ir->condition->accept(this);
  247.  
  248.    handle_if_block(&ir->then_instructions);
  249.    handle_if_block(&ir->else_instructions);
  250.  
  251.    /* handle_if_block() already descended into the children. */
  252.    return visit_continue_with_parent;
  253. }
  254.  
  255. ir_visitor_status
  256. ir_copy_propagation_visitor::visit_enter(ir_loop *ir)
  257. {
  258.    exec_list *orig_acp = this->acp;
  259.    exec_list *orig_kills = this->kills;
  260.    bool orig_killed_all = this->killed_all;
  261.  
  262.    /* FINISHME: For now, the initial acp for loops is totally empty.
  263.     * We could go through once, then go through again with the acp
  264.     * cloned minus the killed entries after the first run through.
  265.     */
  266.    this->acp = new(mem_ctx) exec_list;
  267.    this->kills = new(mem_ctx) exec_list;
  268.    this->killed_all = false;
  269.  
  270.    visit_list_elements(this, &ir->body_instructions);
  271.  
  272.    if (this->killed_all) {
  273.       orig_acp->make_empty();
  274.    }
  275.  
  276.    exec_list *new_kills = this->kills;
  277.    this->kills = orig_kills;
  278.    ralloc_free(this->acp);
  279.    this->acp = orig_acp;
  280.    this->killed_all = this->killed_all || orig_killed_all;
  281.  
  282.    foreach_in_list(kill_entry, k, new_kills) {
  283.       kill(k->var);
  284.    }
  285.  
  286.    ralloc_free(new_kills);
  287.  
  288.    /* already descended into the children. */
  289.    return visit_continue_with_parent;
  290. }
  291.  
  292. void
  293. ir_copy_propagation_visitor::kill(ir_variable *var)
  294. {
  295.    assert(var != NULL);
  296.  
  297.    /* Remove any entries currently in the ACP for this kill. */
  298.    foreach_in_list_safe(acp_entry, entry, acp) {
  299.       if (entry->lhs == var || entry->rhs == var) {
  300.          entry->remove();
  301.       }
  302.    }
  303.  
  304.    /* Add the LHS variable to the list of killed variables in this block.
  305.     */
  306.    this->kills->push_tail(new(this->kills) kill_entry(var));
  307. }
  308.  
  309. /**
  310.  * Adds an entry to the available copy list if it's a plain assignment
  311.  * of a variable to a variable.
  312.  */
  313. void
  314. ir_copy_propagation_visitor::add_copy(ir_assignment *ir)
  315. {
  316.    acp_entry *entry;
  317.  
  318.    if (ir->condition)
  319.       return;
  320.  
  321.    ir_variable *lhs_var = ir->whole_variable_written();
  322.    ir_variable *rhs_var = ir->rhs->whole_variable_referenced();
  323.  
  324.    if ((lhs_var != NULL) && (rhs_var != NULL)) {
  325.       if (lhs_var == rhs_var) {
  326.          /* This is a dumb assignment, but we've conveniently noticed
  327.           * it here.  Removing it now would mess up the loop iteration
  328.           * calling us.  Just flag it to not execute, and someone else
  329.           * will clean up the mess.
  330.           */
  331.          ir->condition = new(ralloc_parent(ir)) ir_constant(false);
  332.          this->progress = true;
  333.       } else {
  334.          entry = new(this->acp) acp_entry(lhs_var, rhs_var);
  335.          this->acp->push_tail(entry);
  336.       }
  337.    }
  338. }
  339.  
  340. /**
  341.  * Does a copy propagation pass on the code present in the instruction stream.
  342.  */
  343. bool
  344. do_copy_propagation(exec_list *instructions)
  345. {
  346.    ir_copy_propagation_visitor v;
  347.  
  348.    visit_list_elements(&v, instructions);
  349.  
  350.    return v.progress;
  351. }
  352.