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 opt_discard_simplification.cpp
  26.  *
  27.  * This pass simplifies if-statements and loops containing unconditional
  28.  * discards.
  29.  *
  30.  * Case 1: Both branches contain unconditional discards:
  31.  * -----------------------------------------------------
  32.  *
  33.  *    if (cond) {
  34.  *       s1;
  35.  *       discard;
  36.  *       s2;
  37.  *    } else {
  38.  *       s3;
  39.  *       discard;
  40.  *       s4;
  41.  *    }
  42.  *
  43.  * becomes:
  44.  *
  45.  *    discard
  46.  *
  47.  * Case 2: The "then" clause contains an unconditional discard:
  48.  * ------------------------------------------------------------
  49.  *
  50.  *    if (cond) {
  51.  *       s1;
  52.  *       discard;
  53.  *       s2;
  54.  *    } else {
  55.  *       s3;
  56.  *    }
  57.  *
  58.  * becomes:
  59.  *
  60.  *    if (cond) {
  61.  *       discard;
  62.  *    } else {
  63.  *       s3;
  64.  *    }
  65.  *
  66.  * Case 3: The "else" clause contains an unconditional discard:
  67.  * ------------------------------------------------------------
  68.  *
  69.  *    if (cond) {
  70.  *       s1;
  71.  *    } else {
  72.  *       s2;
  73.  *       discard;
  74.  *       s3;
  75.  *    }
  76.  *
  77.  * becomes:
  78.  *
  79.  *    if (cond) {
  80.  *       s1;
  81.  *    } else {
  82.  *       discard;
  83.  *    }
  84.  */
  85.  
  86. #include "glsl_types.h"
  87. #include "ir.h"
  88.  
  89. class discard_simplifier : public ir_hierarchical_visitor {
  90. public:
  91.    discard_simplifier()
  92.    {
  93.       this->progress = false;
  94.    }
  95.  
  96.    ir_visitor_status visit_enter(ir_if *);
  97.    ir_visitor_status visit_enter(ir_loop *);
  98.  
  99.    bool progress;
  100. };
  101.  
  102. static ir_discard *
  103. find_unconditional_discard(exec_list &instructions)
  104. {
  105.    foreach_list(n, &instructions) {
  106.       ir_discard *ir = ((ir_instruction *) n)->as_discard();
  107.       if (ir != NULL && ir->condition == NULL)
  108.          return ir;
  109.    }
  110.    return NULL;
  111. }
  112.  
  113. static bool
  114. is_only_instruction(ir_discard *discard)
  115. {
  116.    return (discard->prev->is_head_sentinel() &&
  117.            discard->next->is_tail_sentinel());
  118. }
  119.  
  120. ir_visitor_status
  121. discard_simplifier::visit_enter(ir_if *ir)
  122. {
  123.    ir_discard *then_discard = find_unconditional_discard(ir->then_instructions);
  124.    ir_discard *else_discard = find_unconditional_discard(ir->else_instructions);
  125.  
  126.    if (then_discard == NULL && else_discard == NULL)
  127.       return visit_continue;
  128.  
  129.    /* If both branches result in discard, replace whole if with discard. */
  130.    if (then_discard != NULL && else_discard != NULL) {
  131.       this->progress = true;
  132.       ir->replace_with(then_discard);
  133.       return visit_continue_with_parent;
  134.    }
  135.  
  136.    /* Otherwise, one branch has a discard. */
  137.    if (then_discard != NULL && !is_only_instruction(then_discard)) {
  138.       this->progress = true;
  139.       ir->then_instructions.make_empty();
  140.       ir->then_instructions.push_tail(then_discard);
  141.    } else if (else_discard != NULL && !is_only_instruction(else_discard)) {
  142.       this->progress = true;
  143.       ir->else_instructions.make_empty();
  144.       ir->else_instructions.push_tail(else_discard);
  145.    }
  146.  
  147.    visit_list_elements(this, &ir->then_instructions);
  148.    return visit_continue_with_parent;
  149. }
  150.  
  151. ir_visitor_status
  152. discard_simplifier::visit_enter(ir_loop *ir)
  153. {
  154.    ir_discard *discard = find_unconditional_discard(ir->body_instructions);
  155.  
  156.    if (discard) {
  157.       ir->replace_with(discard);
  158.       return visit_continue_with_parent;
  159.    }
  160.  
  161.    return visit_continue;
  162. }
  163.  
  164. bool
  165. do_discard_simplification(exec_list *instructions)
  166. {
  167.    /* Look for a top-level unconditional discard */
  168.    ir_discard *discard = find_unconditional_discard(*instructions);
  169.    if (discard != NULL) {
  170.       instructions->make_empty();
  171.       instructions->push_tail(discard);
  172.       return true;
  173.    }
  174.  
  175.    discard_simplifier v;
  176.  
  177.    visit_list_elements(&v, instructions);
  178.  
  179.    return v.progress;
  180. }
  181.