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

Generated on Mon Oct 18 14:17:39 2004 for Sh by doxygen 1.3.7