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.  * 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 lower_discard.cpp
  26.  *
  27.  * This pass moves discards out of if-statements.
  28.  *
  29.  * Case 1: The "then" branch contains a conditional discard:
  30.  * ---------------------------------------------------------
  31.  *
  32.  *    if (cond1) {
  33.  *       s1;
  34.  *       discard cond2;
  35.  *       s2;
  36.  *    } else {
  37.  *       s3;
  38.  *    }
  39.  *
  40.  * becomes:
  41.  *
  42.  *    temp = false;
  43.  *    if (cond1) {
  44.  *       s1;
  45.  *       temp = cond2;
  46.  *       s2;
  47.  *    } else {
  48.  *       s3;
  49.  *    }
  50.  *    discard temp;
  51.  *
  52.  * Case 2: The "else" branch contains a conditional discard:
  53.  * ---------------------------------------------------------
  54.  *
  55.  *    if (cond1) {
  56.  *       s1;
  57.  *    } else {
  58.  *       s2;
  59.  *       discard cond2;
  60.  *       s3;
  61.  *    }
  62.  *
  63.  * becomes:
  64.  *
  65.  *    temp = false;
  66.  *    if (cond1) {
  67.  *       s1;
  68.  *    } else {
  69.  *       s2;
  70.  *       temp = cond2;
  71.  *       s3;
  72.  *    }
  73.  *    discard temp;
  74.  *
  75.  * Case 3: Both branches contain a conditional discard:
  76.  * ----------------------------------------------------
  77.  *
  78.  *    if (cond1) {
  79.  *       s1;
  80.  *       discard cond2;
  81.  *       s2;
  82.  *    } else {
  83.  *       s3;
  84.  *       discard cond3;
  85.  *       s4;
  86.  *    }
  87.  *
  88.  * becomes:
  89.  *
  90.  *    temp = false;
  91.  *    if (cond1) {
  92.  *       s1;
  93.  *       temp = cond2;
  94.  *       s2;
  95.  *    } else {
  96.  *       s3;
  97.  *       temp = cond3;
  98.  *       s4;
  99.  *    }
  100.  *    discard temp;
  101.  *
  102.  * If there are multiple conditional discards, we need only deal with one of
  103.  * them.  Repeatedly applying this pass will take care of the others.
  104.  *
  105.  * Unconditional discards are treated as having a condition of "true".
  106.  */
  107.  
  108. #include "glsl_types.h"
  109. #include "ir.h"
  110.  
  111. class lower_discard_visitor : public ir_hierarchical_visitor {
  112. public:
  113.    lower_discard_visitor()
  114.    {
  115.       this->progress = false;
  116.    }
  117.  
  118.    ir_visitor_status visit_leave(ir_if *);
  119.  
  120.    bool progress;
  121. };
  122.  
  123.  
  124. bool
  125. lower_discard(exec_list *instructions)
  126. {
  127.    lower_discard_visitor v;
  128.  
  129.    visit_list_elements(&v, instructions);
  130.  
  131.    return v.progress;
  132. }
  133.  
  134.  
  135. static ir_discard *
  136. find_discard(exec_list &instructions)
  137. {
  138.    foreach_list(n, &instructions) {
  139.       ir_discard *ir = ((ir_instruction *) n)->as_discard();
  140.       if (ir != NULL)
  141.          return ir;
  142.    }
  143.    return NULL;
  144. }
  145.  
  146.  
  147. static void
  148. replace_discard(void *mem_ctx, ir_variable *var, ir_discard *ir)
  149. {
  150.    ir_rvalue *condition = ir->condition;
  151.  
  152.    /* For unconditional discards, use "true" as the condition. */
  153.    if (condition == NULL)
  154.       condition = new(mem_ctx) ir_constant(true);
  155.  
  156.    ir_assignment *assignment =
  157.       new(mem_ctx) ir_assignment(new(mem_ctx) ir_dereference_variable(var),
  158.                                  condition, NULL);
  159.  
  160.    ir->replace_with(assignment);
  161. }
  162.  
  163.  
  164. ir_visitor_status
  165. lower_discard_visitor::visit_leave(ir_if *ir)
  166. {
  167.    ir_discard *then_discard = find_discard(ir->then_instructions);
  168.    ir_discard *else_discard = find_discard(ir->else_instructions);
  169.  
  170.    if (then_discard == NULL && else_discard == NULL)
  171.       return visit_continue;
  172.  
  173.    void *mem_ctx = ralloc_parent(ir);
  174.  
  175.    ir_variable *temp = new(mem_ctx) ir_variable(glsl_type::bool_type,
  176.                                                 "discard_cond_temp",
  177.                                                 ir_var_temporary);
  178.    ir_assignment *temp_initializer =
  179.       new(mem_ctx) ir_assignment(new(mem_ctx) ir_dereference_variable(temp),
  180.                                  new(mem_ctx) ir_constant(false), NULL);
  181.  
  182.    ir->insert_before(temp);
  183.    ir->insert_before(temp_initializer);
  184.  
  185.    if (then_discard != NULL)
  186.       replace_discard(mem_ctx, temp, then_discard);
  187.  
  188.    if (else_discard != NULL)
  189.       replace_discard(mem_ctx, temp, else_discard);
  190.  
  191.    ir_discard *discard = then_discard != NULL ? then_discard : else_discard;
  192.    discard->condition = new(mem_ctx) ir_dereference_variable(temp);
  193.    ir->insert_after(discard);
  194.  
  195.    this->progress = true;
  196.  
  197.    return visit_continue;
  198. }
  199.