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