1 /* 2 * Copyright 2013 Vadim Girlin <vadimgirlin (at) gmail.com> 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 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 * USE OR OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: 24 * Vadim Girlin 25 */ 26 27 #define GVN_DEBUG 0 28 29 #if GVN_DEBUG 30 #define GVN_DUMP(q) do { q } while (0) 31 #else 32 #define GVN_DUMP(q) 33 #endif 34 35 #include "sb_shader.h" 36 #include "sb_pass.h" 37 #include "sb_sched.h" 38 39 namespace r600_sb { 40 41 bool gvn::visit(node& n, bool enter) { 42 if (enter) { 43 44 45 bool rewrite = true; 46 47 if (n.dst[0]->is_agpr()) { 48 rewrite = false; 49 } 50 51 52 process_op(n, rewrite); 53 54 assert(n.parent); 55 56 if (n.parent->subtype == NST_LOOP_PHI_CONTAINER) { 57 // There is a problem - sometimes with nested loops 58 // loop counter initialization for inner loop is incorrectly hoisted 59 // out of the outer loop 60 61 // FIXME not sure if this is enough to fix a problem completely, 62 // possibly more complete fix is needed (anyway, the 63 // problem was seen only in relatively complex 64 // case involving nested loops and 65 // indirect access to loop counters (without proper array info 66 // loop counters may be considered as array elements too), 67 // was not seen in any tests 68 // or real apps when proper array information is available in TGSI). 69 70 // For now just mark the instructions that initialize loop counters 71 // with DONT_HOIST flag to prevent the insts like MOV r, 0 72 // (initialization of inner loop's counter with const) 73 // from being hoisted out of the outer loop 74 75 assert(!n.src.empty()); 76 value *v = n.src[0]; 77 78 if (v->is_any_gpr() && v->def) 79 v->def->flags |= NF_DONT_HOIST; 80 } 81 82 } else { 83 } 84 return true; 85 } 86 87 bool gvn::visit(cf_node& n, bool enter) { 88 if (enter) { 89 process_op(n); 90 } else { 91 } 92 return true; 93 } 94 95 bool gvn::visit(alu_node& n, bool enter) { 96 if (enter) { 97 process_op(n); 98 } else { 99 } 100 return true; 101 } 102 103 bool gvn::visit(alu_packed_node& n, bool enter) { 104 if (enter) { 105 process_op(n); 106 } else { 107 } 108 return false; 109 } 110 111 bool gvn::visit(fetch_node& n, bool enter) { 112 if (enter) { 113 process_op(n); 114 } else { 115 } 116 return true; 117 } 118 119 bool gvn::visit(region_node& n, bool enter) { 120 if (enter) { 121 // FIXME: loop_phi sources are undefined yet (except theone from the preceding 122 // code), can we handle that somehow? 123 // if (n.loop_phi) 124 // run_on(*n.loop_phi); 125 } else { 126 if (n.loop_phi) 127 run_on(*n.loop_phi); 128 129 if (n.phi) 130 run_on(*n.phi); 131 } 132 return true; 133 } 134 135 bool gvn::process_src(value* &v, bool rewrite) { 136 if (!v->gvn_source) 137 sh.vt.add_value(v); 138 139 if (rewrite && !v->gvn_source->is_rel()) { 140 v = v->gvn_source; 141 return true; 142 } 143 return false; 144 } 145 146 // FIXME: maybe handle it in the scheduler? 147 void gvn::process_alu_src_constants(node &n, value* &v) { 148 if (n.src.size() < 3) { 149 process_src(v, true); 150 return; 151 } 152 153 if (!v->gvn_source) 154 sh.vt.add_value(v); 155 156 rp_kcache_tracker kc(sh); 157 158 if (v->gvn_source->is_kcache()) 159 kc.try_reserve(v->gvn_source->select); 160 161 // don't propagate 3rd constant to the trans-only instruction 162 if (!n.is_alu_packed()) { 163 alu_node *a = static_cast<alu_node*>(&n); 164 if (a->bc.op_ptr->src_count == 3 && !(a->bc.slot_flags & AF_V)) { 165 unsigned const_count = 0; 166 for (vvec::iterator I = n.src.begin(), E = n.src.end(); I != E; 167 ++I) { 168 value *c = (*I); 169 if (c && c->is_readonly() && ++const_count == 2) { 170 process_src(v, false); 171 return; 172 } 173 } 174 } 175 } 176 177 for (vvec::iterator I = n.src.begin(), E = n.src.end(); I != E; ++I) { 178 value *c = (*I); 179 180 if (c->is_kcache() && !kc.try_reserve(c->select)) { 181 process_src(v, false); 182 return; 183 } 184 } 185 process_src(v, true); 186 } 187 188 void gvn::process_op(node& n, bool rewrite) { 189 190 for(vvec::iterator I = n.src.begin(), E = n.src.end(); I != E; ++I) { 191 value* &v = *I; 192 if (v) { 193 if (v->rel) { 194 process_src(v->rel, rewrite); 195 } 196 197 if (rewrite && v->gvn_source && v->gvn_source->is_readonly() && 198 n.is_any_alu()) { 199 process_alu_src_constants(n, v); 200 } else if (rewrite && v->gvn_source && v->gvn_source->is_const() && 201 (n.is_fetch_op(FETCH_OP_VFETCH) || 202 n.is_fetch_op(FETCH_OP_SEMFETCH))) 203 process_src(v, false); 204 else 205 process_src(v, rewrite); 206 } 207 } 208 if (n.pred) 209 process_src(n.pred, false); 210 211 if (n.type == NT_IF) { 212 if_node &i = (if_node&)n; 213 if (i.cond) 214 process_src(i.cond, false); 215 } 216 217 for(vvec::iterator I = n.dst.begin(), E = n.dst.end(); I != E; ++I) { 218 value *v = *I; 219 if (v) { 220 if (v->rel) 221 process_src(v->rel, rewrite); 222 sh.vt.add_value(v); 223 } 224 } 225 } 226 227 } // namespace r600_sb 228