Home | History | Annotate | Download | only in glsl
      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