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 opt_dead_code_local.cpp
  26.  *
  27.  * Eliminates local dead assignments from the code.
  28.  *
  29.  * This operates on basic blocks, tracking assignments and finding if
  30.  * they're used before the variable is completely reassigned.
  31.  *
  32.  * Compare this to ir_dead_code.cpp, which operates globally looking
  33.  * for assignments to variables that are never read.
  34.  */
  35.  
  36. #include "ir.h"
  37. #include "ir_basic_block.h"
  38. #include "ir_optimization.h"
  39. #include "glsl_types.h"
  40.  
  41. static bool debug = false;
  42.  
  43. namespace {
  44.  
  45. class assignment_entry : public exec_node
  46. {
  47. public:
  48.    assignment_entry(ir_variable *lhs, ir_assignment *ir)
  49.    {
  50.       assert(lhs);
  51.       assert(ir);
  52.       this->lhs = lhs;
  53.       this->ir = ir;
  54.       this->available = ir->write_mask;
  55.    }
  56.  
  57.    ir_variable *lhs;
  58.    ir_assignment *ir;
  59.  
  60.    /* bitmask of xyzw channels written that haven't been used so far. */
  61.    int available;
  62. };
  63.  
  64. class kill_for_derefs_visitor : public ir_hierarchical_visitor {
  65. public:
  66.    kill_for_derefs_visitor(exec_list *assignments)
  67.    {
  68.       this->assignments = assignments;
  69.    }
  70.  
  71.    void kill_channels(ir_variable *const var, int used)
  72.    {
  73.       foreach_iter(exec_list_iterator, iter, *this->assignments) {
  74.          assignment_entry *entry = (assignment_entry *)iter.get();
  75.  
  76.          if (entry->lhs == var) {
  77.             if (var->type->is_scalar() || var->type->is_vector()) {
  78.                if (debug)
  79.                   printf("kill %s (0x%01x - 0x%01x)\n", entry->lhs->name,
  80.                          entry->available, used);
  81.                entry->available &= ~used;
  82.                if (!entry->available)
  83.                   entry->remove();
  84.             } else {
  85.                if (debug)
  86.                   printf("kill %s\n", entry->lhs->name);
  87.                entry->remove();
  88.             }
  89.          }
  90.       }
  91.    }
  92.  
  93.    virtual ir_visitor_status visit(ir_dereference_variable *ir)
  94.    {
  95.       kill_channels(ir->var, ~0);
  96.  
  97.       return visit_continue;
  98.    }
  99.  
  100.    virtual ir_visitor_status visit(ir_swizzle *ir)
  101.    {
  102.       ir_dereference_variable *deref = ir->val->as_dereference_variable();
  103.       if (!deref)
  104.          return visit_continue;
  105.  
  106.       int used = 0;
  107.       used |= 1 << ir->mask.x;
  108.       used |= 1 << ir->mask.y;
  109.       used |= 1 << ir->mask.z;
  110.       used |= 1 << ir->mask.w;
  111.  
  112.       kill_channels(deref->var, used);
  113.  
  114.       return visit_continue_with_parent;
  115.    }
  116.  
  117. private:
  118.    exec_list *assignments;
  119. };
  120.  
  121. class array_index_visit : public ir_hierarchical_visitor {
  122. public:
  123.    array_index_visit(ir_hierarchical_visitor *v)
  124.    {
  125.       this->visitor = v;
  126.    }
  127.  
  128.    virtual ir_visitor_status visit_enter(class ir_dereference_array *ir)
  129.    {
  130.       ir->array_index->accept(visitor);
  131.       return visit_continue;
  132.    }
  133.  
  134.    static void run(ir_instruction *ir, ir_hierarchical_visitor *v)
  135.    {
  136.       array_index_visit top_visit(v);
  137.       ir->accept(& top_visit);
  138.    }
  139.  
  140.    ir_hierarchical_visitor *visitor;
  141. };
  142.  
  143. } /* unnamed namespace */
  144.  
  145. /**
  146.  * Adds an entry to the available copy list if it's a plain assignment
  147.  * of a variable to a variable.
  148.  */
  149. static bool
  150. process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments)
  151. {
  152.    ir_variable *var = NULL;
  153.    bool progress = false;
  154.    kill_for_derefs_visitor v(assignments);
  155.  
  156.    /* Kill assignment entries for things used to produce this assignment. */
  157.    ir->rhs->accept(&v);
  158.    if (ir->condition) {
  159.       ir->condition->accept(&v);
  160.    }
  161.  
  162.    /* Kill assignment enties used as array indices.
  163.     */
  164.    array_index_visit::run(ir->lhs, &v);
  165.    var = ir->lhs->variable_referenced();
  166.    assert(var);
  167.  
  168.    /* Now, check if we did a whole-variable assignment. */
  169.    if (!ir->condition) {
  170.       ir_dereference_variable *deref_var = ir->lhs->as_dereference_variable();
  171.  
  172.       /* If it's a vector type, we can do per-channel elimination of
  173.        * use of the RHS.
  174.        */
  175.       if (deref_var && (deref_var->var->type->is_scalar() ||
  176.                         deref_var->var->type->is_vector())) {
  177.  
  178.          if (debug)
  179.             printf("looking for %s.0x%01x to remove\n", var->name,
  180.                    ir->write_mask);
  181.  
  182.          foreach_iter(exec_list_iterator, iter, *assignments) {
  183.             assignment_entry *entry = (assignment_entry *)iter.get();
  184.  
  185.             if (entry->lhs != var)
  186.                continue;
  187.  
  188.             int remove = entry->available & ir->write_mask;
  189.             if (debug) {
  190.                printf("%s 0x%01x - 0x%01x = 0x%01x\n",
  191.                       var->name,
  192.                       entry->ir->write_mask,
  193.                       remove, entry->ir->write_mask & ~remove);
  194.             }
  195.             if (remove) {
  196.                progress = true;
  197.  
  198.                if (debug) {
  199.                   printf("rewriting:\n  ");
  200.                   entry->ir->print();
  201.                   printf("\n");
  202.                }
  203.  
  204.                entry->ir->write_mask &= ~remove;
  205.                entry->available &= ~remove;
  206.                if (entry->ir->write_mask == 0) {
  207.                   /* Delete the dead assignment. */
  208.                   entry->ir->remove();
  209.                   entry->remove();
  210.                } else {
  211.                   void *mem_ctx = ralloc_parent(entry->ir);
  212.                   /* Reswizzle the RHS arguments according to the new
  213.                    * write_mask.
  214.                    */
  215.                   unsigned components[4];
  216.                   unsigned channels = 0;
  217.                   unsigned next = 0;
  218.  
  219.                   for (int i = 0; i < 4; i++) {
  220.                      if ((entry->ir->write_mask | remove) & (1 << i)) {
  221.                         if (!(remove & (1 << i)))
  222.                            components[channels++] = next;
  223.                         next++;
  224.                      }
  225.                   }
  226.  
  227.                   entry->ir->rhs = new(mem_ctx) ir_swizzle(entry->ir->rhs,
  228.                                                            components,
  229.                                                            channels);
  230.                   if (debug) {
  231.                      printf("to:\n  ");
  232.                      entry->ir->print();
  233.                      printf("\n");
  234.                   }
  235.                }
  236.             }
  237.          }
  238.       } else if (ir->whole_variable_written() != NULL) {
  239.          /* We did a whole-variable assignment.  So, any instruction in
  240.           * the assignment list with the same LHS is dead.
  241.           */
  242.          if (debug)
  243.             printf("looking for %s to remove\n", var->name);
  244.          foreach_iter(exec_list_iterator, iter, *assignments) {
  245.             assignment_entry *entry = (assignment_entry *)iter.get();
  246.  
  247.             if (entry->lhs == var) {
  248.                if (debug)
  249.                   printf("removing %s\n", var->name);
  250.                entry->ir->remove();
  251.                entry->remove();
  252.                progress = true;
  253.             }
  254.          }
  255.       }
  256.    }
  257.  
  258.    /* Add this instruction to the assignment list available to be removed. */
  259.    assignment_entry *entry = new(ctx) assignment_entry(var, ir);
  260.    assignments->push_tail(entry);
  261.  
  262.    if (debug) {
  263.       printf("add %s\n", var->name);
  264.  
  265.       printf("current entries\n");
  266.       foreach_iter(exec_list_iterator, iter, *assignments) {
  267.          assignment_entry *entry = (assignment_entry *)iter.get();
  268.  
  269.          printf("    %s (0x%01x)\n", entry->lhs->name, entry->available);
  270.       }
  271.    }
  272.  
  273.    return progress;
  274. }
  275.  
  276. static void
  277. dead_code_local_basic_block(ir_instruction *first,
  278.                              ir_instruction *last,
  279.                              void *data)
  280. {
  281.    ir_instruction *ir, *ir_next;
  282.    /* List of avaialble_copy */
  283.    exec_list assignments;
  284.    bool *out_progress = (bool *)data;
  285.    bool progress = false;
  286.  
  287.    void *ctx = ralloc_context(NULL);
  288.    /* Safe looping, since process_assignment */
  289.    for (ir = first, ir_next = (ir_instruction *)first->next;;
  290.         ir = ir_next, ir_next = (ir_instruction *)ir->next) {
  291.       ir_assignment *ir_assign = ir->as_assignment();
  292.  
  293.       if (debug) {
  294.          ir->print();
  295.          printf("\n");
  296.       }
  297.  
  298.       if (ir_assign) {
  299.          progress = process_assignment(ctx, ir_assign, &assignments) || progress;
  300.       } else {
  301.          kill_for_derefs_visitor kill(&assignments);
  302.          ir->accept(&kill);
  303.       }
  304.  
  305.       if (ir == last)
  306.          break;
  307.    }
  308.    *out_progress = progress;
  309.    ralloc_free(ctx);
  310. }
  311.  
  312. /**
  313.  * Does a copy propagation pass on the code present in the instruction stream.
  314.  */
  315. bool
  316. do_dead_code_local(exec_list *instructions)
  317. {
  318.    bool progress = false;
  319.  
  320.    call_for_basic_blocks(instructions, dead_code_local_basic_block, &progress);
  321.  
  322.    return progress;
  323. }
  324.