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 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. namespace {
  112.  
  113. class lower_discard_visitor : public ir_hierarchical_visitor {
  114. public:
  115.    lower_discard_visitor()
  116.    {
  117.       this->progress = false;
  118.    }
  119.  
  120.    ir_visitor_status visit_leave(ir_if *);
  121.  
  122.    bool progress;
  123. };
  124.  
  125. } /* anonymous namespace */
  126.  
  127. bool
  128. lower_discard(exec_list *instructions)
  129. {
  130.    lower_discard_visitor v;
  131.  
  132.    visit_list_elements(&v, instructions);
  133.  
  134.    return v.progress;
  135. }
  136.  
  137.  
  138. static ir_discard *
  139. find_discard(exec_list &instructions)
  140. {
  141.    foreach_in_list(ir_instruction, node, &instructions) {
  142.       ir_discard *ir = node->as_discard();
  143.       if (ir != NULL)
  144.          return ir;
  145.    }
  146.    return NULL;
  147. }
  148.  
  149.  
  150. static void
  151. replace_discard(void *mem_ctx, ir_variable *var, ir_discard *ir)
  152. {
  153.    ir_rvalue *condition = ir->condition;
  154.  
  155.    /* For unconditional discards, use "true" as the condition. */
  156.    if (condition == NULL)
  157.       condition = new(mem_ctx) ir_constant(true);
  158.  
  159.    ir_assignment *assignment =
  160.       new(mem_ctx) ir_assignment(new(mem_ctx) ir_dereference_variable(var),
  161.                                  condition, NULL);
  162.  
  163.    ir->replace_with(assignment);
  164. }
  165.  
  166.  
  167. ir_visitor_status
  168. lower_discard_visitor::visit_leave(ir_if *ir)
  169. {
  170.    ir_discard *then_discard = find_discard(ir->then_instructions);
  171.    ir_discard *else_discard = find_discard(ir->else_instructions);
  172.  
  173.    if (then_discard == NULL && else_discard == NULL)
  174.       return visit_continue;
  175.  
  176.    void *mem_ctx = ralloc_parent(ir);
  177.  
  178.    ir_variable *temp = new(mem_ctx) ir_variable(glsl_type::bool_type,
  179.                                                 "discard_cond_temp",
  180.                                                 ir_var_temporary);
  181.    ir_assignment *temp_initializer =
  182.       new(mem_ctx) ir_assignment(new(mem_ctx) ir_dereference_variable(temp),
  183.                                  new(mem_ctx) ir_constant(false), NULL);
  184.  
  185.    ir->insert_before(temp);
  186.    ir->insert_before(temp_initializer);
  187.  
  188.    if (then_discard != NULL)
  189.       replace_discard(mem_ctx, temp, then_discard);
  190.  
  191.    if (else_discard != NULL)
  192.       replace_discard(mem_ctx, temp, else_discard);
  193.  
  194.    ir_discard *discard = then_discard != NULL ? then_discard : else_discard;
  195.    discard->condition = new(mem_ctx) ir_dereference_variable(temp);
  196.    ir->insert_after(discard);
  197.  
  198.    this->progress = true;
  199.  
  200.    return visit_continue;
  201. }
  202.