Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

ShConstProp.cpp

00001 #include "ShOptimizations.hpp" 00002 #include <map> 00003 #include <set> 00004 #include <utility> 00005 #include <iostream> 00006 #include "ShBitSet.hpp" 00007 #include "ShCtrlGraph.hpp" 00008 #include "ShDebug.hpp" 00009 #include "ShEvaluate.hpp" 00010 #include "ShContext.hpp" 00011 #include "ShSyntax.hpp" 00012 #include <sstream> 00013 #include <fstream> 00014 00015 // Uncomment to enable constant/uniform propagation debugging (verbose!) 00016 //#define SH_DEBUG_CONSTPROP 00017 00018 #ifdef SH_DEBUG_OPTIMIZER 00019 #ifndef SH_DEBUG_CONSTPROP 00020 #define SH_DEBUG_CONSTPROP 00021 #endif 00022 #endif 00023 00024 namespace { 00025 00026 using namespace SH; 00027 00028 typedef std::queue<ValueTracking::Def> ConstWorkList; 00029 00030 struct ConstProp : public ShStatementInfo { 00031 ConstProp(ShStatement* stmt, 00032 ConstWorkList& worklist) 00033 : stmt(stmt) 00034 { 00035 for (int i = 0; i < opInfo[stmt->op].arity ; i++) { 00036 for (int j = 0; j < stmt->src[i].size(); j++) { 00037 switch(stmt->src[i].node()->kind()) { 00038 case SH_INPUT: 00039 case SH_OUTPUT: 00040 case SH_INOUT: 00041 case SH_TEXTURE: 00042 case SH_STREAM: 00043 case SH_PALETTE: 00044 src[i].push_back(Cell(Cell::BOTTOM)); 00045 break; 00046 case SH_TEMP: 00047 if (stmt->src[i].uniform()) { 00048 // Don't lift computations dependent on uniforms which 00049 // have been marked with "opt:lifting" == "never" 00050 if (stmt->src[i].meta("opt:lifting") != "never") { 00051 src[i].push_back(Cell(Cell::UNIFORM, stmt->src[i], j)); 00052 } else { 00053 src[i].push_back(Cell(Cell::BOTTOM)); 00054 } 00055 } else { 00056 src[i].push_back(Cell(Cell::TOP)); 00057 } 00058 break; 00059 case SH_CONST: 00060 src[i].push_back(Cell(Cell::CONSTANT, stmt->src[i].getValue(j))); 00061 break; 00062 } 00063 } 00064 } 00065 updateDest(worklist); 00066 } 00067 00068 ShStatementInfo* clone() const; 00069 00070 int idx(int destindex, int source) 00071 { 00072 return (stmt->src[source].size() == 1 ? 0 : destindex); 00073 } 00074 00075 void updateDest(ConstWorkList& worklist) 00076 { 00077 dest.clear(); 00078 00079 // Ignore KIL, optbra, etc. 00080 if (opInfo[stmt->op].result_source == ShOperationInfo::IGNORE) return; 00081 00082 if (stmt->op == SH_OP_ASN) { 00083 for (int i = 0; i < stmt->dest.size(); i++) { 00084 dest.push_back(src[0][i]); 00085 if (src[0][i].state == Cell::UNIFORM || 00086 src[0][i].state == Cell::CONSTANT) { 00087 worklist.push(ValueTracking::Def(stmt, i)); 00088 } 00089 } 00090 } else if (opInfo[stmt->op].result_source == ShOperationInfo::EXTERNAL) { 00091 // This statement never results in a constant 00092 // E.g. texture fetches, stream fetches. 00093 for (int i = 0; i < stmt->dest.size(); i++) { 00094 dest.push_back(Cell(Cell::BOTTOM)); 00095 } 00096 } else if (opInfo[stmt->op].result_source == ShOperationInfo::LINEAR) { 00097 // Consider each tuple element in turn. 00098 // Dest and sources are guaranteed to be of the same length. 00099 // Except that sources might be scalar. 00100 bool all_fields_uniform = true; 00101 for (int i = 0; i < stmt->dest.size(); i++) { 00102 bool alluniform = true; 00103 bool allconst = true; 00104 for (int s = 0; s < opInfo[stmt->op].arity; s++) { 00105 if (src[s][idx(i,s)].state != Cell::CONSTANT) { 00106 allconst = false; 00107 if (src[s][idx(i,s)].state != Cell::UNIFORM) { 00108 alluniform = false; 00109 } 00110 } 00111 } 00112 if (!alluniform) all_fields_uniform = false; 00113 if (allconst) { 00114 ShVariable tmpdest(new ShVariableNode(SH_CONST, 1)); 00115 ShStatement eval(*stmt); 00116 eval.dest = tmpdest; 00117 for (int k = 0; k < opInfo[stmt->op].arity; k++) { 00118 ShVariable tmpsrc(new ShVariableNode(SH_CONST, 1)); 00119 tmpsrc.setValue(0, src[k][idx(i,k)].value); 00120 eval.src[k] = tmpsrc; 00121 } 00122 evaluate(eval); 00123 dest.push_back(Cell(Cell::CONSTANT, tmpdest.getValue(0))); 00124 worklist.push(ValueTracking::Def(stmt, i)); 00125 } else { 00126 dest.push_back(Cell(Cell::BOTTOM)); 00127 } 00128 } 00129 00130 // Because making a uniform cell based on a ConstProp requires 00131 // generating a value for the entire statement (not just one 00132 // field of the destination), we only push said cells if ALL of 00133 // the indices are uniform for ALL of their corresponding sources. 00134 if (all_fields_uniform) { 00135 dest.clear(); 00136 for (int i = 0; i < stmt->dest.size(); i++) { 00137 dest.push_back(Cell(Cell::UNIFORM, this, i)); 00138 worklist.push(ValueTracking::Def(stmt, i)); 00139 } 00140 } 00141 } else if (opInfo[stmt->op].result_source == ShOperationInfo::ALL) { 00142 // build statement ONLY if ALL elements of ALL sources are constant 00143 bool allconst = true; 00144 bool alluniform = true; // all statements are either uniform or constant 00145 for (int s = 0; s < opInfo[stmt->op].arity; s++) { 00146 for (unsigned int k = 0; k < src[s].size(); k++) { 00147 if (src[s][k].state != Cell::CONSTANT) { 00148 allconst = false; 00149 if (src[s][k].state != Cell::UNIFORM) { 00150 alluniform = false; 00151 } 00152 } 00153 } 00154 } 00155 if (allconst) { 00156 ShVariable tmpdest(new ShVariableNode(SH_CONST, stmt->dest.size())); 00157 ShStatement eval(*stmt); 00158 eval.dest = tmpdest; 00159 for (int i = 0; i < opInfo[stmt->op].arity; i++) { 00160 ShVariable tmpsrc(new ShVariableNode(SH_CONST, stmt->src[i].size())); 00161 for (int j = 0; j < stmt->src[i].size(); j++) { 00162 tmpsrc.setValue(j, src[i][j].value); 00163 } 00164 eval.src[i] = tmpsrc; 00165 } 00166 evaluate(eval); 00167 for (int i = 0; i < stmt->dest.size(); i++) { 00168 dest.push_back(Cell(Cell::CONSTANT, tmpdest.getValue(i))); 00169 worklist.push(ValueTracking::Def(stmt, i)); 00170 } 00171 } else if (alluniform) { 00172 for (int i = 0; i < stmt->dest.size(); i++) { 00173 dest.push_back(Cell(Cell::UNIFORM, this, i)); 00174 worklist.push(ValueTracking::Def(stmt, i)); 00175 } 00176 } else { 00177 for (int i = 0; i < stmt->dest.size(); i++) { 00178 dest.push_back(Cell(Cell::BOTTOM)); 00179 worklist.push(ValueTracking::Def(stmt, i)); 00180 } 00181 } 00182 } else { 00183 SH_DEBUG_ASSERT(0 && "Invalid result source type"); 00184 } 00185 } 00186 00187 typedef int ValueNum; 00188 00189 struct Uniform { 00190 Uniform() 00191 : constant(false), 00192 valuenum(-1) 00193 { 00194 } 00195 00196 Uniform(float constval) 00197 : constant(true), 00198 constval(constval) 00199 { 00200 } 00201 00202 Uniform(int valuenum, int index, bool neg) 00203 : constant(false), 00204 valuenum(valuenum), index(index), neg(neg) 00205 { 00206 } 00207 00208 bool operator==(const Uniform& other) const 00209 { 00210 if (constant != other.constant) return false; 00211 00212 if (constant) { 00213 return constval == other.constval; 00214 } else { 00215 if (valuenum != other.valuenum) return false; 00216 if (index != other.index) return false; 00217 if (neg != other.neg) return false; 00218 return true; 00219 } 00220 } 00221 00222 bool operator!=(const Uniform& other) const 00223 { 00224 return !(*this == other); 00225 } 00226 00227 bool constant; 00228 00229 ValueNum valuenum; 00230 int index; 00231 bool neg; 00232 00233 float constval; 00234 }; 00235 00236 class Value { 00237 public: 00238 enum Type { 00239 NODE, 00240 STMT 00241 }; 00242 00243 Type type; 00244 00245 // Only for type == NODE: 00246 ShVariableNodePtr node; 00247 00248 // Only for type == STMT: 00249 ShOperation op; 00250 int destsize; 00251 std::vector<Uniform> src[3]; 00252 00253 static void clear() 00254 { 00255 m_values.clear(); 00256 } 00257 00258 static ValueNum lookup(const ShVariableNodePtr& node) 00259 { 00260 for (std::size_t i = 0; i < m_values.size(); i++) { 00261 if (m_values[i]->type == NODE && m_values[i]->node == node) return i; 00262 } 00263 m_values.push_back(new Value(node)); 00264 return m_values.size() - 1; 00265 } 00266 00267 bool operator==(const Value& other) const 00268 { 00269 if (type != other.type) return false; 00270 if (type == NODE) { 00271 return node == other.node; 00272 } else if (type == STMT) { 00273 if (op != other.op || destsize != other.destsize) return false; 00274 for (int i = 0; i < opInfo[op].arity; i++) { 00275 if (src[i].size() != other.src[i].size()) return false; 00276 for (std::size_t j = 0; j < src[i].size(); j++) { 00277 if (src[i][j] != other.src[i][j]) return false; 00278 } 00279 } 00280 return true; 00281 } 00282 return false; 00283 } 00284 00285 bool operator!=(const Value& other) const 00286 { 00287 return !(*this == other); 00288 } 00289 00290 static ValueNum lookup(ConstProp* cp) 00291 { 00292 Value* val = new Value(cp); 00293 00294 for (std::size_t i = 0; i < m_values.size(); i++) { 00295 if (m_values[i]->type != STMT) continue; 00296 if (m_values[i]->op != cp->stmt->op) continue; 00297 00298 if (*val == *m_values[i]) { 00299 delete val; 00300 return i; 00301 } 00302 } 00303 m_values.push_back(val); 00304 return m_values.size() - 1; 00305 } 00306 00307 static Value* get(ValueNum n) 00308 { 00309 return m_values[n]; 00310 } 00311 00312 static void dump(std::ostream& out); 00313 00314 private: 00315 Value(const ShVariableNodePtr& node) 00316 : type(NODE), node(node) 00317 { 00318 } 00319 00320 Value(ConstProp* cp) 00321 : type(STMT), node(0), op(cp->stmt->op), destsize(cp->stmt->dest.size()) 00322 { 00323 for (int i = 0; i < opInfo[cp->stmt->op].arity; i++) { 00324 for (std::size_t j = 0; j < cp->src[i].size(); j++) { 00325 if (cp->src[i][j].state == Cell::UNIFORM) { 00326 src[i].push_back(cp->src[i][j].uniform); 00327 } else { 00328 src[i].push_back(Uniform(cp->src[i][j].value)); 00329 } 00330 } 00331 } 00332 } 00333 00334 static std::vector<Value*> m_values; 00335 }; 00336 00337 struct Cell { 00338 enum State { 00339 BOTTOM, 00340 CONSTANT, 00341 UNIFORM, 00342 TOP 00343 }; 00344 00345 Cell(State state, float value = 0.0) 00346 : state(state), value(value) 00347 { 00348 } 00349 00350 Cell(State state, const ShVariable& var, int index) 00351 : state(state), value(0.0), 00352 uniform(Value::lookup(var.node()), var.swizzle()[index], var.neg()) 00353 { 00354 } 00355 00356 Cell(State state, ConstProp* cp, int index) 00357 : state(state), value(0.0), 00358 uniform(Value::lookup(cp), index, false) 00359 { 00360 } 00361 00362 bool operator==(const Cell& other) const 00363 { 00364 return state == other.state && value == other.value; 00365 } 00366 bool operator!=(const Cell& other) const 00367 { 00368 return !(*this == other); 00369 } 00370 00371 State state; 00372 float value; // Only for state == CONSTANT 00373 00374 Uniform uniform; // Only for state == UNIFORM 00375 }; 00376 00377 ShStatement* stmt; 00378 std::vector<Cell> dest; 00379 std::vector<Cell> src[3]; 00380 }; 00381 00382 ShStatementInfo* ConstProp::clone() const 00383 { 00384 return new ConstProp(*this); 00385 } 00386 00387 ConstProp::Cell meet(const ConstProp::Cell& a, const ConstProp::Cell& b) 00388 { 00389 if (a.state == ConstProp::Cell::BOTTOM || b.state == ConstProp::Cell::BOTTOM) { 00390 return ConstProp::Cell(ConstProp::Cell::BOTTOM); 00391 } 00392 if (a.state != b.state 00393 && (a.state != ConstProp::Cell::TOP && b.state != ConstProp::Cell::TOP)) { 00394 return ConstProp::Cell(ConstProp::Cell::BOTTOM); 00395 } 00396 // At this point either the cells are the same or one of them is 00397 // top. 00398 if (a.state == b.state) { 00399 if (a.state == ConstProp::Cell::CONSTANT) { 00400 if (a.value == b.value) { 00401 return a; 00402 } else { 00403 return ConstProp::Cell(ConstProp::Cell::BOTTOM); 00404 } 00405 } 00406 if (a.state == ConstProp::Cell::UNIFORM) { 00407 if (a.uniform == b.uniform) return a; 00408 return ConstProp::Cell(ConstProp::Cell::BOTTOM); 00409 } 00410 } 00411 00412 if (a.state != ConstProp::Cell::TOP) return a; 00413 if (b.state != ConstProp::Cell::TOP) return b; 00414 00415 return ConstProp::Cell(ConstProp::Cell::TOP); 00416 } 00417 00418 std::vector<ConstProp::Value*> ConstProp::Value::m_values = std::vector<ConstProp::Value*>(); 00419 00420 std::ostream& operator<<(std::ostream& out, const ConstProp::Uniform& uniform) 00421 { 00422 if (uniform.constant) { 00423 out << uniform.constval; 00424 } else { 00425 if (uniform.neg) out << '-'; 00426 out << "v" << uniform.valuenum << "[" << uniform.index << "]"; 00427 } 00428 return out; 00429 } 00430 00431 void ConstProp::Value::dump(std::ostream& out) 00432 { 00433 out << "--- uniform values ---" << std::endl; 00434 for (std::size_t i = 0; i < m_values.size(); i++) { 00435 out << i << ": "; 00436 if (m_values[i]->type == NODE) { 00437 out << "node " << m_values[i]->node->name() << std::endl; 00438 } else if (m_values[i]->type == STMT) { 00439 out << "stmt [" << m_values[i]->destsize << "] " << opInfo[m_values[i]->op].name << " "; 00440 for (int j = 0; j < opInfo[m_values[i]->op].arity; j++) { 00441 if (j) out << ", "; 00442 for (std::vector<Uniform>::iterator U = m_values[i]->src[j].begin(); 00443 U != m_values[i]->src[j].end(); ++U) { 00444 out << *U; 00445 } 00446 } 00447 out << ";" << std::endl; 00448 } 00449 } 00450 } 00451 00452 std::ostream& operator<<(std::ostream& out, const ConstProp::Cell& cell) 00453 { 00454 switch(cell.state) { 00455 case ConstProp::Cell::BOTTOM: 00456 out << "[bot]"; 00457 break; 00458 case ConstProp::Cell::CONSTANT: 00459 out << "[" << cell.value << "]"; 00460 break; 00461 case ConstProp::Cell::TOP: 00462 out << "[top]"; 00463 break; 00464 case ConstProp::Cell::UNIFORM: 00465 out << "<" << cell.uniform << ">"; 00466 break; 00467 } 00468 return out; 00469 } 00470 00471 struct InitConstProp { 00472 InitConstProp(ConstWorkList& worklist) 00473 : worklist(worklist) 00474 { 00475 } 00476 00477 void operator()(const ShCtrlGraphNodePtr& node) 00478 { 00479 if (!node) return; 00480 ShBasicBlockPtr block = node->block; 00481 if (!block) return; 00482 for (ShBasicBlock::ShStmtList::iterator I = block->begin(); I != block->end(); ++I) { 00483 I->destroy_info<ConstProp>(); 00484 ConstProp* cp = new ConstProp(&(*I), worklist); 00485 I->add_info(cp); 00486 } 00487 } 00488 00489 ConstWorkList& worklist; 00490 }; 00491 00492 struct DumpConstProp { 00493 void operator()(const ShCtrlGraphNodePtr& node) 00494 { 00495 if (!node) return; 00496 ShBasicBlockPtr block = node->block; 00497 if (!block) return; 00498 for (ShBasicBlock::ShStmtList::iterator I = block->begin(); I != block->end(); ++I) { 00499 std::cerr << "{" << *I << "} --- "; 00500 ConstProp* cp = I->get_info<ConstProp>(); 00501 00502 if (!cp) { 00503 std::cerr << "NO CP INFORMATION" << std::endl; 00504 continue; 00505 } 00506 00507 std::cerr << "dest = {"; 00508 for (std::size_t i = 0; i < cp->dest.size(); i++) { 00509 std::cerr << cp->dest[i]; 00510 } 00511 std::cerr << "}; "; 00512 for (int s = 0; s < opInfo[I->op].arity; s++) { 00513 if (s) std::cerr << ", "; 00514 std::cerr << "src" << s << " = {"; 00515 for (std::size_t i = 0; i < cp->src[s].size(); i++) { 00516 std::cerr << cp->src[s][i]; 00517 } 00518 std::cerr << "}"; 00519 } 00520 std::cerr << std::endl; 00521 } 00522 00523 } 00524 }; 00525 00526 struct FinishConstProp 00527 { 00528 FinishConstProp(bool lift_uniforms) 00529 : lift_uniforms(lift_uniforms) 00530 { 00531 } 00532 00533 void operator()(const ShCtrlGraphNodePtr& node) { 00534 if (!node) return; 00535 ShBasicBlockPtr block = node->block; 00536 if (!block) return; 00537 for (ShBasicBlock::ShStmtList::iterator I = block->begin(); I != block->end(); ++I) { 00538 ConstProp* cp = I->get_info<ConstProp>(); 00539 00540 if (!cp) continue; 00541 00542 if (!cp->dest.empty()) { 00543 // if all dest fields are constants, replace this with a 00544 // constant assignment 00545 00546 if (I->op != SH_OP_ASN || I->src[0].node()->kind() != SH_CONST) { 00547 ShVariable newconst(new ShVariableNode(SH_CONST, I->dest.size())); 00548 bool allconst = true; 00549 for (int i = 0; i < I->dest.size(); i++) { 00550 if (cp->dest[i].state != ConstProp::Cell::CONSTANT) { 00551 allconst = false; 00552 break; 00553 } 00554 newconst.setValue(i, cp->dest[i].value); 00555 } 00556 if (allconst) { 00557 #ifdef SH_DEBUG_CONSTPROP 00558 SH_DEBUG_PRINT("Replaced {" << *I << "} with " << newconst); 00559 #endif 00560 *I = ShStatement(I->dest, SH_OP_ASN, newconst); 00561 } else { 00562 // otherwise, do the same for each source field. 00563 for (int s = 0; s < opInfo[I->op].arity; s++) { 00564 if (I->src[s].node()->kind() == SH_CONST) continue; 00565 00566 ShVariable newconst(new ShVariableNode(SH_CONST, I->src[s].size())); 00567 bool allconst = true; 00568 for (int i = 0; i < I->src[s].size(); i++) { 00569 if (cp->src[s][i].state != ConstProp::Cell::CONSTANT) { 00570 allconst = false; 00571 break; 00572 } 00573 newconst.setValue(i, cp->src[s][i].value); 00574 } 00575 if (allconst) { 00576 #ifdef SH_DEBUG_CONSTPROP 00577 SH_DEBUG_PRINT("Replaced {" << *I << "}.src[" << s << "] with " << newconst); 00578 #endif 00579 I->src[s] = newconst; 00580 } 00581 } 00582 } 00583 00584 if (!lift_uniforms || allconst) { 00585 //SH_DEBUG_PRINT("Skipping uniform lifting"); 00586 continue; 00587 } 00588 00589 bool alluniform = true; 00590 for (int s = 0; s < opInfo[I->op].arity; s++) { 00591 for (int i = 0; i < I->src[s].size(); i++) { 00592 if (cp->src[s][i].state != ConstProp::Cell::UNIFORM 00593 && cp->src[s][i].state != ConstProp::Cell::CONSTANT) { 00594 alluniform = false; 00595 break; 00596 } 00597 } 00598 if (!alluniform) break; 00599 } 00600 if (!alluniform || I->dest.node()->kind() == SH_OUTPUT 00601 || I->dest.node()->kind() == SH_INOUT) { 00602 #ifdef SH_DEBUG_CONSTPROP 00603 SH_DEBUG_PRINT("Considering " << *I << " for uniform lifting"); 00604 #endif 00605 for (int s = 0; s < opInfo[I->op].arity; s++) { 00606 if (I->src[s].uniform()) { 00607 #ifdef SH_DEBUG_CONSTPROP 00608 SH_DEBUG_PRINT(*I << ".src[" << s << "] is already a uniform"); 00609 #endif 00610 continue; 00611 } 00612 00613 bool mixed = false; 00614 bool neg = false; 00615 ConstProp::ValueNum uniform = -1; 00616 std::vector<int> indices; 00617 00618 for (int i = 0; i < I->src[s].size(); i++) { 00619 if (cp->src[s][i].state == ConstProp::Cell::UNIFORM) { 00620 if (uniform < 0) { 00621 uniform = cp->src[s][i].uniform.valuenum; 00622 neg = cp->src[s][i].uniform.neg; 00623 indices.push_back(cp->src[s][i].uniform.index); 00624 } else { 00625 if (uniform != cp->src[s][i].uniform.valuenum 00626 || neg != cp->src[s][i].uniform.neg) { 00627 mixed = true; 00628 break; 00629 } 00630 indices.push_back(cp->src[s][i].uniform.index); 00631 } 00632 } else { 00633 // Can't lift this, unless we introduce intermediate instructions. 00634 mixed = true; 00635 } 00636 } 00637 00638 00639 if (mixed) { 00640 #ifdef SH_DEBUG_CONSTPROP 00641 SH_DEBUG_PRINT(*I << ".src[" << s << "] is mixed"); 00642 #endif 00643 continue; 00644 } 00645 if (uniform < 0) { 00646 #ifdef SH_DEBUG_CONSTPROP 00647 SH_DEBUG_PRINT(*I << ".src[" << s << "] is not uniform"); 00648 #endif 00649 continue; 00650 } 00651 ConstProp::Value* value = ConstProp::Value::get(uniform); 00652 00653 00654 #ifdef SH_DEBUG_CONSTPROP 00655 SH_DEBUG_PRINT("Lifting {" << *I << "}.src[" << s << "]: " << uniform); 00656 #endif 00657 int srcsize; 00658 if (value->type == ConstProp::Value::NODE) { 00659 srcsize = value->node->size(); 00660 } else { 00661 srcsize = value->destsize; 00662 } 00663 ShSwizzle swizzle(srcsize, indices.size(), &(*indices.begin())); 00664 // Build a uniform to represent this computation. 00665 ShVariableNodePtr node = build_uniform(value, uniform); 00666 if (node) { 00667 I->src[s] = ShVariable(node, swizzle, neg); 00668 } else { 00669 #ifdef SH_DEBUG_CONSTPROP 00670 SH_DEBUG_PRINT("Could not lift " << *I << ".src[" << s << "] for some reason"); 00671 #endif 00672 } 00673 } 00674 } 00675 } 00676 } 00677 } 00678 00679 // Clean up 00680 for (ShBasicBlock::ShStmtList::iterator I = block->begin(); I != block->end(); ++I) { 00681 // Remove constant propagation information. 00682 I->destroy_info<ConstProp>(); 00683 } 00684 } 00685 00686 ShVariableNodePtr build_uniform(ConstProp::Value* value, 00687 ConstProp::ValueNum valuenum) 00688 { 00689 if (value->type == ConstProp::Value::NODE) { 00690 return value->node; 00691 } 00692 00693 ShContext::current()->enter(0); 00694 ShVariableNodePtr node = new ShVariableNode(SH_TEMP, value->destsize); 00695 { 00696 std::ostringstream s; 00697 s << "dep_" << valuenum; 00698 node->name(s.str()); 00699 } 00700 ShContext::current()->exit(); 00701 00702 #ifdef SH_DEBUG_CONSTPROP 00703 SH_DEBUG_PRINT("Lifting value #" << valuenum); 00704 #endif 00705 00706 bool broken = false; 00707 00708 ShProgram prg = SH_BEGIN_PROGRAM("uniform") { 00709 ShStatement stmt(node, value->op); 00710 00711 for (int i = 0; i < opInfo[value->op].arity; i++) { 00712 stmt.src[i] = compute(value->src[i]); 00713 if (stmt.src[i].null()) broken = true; 00714 } 00715 00716 ShContext::current()->parsing()->tokenizer.blockList()->addStatement(stmt); 00717 } SH_END; 00718 00719 #ifdef SH_DEBUG_CONSTPROP 00720 { 00721 std::ostringstream s; 00722 s << "lifted_" << valuenum; 00723 std::string dotfilename(s.str() + ".dot"); 00724 std::ofstream dot(dotfilename.c_str()); 00725 prg.node()->ctrlGraph->graphvizDump(dot); 00726 dot.close(); 00727 std::string cmdline = std::string("dot -Tps -o ") + s.str() + ".ps " + s.str() + ".dot"; 00728 system(cmdline.c_str()); 00729 } 00730 #endif 00731 00732 if (broken) return 0; 00733 node->attach(prg.node()); 00734 00735 value->type = ConstProp::Value::NODE; 00736 value->node = node; 00737 00738 return node; 00739 } 00740 00741 ShVariable compute(const std::vector<ConstProp::Uniform>& src) 00742 { 00743 ConstProp::ValueNum v = -1; 00744 00745 bool allsame = true; 00746 bool neg = false; 00747 std::vector<int> indices; 00748 std::vector<float> constvals; 00749 for (std::size_t i = 0; i < src.size(); i++) { 00750 if (src[i].constant) { 00751 if (v >= 0) { 00752 allsame = false; 00753 break; 00754 } 00755 constvals.push_back(src[i].constval); 00756 } else { 00757 if (v < 0 && constvals.empty()) { 00758 v = src[i].valuenum; 00759 neg = src[i].neg; 00760 } else { 00761 if (v != src[i].valuenum || neg != src[i].neg || !constvals.empty()) { 00762 allsame = false; 00763 } 00764 } 00765 indices.push_back(src[i].index); 00766 } 00767 } 00768 if (!allsame) { 00769 // Make intermediate variables, combine them together. 00770 ShVariable r = ShVariable(new ShVariableNode(SH_TEMP, src.size())); 00771 00772 for (std::size_t i = 0; i < src.size(); i++) { 00773 std::vector<ConstProp::Uniform> v; 00774 v.push_back(src[i]); 00775 ShVariable scalar = compute(v); 00776 ShStatement stmt(r(i), SH_OP_ASN, scalar); 00777 ShContext::current()->parsing()->tokenizer.blockList()->addStatement(stmt); 00778 } 00779 return r; 00780 } 00781 00782 if (!constvals.empty()) { 00783 ShVariable var(new ShVariableNode(SH_CONST, constvals.size())); 00784 var.setValues(&*constvals.begin()); 00785 return var; 00786 } 00787 00788 ConstProp::Value* value = ConstProp::Value::get(v); 00789 00790 if (value->type == ConstProp::Value::NODE) { 00791 ShSwizzle swizzle(value->node->size(), indices.size(), &*indices.begin()); 00792 return ShVariable(value->node, swizzle, neg); 00793 } 00794 if (value->type == ConstProp::Value::STMT) { 00795 ShVariableNodePtr node = new ShVariableNode(SH_TEMP, value->destsize); 00796 ShStatement stmt(node, value->op); 00797 00798 for (int i = 0; i < opInfo[value->op].arity; i++) { 00799 stmt.src[i] = compute(value->src[i]); 00800 if (stmt.src[i].null()) return ShVariable(); 00801 } 00802 00803 ShContext::current()->parsing()->tokenizer.blockList()->addStatement(stmt); 00804 ShSwizzle swizzle(node->size(), indices.size(), &*indices.begin()); 00805 return ShVariable(node, swizzle, neg); 00806 } 00807 00808 #ifdef SH_DEBUG_CONSTPROP 00809 SH_DEBUG_PRINT("Reached invalid point"); 00810 #endif 00811 00812 // Should never reach here. 00813 return ShVariable(); 00814 } 00815 00816 bool lift_uniforms; 00817 }; 00818 00819 } 00820 00821 namespace SH { 00822 00823 00824 void propagate_constants(ShProgram& p) 00825 { 00826 ShCtrlGraphPtr graph = p.node()->ctrlGraph; 00827 00828 ConstWorkList worklist; 00829 00830 //ConstProp::Value::clear(); 00831 00832 InitConstProp init(worklist); 00833 graph->dfs(init); 00834 00835 #ifdef SH_DEBUG_CONSTPROP 00836 SH_DEBUG_PRINT("Const Prop Initial Values:"); 00837 DumpConstProp dump_pre; 00838 graph->dfs(dump_pre); 00839 #endif 00840 00841 00842 while (!worklist.empty()) { 00843 ValueTracking::Def def = worklist.front(); worklist.pop(); 00844 ValueTracking* vt = def.stmt->get_info<ValueTracking>(); 00845 if (!vt) { 00846 #ifdef SH_DEBUG_CONSTPROP 00847 SH_DEBUG_PRINT(*def.stmt << " on worklist does not have VT information?"); 00848 #endif 00849 continue; 00850 } 00851 00852 00853 for (ValueTracking::DefUseChain::iterator use = vt->uses[def.index].begin(); 00854 use != vt->uses[def.index].end(); ++use) { 00855 ConstProp* cp = use->stmt->get_info<ConstProp>(); 00856 if (!cp) { 00857 #ifdef SH_DEBUG_CONSTPROP 00858 SH_DEBUG_PRINT("Use " << *use->stmt << " does not have const prop information!"); 00859 #endif 00860 continue; 00861 } 00862 00863 ConstProp::Cell cell = cp->src[use->source][use->index]; 00864 00865 ValueTracking* ut = use->stmt->get_info<ValueTracking>(); 00866 if (!ut) { 00867 // Should never happen... 00868 #ifdef SH_DEBUG_CONSTPROP 00869 SH_DEBUG_PRINT("Use " << *use->stmt << " on worklist does not have VT information?"); 00870 #endif 00871 continue; 00872 } 00873 00874 #ifdef SH_DEBUG_CONSTPROP 00875 SH_DEBUG_PRINT("Meeting cell for {" << *use->stmt 00876 << "}.src" << use->source << "[" << use->index << "]"); 00877 #endif 00878 00879 ConstProp::Cell new_cell(ConstProp::Cell::TOP); 00880 00881 for (ValueTracking::UseDefChain::iterator possdef 00882 = ut->defs[use->source][use->index].begin(); 00883 possdef != ut->defs[use->source][use->index].end(); ++possdef) { 00884 ConstProp* dcp = possdef->stmt->get_info<ConstProp>(); 00885 if (!dcp) { 00886 #ifdef SH_DEBUG_CONSTPROP 00887 SH_DEBUG_PRINT("Possible def " << *dcp->stmt << " on worklist does not have CP information?"); 00888 #endif 00889 continue; 00890 } 00891 00892 ConstProp::Cell destcell = dcp->dest[possdef->index]; 00893 00894 // If the use is negated, we need to change the cell 00895 if (use->stmt->src[use->source].neg()) { 00896 if (destcell.state == ConstProp::Cell::CONSTANT) { 00897 destcell.value = -destcell.value; 00898 } else if (destcell.state == ConstProp::Cell::UNIFORM) { 00899 destcell.uniform.neg = !destcell.uniform.neg; 00900 } 00901 } 00902 #ifdef SH_DEBUG_CONSTPROP 00903 SH_DEBUG_PRINT(" meet(" << new_cell << ", " << destcell << ") = " << 00904 meet(new_cell, destcell)); 00905 #endif 00906 new_cell = meet(new_cell, destcell); 00907 } 00908 00909 if (cell != new_cell) { 00910 #ifdef SH_DEBUG_CONSTPROP 00911 SH_DEBUG_PRINT(" ...replacing cell"); 00912 #endif 00913 cp->src[use->source][use->index] = new_cell; 00914 cp->updateDest(worklist); 00915 } 00916 } 00917 } 00918 // Now do something with our glorious newfound information. 00919 00920 00921 #ifdef SH_DEBUG_CONSTPROP 00922 ConstProp::Value::dump(std::cerr); 00923 00924 DumpConstProp dump; 00925 graph->dfs(dump); 00926 #endif 00927 00928 FinishConstProp finish(p.node()->target().find("gpu:") == 0 00929 && !ShContext::current()->optimization_disabled("uniform lifting")); 00930 graph->dfs(finish); 00931 00932 } 00933 00934 }

Generated on Fri Nov 5 16:51:19 2004 for Sh by doxygen 1.3.7