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 #include <stack> 28 #include <map> 29 30 #include "sb_shader.h" 31 #include "sb_pass.h" 32 33 namespace r600_sb { 34 35 container_node* ssa_prepare::create_phi_nodes(int count) { 36 container_node *p = sh.create_container(); 37 val_set &vars = cur_set(); 38 node *nn; 39 40 for (val_set::iterator I = vars.begin(sh), E = vars.end(sh); I != E; ++I) { 41 nn = sh.create_node(NT_OP, NST_PHI); 42 nn->dst.assign(1, *I); 43 nn->src.assign(count, *I); 44 p->push_back(nn); 45 } 46 return p; 47 } 48 49 void ssa_prepare::add_defs(node &n) { 50 val_set &s = cur_set(); 51 for (vvec::iterator I = n.dst.begin(), E = n.dst.end(); I != E; ++I) { 52 value *v = *I; 53 if (!v) 54 continue; 55 56 if (v->is_rel()) { 57 s.add_vec(v->mdef); 58 } else 59 s.add_val(v); 60 } 61 } 62 63 bool ssa_prepare::visit(cf_node& n, bool enter) { 64 if (enter) { 65 push_stk(); 66 } else { 67 add_defs(n); 68 pop_stk(); 69 } 70 return true; 71 } 72 73 bool ssa_prepare::visit(alu_node& n, bool enter) { 74 if (enter) { 75 } else { 76 add_defs(n); 77 } 78 return true; 79 } 80 81 bool ssa_prepare::visit(fetch_node& n, bool enter) { 82 if (enter) { 83 } else { 84 add_defs(n); 85 } 86 return true; 87 } 88 89 bool ssa_prepare::visit(region_node& n, bool enter) { 90 if (enter) { 91 92 push_stk(); 93 } else { 94 cur_set().add_set(n.vars_defined); 95 if (n.dep_count() > 0) 96 n.phi = create_phi_nodes(n.dep_count()); 97 if (n.rep_count() > 1) { 98 n.loop_phi = create_phi_nodes(n.rep_count()); 99 n.loop_phi->subtype = NST_LOOP_PHI_CONTAINER; 100 } 101 n.vars_defined.clear(); 102 pop_stk(); 103 } 104 return true; 105 } 106 107 bool ssa_prepare::visit(repeat_node& n, bool enter) { 108 if (enter) { 109 push_stk(); 110 } else { 111 assert(n.target); 112 n.target->vars_defined.add_set(cur_set()); 113 cur_set().clear(); 114 pop_stk(); 115 } 116 return true; 117 } 118 119 bool ssa_prepare::visit(depart_node& n, bool enter) { 120 if (enter) { 121 push_stk(); 122 } else { 123 assert(n.target); 124 n.target->vars_defined.add_set(cur_set()); 125 cur_set().clear(); 126 pop_stk(); 127 } 128 return true; 129 } 130 131 // =============================== 132 133 int ssa_rename::init() { 134 rename_stack.push(def_map()); 135 return 0; 136 } 137 138 bool ssa_rename::visit(alu_group_node& n, bool enter) { 139 // taking into account parallel execution of the alu group 140 if (enter) { 141 for (node_iterator I = n.begin(), E = n.end(); I != E; ++I) { 142 I->accept(*this, true); 143 } 144 } else { 145 for (node_iterator I = n.begin(), E = n.end(); I != E; ++I) { 146 I->accept(*this, false); 147 } 148 } 149 return false; 150 } 151 152 bool ssa_rename::visit(cf_node& n, bool enter) { 153 if (enter) { 154 rename_src(&n); 155 } else { 156 rename_dst(&n); 157 } 158 return true; 159 } 160 161 bool ssa_rename::visit(alu_node& n, bool enter) { 162 if (enter) { 163 rename_src(&n); 164 } else { 165 166 node *psi = NULL; 167 168 if (n.pred && n.dst[0]) { 169 170 value *d = n.dst[0]; 171 unsigned index = get_index(rename_stack.top(), d); 172 value *p = sh.get_value_version(d, index); 173 174 psi = sh.create_node(NT_OP, NST_PSI); 175 176 container_node *parent; 177 if (n.parent->subtype == NST_ALU_GROUP) 178 parent = n.parent; 179 else { 180 assert (n.parent->parent->subtype == NST_ALU_GROUP); 181 parent = n.parent->parent; 182 } 183 parent->insert_after(psi); 184 185 assert(n.bc.pred_sel); 186 187 psi->src.resize(6); 188 psi->src[2] = p; 189 psi->src[3] = n.pred; 190 psi->src[4] = sh.get_pred_sel(n.bc.pred_sel - PRED_SEL_0); 191 psi->src[5] = d; 192 psi->dst.push_back(d); 193 } 194 195 rename_dst(&n); 196 197 if (psi) { 198 rename_src(psi); 199 rename_dst(psi); 200 } 201 202 if (!n.dst.empty() && n.dst[0]) { 203 // FIXME probably use separate pass for such things 204 if ((n.bc.op_ptr->flags & AF_INTERP) || n.bc.op == ALU_OP2_CUBE) 205 n.dst[0]->flags |= VLF_PIN_CHAN; 206 } 207 } 208 return true; 209 } 210 211 bool ssa_rename::visit(alu_packed_node& n, bool enter) { 212 if (enter) { 213 for (node_iterator I = n.begin(), E = n.end(); I != E; ++I) { 214 I->accept(*this, true); 215 } 216 } else { 217 for (node_iterator I = n.begin(), E = n.end(); I != E; ++I) { 218 I->accept(*this, false); 219 } 220 221 bool repl = (n.op_ptr()->flags & AF_REPL) || 222 (ctx.is_cayman() && (n.first->alu_op_slot_flags() & AF_S)); 223 224 n.init_args(repl); 225 } 226 return false; 227 } 228 229 bool ssa_rename::visit(fetch_node& n, bool enter) { 230 if (enter) { 231 rename_src(&n); 232 rename_dst(&n); 233 } else { 234 } 235 return true; 236 } 237 238 bool ssa_rename::visit(region_node& n, bool enter) { 239 if (enter) { 240 if (n.loop_phi) 241 rename_phi_args(n.loop_phi, 0, true); 242 } else { 243 if (n.phi) 244 rename_phi_args(n.phi, ~0u, true); 245 } 246 return true; 247 } 248 249 bool ssa_rename::visit(repeat_node& n, bool enter) { 250 if (enter) { 251 push(n.target->loop_phi); 252 } else { 253 if (n.target->loop_phi) 254 rename_phi_args(n.target->loop_phi, n.rep_id, false); 255 pop(); 256 } 257 return true; 258 } 259 260 bool ssa_rename::visit(depart_node& n, bool enter) { 261 if (enter) { 262 push(n.target->phi); 263 } else { 264 if (n.target->phi) 265 rename_phi_args(n.target->phi, n.dep_id, false); 266 pop(); 267 } 268 return true; 269 } 270 271 bool ssa_rename::visit(if_node& n, bool enter) { 272 if (enter) { 273 } else { 274 n.cond = rename_use(&n, n.cond); 275 } 276 return true; 277 } 278 279 void ssa_rename::push(node* phi) { 280 rename_stack.push(rename_stack.top()); 281 } 282 283 void ssa_rename::pop() { 284 rename_stack.pop(); 285 } 286 287 value* ssa_rename::rename_use(node *n, value* v) { 288 if (v->version) 289 return v; 290 291 unsigned index = get_index(rename_stack.top(), v); 292 v = sh.get_value_version(v, index); 293 294 // if (alu) instruction is predicated and source arg comes from psi node 295 // (that is, from another predicated instruction through its psi node), 296 // we can try to select the corresponding source value directly 297 if (n->pred && v->def && v->def->subtype == NST_PSI) { 298 assert(n->subtype == NST_ALU_INST); 299 alu_node *an = static_cast<alu_node*>(n); 300 node *pn = v->def; 301 // FIXME make it more generic ??? 302 if (pn->src.size() == 6) { 303 if (pn->src[3] == n->pred) { 304 value* ps = sh.get_pred_sel(an->bc.pred_sel - PRED_SEL_0); 305 if (pn->src[4] == ps) 306 return pn->src[5]; 307 else 308 return pn->src[2]; 309 } 310 } 311 } 312 return v; 313 } 314 315 value* ssa_rename::rename_def(node *n, value* v) { 316 unsigned index = new_index(def_count, v); 317 set_index(rename_stack.top(), v, index); 318 value *r = sh.get_value_version(v, index); 319 return r; 320 } 321 322 void ssa_rename::rename_src_vec(node *n, vvec &vv, bool src) { 323 for(vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I) { 324 value* &v = *I; 325 if (!v || v->is_readonly()) 326 continue; 327 328 if (v->is_rel()) { 329 if (!v->rel->is_readonly()) 330 v->rel = rename_use(n, v->rel); 331 rename_src_vec(n, v->muse, true); 332 } else if (src) 333 v = rename_use(n, v); 334 } 335 } 336 337 void ssa_rename::rename_src(node* n) { 338 if (n->pred) 339 n->pred = rename_use(n, n->pred); 340 341 rename_src_vec(n, n->src, true); 342 rename_src_vec(n, n->dst, false); 343 344 } 345 346 void ssa_rename::rename_dst_vec(node *n, vvec &vv, bool set_def) { 347 348 for(vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I) { 349 value* &v = *I; 350 if (!v) 351 continue; 352 353 if (v->is_rel()) { 354 rename_dst_vec(n, v->mdef, false); 355 } else { 356 v = rename_def(n, v); 357 if (set_def) 358 v->def = n; 359 } 360 } 361 } 362 363 void ssa_rename::rename_dst(node* n) { 364 rename_dst_vec(n, n->dst, true); 365 } 366 367 unsigned ssa_rename::get_index(def_map& m, value* v) { 368 def_map::iterator I = m.find(v); 369 if (I != m.end()) 370 return I->second; 371 return 0; 372 } 373 374 void ssa_rename::set_index(def_map& m, value* v, unsigned index) { 375 std::pair<def_map::iterator,bool> r = m.insert(std::make_pair(v, index)); 376 if (!r.second) 377 r.first->second = index; 378 } 379 380 unsigned ssa_rename::new_index(def_map& m, value* v) { 381 unsigned index = 1; 382 def_map::iterator I = m.find(v); 383 if (I != m.end()) 384 index = ++I->second; 385 else 386 m.insert(std::make_pair(v, index)); 387 return index; 388 } 389 390 bool ssa_rename::visit(node& n, bool enter) { 391 if (enter) { 392 assert(n.subtype == NST_PSI); 393 rename_src(&n); 394 rename_dst(&n); 395 } 396 return false; 397 } 398 399 bool ssa_rename::visit(container_node& n, bool enter) { 400 if (enter) { 401 } else { 402 // should be root container node 403 assert(n.parent == NULL); 404 rename_src_vec(&n, n.src, true); 405 } 406 return true; 407 } 408 409 void ssa_rename::rename_phi_args(container_node* phi, unsigned op, bool def) { 410 for (node_iterator I = phi->begin(), E = phi->end(); I != E; ++I) { 411 node *o = *I; 412 if (op != ~0u) 413 o->src[op] = rename_use(o, o->src[op]); 414 if (def) { 415 o->dst[0] = rename_def(o, o->dst[0]); 416 o->dst[0]->def = o; 417 } 418 } 419 } 420 421 } // namespace r600_sb 422