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