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_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->unused = 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 unused;
  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 use_channels(ir_variable *const var, int used)
  72.    {
  73.       foreach_in_list_safe(assignment_entry, entry, this->assignments) {
  74.          if (entry->lhs == var) {
  75.             if (var->type->is_scalar() || var->type->is_vector()) {
  76.                if (debug)
  77.                   printf("used %s (0x%01x - 0x%01x)\n", entry->lhs->name,
  78.                          entry->unused, used & 0xf);
  79.                entry->unused &= ~used;
  80.                if (!entry->unused)
  81.                   entry->remove();
  82.             } else {
  83.                if (debug)
  84.                   printf("used %s\n", entry->lhs->name);
  85.                entry->remove();
  86.             }
  87.          }
  88.       }
  89.    }
  90.  
  91.    virtual ir_visitor_status visit(ir_dereference_variable *ir)
  92.    {
  93.       use_channels(ir->var, ~0);
  94.  
  95.       return visit_continue;
  96.    }
  97.  
  98.    virtual ir_visitor_status visit(ir_swizzle *ir)
  99.    {
  100.       ir_dereference_variable *deref = ir->val->as_dereference_variable();
  101.       if (!deref)
  102.          return visit_continue;
  103.  
  104.       int used = 0;
  105.       used |= 1 << ir->mask.x;
  106.       used |= 1 << ir->mask.y;
  107.       used |= 1 << ir->mask.z;
  108.       used |= 1 << ir->mask.w;
  109.  
  110.       use_channels(deref->var, used);
  111.  
  112.       return visit_continue_with_parent;
  113.    }
  114.  
  115.    virtual ir_visitor_status visit_leave(ir_emit_vertex *)
  116.    {
  117.       /* For the purpose of dead code elimination, emitting a vertex counts as
  118.        * "reading" all of the currently assigned output variables.
  119.        */
  120.       foreach_in_list_safe(assignment_entry, entry, this->assignments) {
  121.          if (entry->lhs->data.mode == ir_var_shader_out) {
  122.             if (debug)
  123.                printf("kill %s\n", entry->lhs->name);
  124.             entry->remove();
  125.          }
  126.       }
  127.  
  128.       return visit_continue;
  129.    }
  130.  
  131. private:
  132.    exec_list *assignments;
  133. };
  134.  
  135. class array_index_visit : public ir_hierarchical_visitor {
  136. public:
  137.    array_index_visit(ir_hierarchical_visitor *v)
  138.    {
  139.       this->visitor = v;
  140.    }
  141.  
  142.    virtual ir_visitor_status visit_enter(class ir_dereference_array *ir)
  143.    {
  144.       ir->array_index->accept(visitor);
  145.       return visit_continue;
  146.    }
  147.  
  148.    static void run(ir_instruction *ir, ir_hierarchical_visitor *v)
  149.    {
  150.       array_index_visit top_visit(v);
  151.       ir->accept(& top_visit);
  152.    }
  153.  
  154.    ir_hierarchical_visitor *visitor;
  155. };
  156.  
  157. } /* unnamed namespace */
  158.  
  159. /**
  160.  * Adds an entry to the available copy list if it's a plain assignment
  161.  * of a variable to a variable.
  162.  */
  163. static bool
  164. process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments)
  165. {
  166.    ir_variable *var = NULL;
  167.    bool progress = false;
  168.    kill_for_derefs_visitor v(assignments);
  169.  
  170.    /* Kill assignment entries for things used to produce this assignment. */
  171.    ir->rhs->accept(&v);
  172.    if (ir->condition) {
  173.       ir->condition->accept(&v);
  174.    }
  175.  
  176.    /* Kill assignment enties used as array indices.
  177.     */
  178.    array_index_visit::run(ir->lhs, &v);
  179.    var = ir->lhs->variable_referenced();
  180.    assert(var);
  181.  
  182.    /* Now, check if we did a whole-variable assignment. */
  183.    if (!ir->condition) {
  184.       ir_dereference_variable *deref_var = ir->lhs->as_dereference_variable();
  185.  
  186.       /* If it's a vector type, we can do per-channel elimination of
  187.        * use of the RHS.
  188.        */
  189.       if (deref_var && (deref_var->var->type->is_scalar() ||
  190.                         deref_var->var->type->is_vector())) {
  191.  
  192.          if (debug)
  193.             printf("looking for %s.0x%01x to remove\n", var->name,
  194.                    ir->write_mask);
  195.  
  196.          foreach_in_list_safe(assignment_entry, entry, assignments) {
  197.             if (entry->lhs != var)
  198.                continue;
  199.  
  200.             int remove = entry->unused & ir->write_mask;
  201.             if (debug) {
  202.                printf("%s 0x%01x - 0x%01x = 0x%01x\n",
  203.                       var->name,
  204.                       entry->ir->write_mask,
  205.                       remove, entry->ir->write_mask & ~remove);
  206.             }
  207.             if (remove) {
  208.                progress = true;
  209.  
  210.                if (debug) {
  211.                   printf("rewriting:\n  ");
  212.                   entry->ir->print();
  213.                   printf("\n");
  214.                }
  215.  
  216.                entry->ir->write_mask &= ~remove;
  217.                entry->unused &= ~remove;
  218.                if (entry->ir->write_mask == 0) {
  219.                   /* Delete the dead assignment. */
  220.                   entry->ir->remove();
  221.                   entry->remove();
  222.                } else {
  223.                   void *mem_ctx = ralloc_parent(entry->ir);
  224.                   /* Reswizzle the RHS arguments according to the new
  225.                    * write_mask.
  226.                    */
  227.                   unsigned components[4];
  228.                   unsigned channels = 0;
  229.                   unsigned next = 0;
  230.  
  231.                   for (int i = 0; i < 4; i++) {
  232.                      if ((entry->ir->write_mask | remove) & (1 << i)) {
  233.                         if (!(remove & (1 << i)))
  234.                            components[channels++] = next;
  235.                         next++;
  236.                      }
  237.                   }
  238.  
  239.                   entry->ir->rhs = new(mem_ctx) ir_swizzle(entry->ir->rhs,
  240.                                                            components,
  241.                                                            channels);
  242.                   if (debug) {
  243.                      printf("to:\n  ");
  244.                      entry->ir->print();
  245.                      printf("\n");
  246.                   }
  247.                }
  248.             }
  249.          }
  250.       } else if (ir->whole_variable_written() != NULL) {
  251.          /* We did a whole-variable assignment.  So, any instruction in
  252.           * the assignment list with the same LHS is dead.
  253.           */
  254.          if (debug)
  255.             printf("looking for %s to remove\n", var->name);
  256.          foreach_in_list_safe(assignment_entry, entry, assignments) {
  257.             if (entry->lhs == var) {
  258.                if (debug)
  259.                   printf("removing %s\n", var->name);
  260.                entry->ir->remove();
  261.                entry->remove();
  262.                progress = true;
  263.             }
  264.          }
  265.       }
  266.    }
  267.  
  268.    /* Add this instruction to the assignment list available to be removed. */
  269.    assignment_entry *entry = new(ctx) assignment_entry(var, ir);
  270.    assignments->push_tail(entry);
  271.  
  272.    if (debug) {
  273.       printf("add %s\n", var->name);
  274.  
  275.       printf("current entries\n");
  276.       foreach_in_list(assignment_entry, entry, assignments) {
  277.          printf("    %s (0x%01x)\n", entry->lhs->name, entry->unused);
  278.       }
  279.    }
  280.  
  281.    return progress;
  282. }
  283.  
  284. static void
  285. dead_code_local_basic_block(ir_instruction *first,
  286.                              ir_instruction *last,
  287.                              void *data)
  288. {
  289.    ir_instruction *ir, *ir_next;
  290.    /* List of avaialble_copy */
  291.    exec_list assignments;
  292.    bool *out_progress = (bool *)data;
  293.    bool progress = false;
  294.  
  295.    void *ctx = ralloc_context(NULL);
  296.    /* Safe looping, since process_assignment */
  297.    for (ir = first, ir_next = (ir_instruction *)first->next;;
  298.         ir = ir_next, ir_next = (ir_instruction *)ir->next) {
  299.       ir_assignment *ir_assign = ir->as_assignment();
  300.  
  301.       if (debug) {
  302.          ir->print();
  303.          printf("\n");
  304.       }
  305.  
  306.       if (ir_assign) {
  307.          progress = process_assignment(ctx, ir_assign, &assignments) || progress;
  308.       } else {
  309.          kill_for_derefs_visitor kill(&assignments);
  310.          ir->accept(&kill);
  311.       }
  312.  
  313.       if (ir == last)
  314.          break;
  315.    }
  316.    *out_progress = progress;
  317.    ralloc_free(ctx);
  318. }
  319.  
  320. /**
  321.  * Does a copy propagation pass on the code present in the instruction stream.
  322.  */
  323. bool
  324. do_dead_code_local(exec_list *instructions)
  325. {
  326.    bool progress = false;
  327.  
  328.    call_for_basic_blocks(instructions, dead_code_local_basic_block, &progress);
  329.  
  330.    return progress;
  331. }
  332.