Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | 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 "ShVariant.hpp"
00010 #include "ShEvaluate.hpp"
00011 #include "ShContext.hpp"
00012 #include "ShSyntax.hpp"
00013 #include <sstream>
00014 #include <fstream>
00015 
00016 // Uncomment to enable constant/uniform propagation debugging (verbose!)
00017 //#define SH_DEBUG_CONSTPROP
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             // Don't lift computations dependent on uniforms which
00050             // have been marked with "opt:lifting" == "never"
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     // Ignore KIL, optbra, etc.
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       // This statement never results in a constant
00097       // E.g. texture fetches, stream fetches.
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       // Consider each tuple element in turn.
00103       // Dest and sources are guaranteed to be of the same length.
00104       // Except that sources might be scalar.
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       // Because making a uniform cell based on a ConstProp requires
00137       // generating a value for the entire statement (not just one
00138       // field of the destination), we only push said cells if ALL of
00139       // the indices are uniform for ALL of their corresponding sources.
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       // build statement ONLY if ALL elements of ALL sources are constant
00149       bool allconst = true;
00150       bool alluniform = true; // all statements are either uniform or constant
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); // @todo type DEBUGGING
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     // @todo type...this is my current understanding:
00205     // May be constant or if !constval, value is not
00206     // known to be constant
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         // @todo type
00226         if(!constval) return false;
00227         // Check with Stefanus whether this modification is correct
00228     //    SH_DEBUG_ASSERT(constval); // @todo type debugging
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     // Only for type == NODE:
00269     ShVariableNodePtr node;
00270 
00271     // Only for type == STMT:
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); // @todo type should be fixed
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     // @todo comments added, but may not be correct
00378    
00379     // Construct a CONSTANT Cell with non-null value
00380     // or a TOP/BOTTOM
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     // Construct a UNIFORM cell from a variable
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     // Construct a UNIFORM cell as a result of some
00396     // statement where all relevant sources are uniforms/constants.
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       // @todo type remove debug
00408       SH_DEBUG_ASSERT(!value);
00409       return value == other.value; // null
00410     }
00411 
00412     bool operator!=(const Cell& other) const
00413     {
00414       return !(*this == other);
00415     }
00416     
00417     State state;
00418     ShVariantPtr value; // Only for state == CONSTANT
00419 
00420     Uniform uniform; // Only for state == 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   // At this point either the cells are the same or one of them is
00443   // top.
00444   if (a.state == b.state) {
00445     if (a.state == ConstProp::Cell::CONSTANT) {
00446       SH_DEBUG_ASSERT(a.value); // @todo type debugging
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); // @todo type DEBUGGING
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 }

Generated on Mon Jan 24 18:36:31 2005 for Sh by  doxygen 1.4.1