00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00024 #include <map>
00025 #include <set>
00026 #include <utility>
00027 #include <iostream>
00028 #include <sstream>
00029 #include <fstream>
00030 #include "ShOptimizations.hpp"
00031 #include "ShBitSet.hpp"
00032 #include "ShCtrlGraph.hpp"
00033 #include "ShDebug.hpp"
00034 #include "ShEvaluate.hpp"
00035 #include "ShContext.hpp"
00036 #include "ShSyntax.hpp"
00037 #include "ShProgramNode.hpp"
00038
00039
00040
00041
00042 #ifdef SH_DEBUG_OPTIMIZER
00043 #ifndef SH_DEBUG_VALUETRACK
00044 #define SH_DEBUG_VALUETRACK
00045 #endif
00046 #endif
00047 namespace {
00048 using namespace SH;
00049
00050
00051
00052 struct ReachingDefs {
00053 ReachingDefs()
00054 : defsize(0)
00055 {
00056 }
00057
00058 struct Definition {
00059 Definition(ShStatement* stmt,
00060 const ShCtrlGraphNodePtr& node,
00061 int offset,
00062 ShBitSet disable_mask)
00063 : varnode(stmt->dest.node()), stmt(stmt), node(node), offset(offset),
00064 disable_mask(disable_mask)
00065 {}
00066
00067 Definition(ShVariableNodePtr varnode,
00068 const ShCtrlGraphNodePtr& node,
00069 int offset,
00070 ShBitSet disable_mask)
00071 : varnode(varnode), stmt(0), node(node), offset(offset),
00072 disable_mask(disable_mask)
00073 {}
00074
00075 bool isInput() const
00076 {
00077 return !stmt;
00078 }
00079
00080 int size() const
00081 {
00082 if(isInput()) return varnode->size();
00083 else return stmt->dest.size();
00084 }
00085
00086
00087 int isDisabled(int i) const
00088 {
00089 return disable_mask[index(i)];
00090 }
00091
00092
00093 int off(int i) const
00094 {
00095 return offset + i;
00096 }
00097
00098
00099 int index(int i) const
00100 {
00101 if(isInput()) return i;
00102 return stmt->dest.swizzle()[i];
00103 }
00104
00105
00106 ValueTracking::Def toDef(int i) const
00107 {
00108 if(isInput()) return ValueTracking::Def(varnode, i);
00109 return ValueTracking::Def(stmt, i);
00110 }
00111
00112 friend std::ostream& operator<<(std::ostream& out, const Definition& def)
00113 {
00114 out << "{";
00115 out << " off " << def.offset;
00116 out << ", node " << def.node.object();
00117 out << ", dsbl " << def.disable_mask << ", ";
00118 if(def.isInput()) out << "input " << def.varnode->name();
00119 else out << "stmt " << *def.stmt;
00120 out << "}";
00121 return out;
00122 }
00123
00124 ShVariableNodePtr varnode;
00125 ShStatement* stmt;
00126 ShCtrlGraphNodePtr node;
00127 int offset;
00128
00129
00130
00131
00132
00133 ShBitSet disable_mask;
00134 };
00135
00136 void addDefinition(const Definition& d)
00137 {
00138
00139 defs.push_back(d);
00140 defsize += d.size();
00141 }
00142
00143 typedef std::map<ShCtrlGraphNodePtr, int> SizeMap;
00144 typedef std::map<ShCtrlGraphNodePtr, ShBitSet> ReachingMap;
00145
00146 std::vector<Definition> defs;
00147 int defsize;
00148
00149 ReachingMap gen, prsv;
00150 ReachingMap rchin;
00151 };
00152
00153 struct DefFinder {
00154 DefFinder(ReachingDefs& r, ShCtrlGraphNodePtr entry, const ShProgramNode::VarList& inputs)
00155 : entry(entry), inputs(inputs), r(r), offset(0)
00156 {
00157 }
00158
00159 void operator()(ShCtrlGraphNodePtr node)
00160 {
00161 if (!node) return;
00162 ShBasicBlockPtr block = node->block;
00163
00164
00165
00166 std::map<ShVariableNodePtr, ShBitSet> disable_map;
00167
00168 if(block) {
00169
00170 ShBasicBlock::ShStmtList::iterator I = block->end();
00171 while (1) {
00172 if (I == block->begin()) break;
00173 --I;
00174 if (!I->dest.null() && I->op != SH_OP_KIL && I->op != SH_OP_OPTBRA ) {
00175
00176
00177 if (disable_map.find(I->dest.node()) == disable_map.end()) {
00178 disable_map[I->dest.node()] = ShBitSet(I->dest.node()->size());
00179 }
00180
00181
00182
00183 ShBitSet defn_map(I->dest.node()->size());
00184 for (int i = 0; i < I->dest.size(); i++) defn_map[I->dest.swizzle()[i]] = true;
00185
00186
00187
00188 if ((defn_map & disable_map[I->dest.node()]) == defn_map) continue;
00189
00190
00191 r.addDefinition(ReachingDefs::Definition(&(*I), node, r.defsize,
00192 disable_map[I->dest.node()]));
00193
00194
00195 disable_map[I->dest.node()] |= defn_map;
00196 }
00197 }
00198 }
00199
00200
00201 if(node != entry) return;
00202 for(ShProgramNode::VarList::const_iterator I = inputs.begin();
00203 I != inputs.end(); ++I) {
00204 if(disable_map.find(*I) == disable_map.end()) {
00205 disable_map[*I] = ShBitSet((*I)->size());
00206 }
00207
00208
00209 if(disable_map[*I].full()) continue;
00210
00211 r.addDefinition(ReachingDefs::Definition(*I, node, r.defsize,
00212 disable_map[*I]));
00213 }
00214 }
00215
00216 ShCtrlGraphNodePtr entry;
00217 const ShProgramNode::VarList& inputs;
00218 ReachingDefs& r;
00219 int offset;
00220 };
00221
00222 struct InitRch {
00223 InitRch(ReachingDefs& r)
00224 : r(r)
00225 {
00226 }
00227
00228 void operator()(ShCtrlGraphNodePtr node)
00229 {
00230 if (!node) return;
00231
00232 r.rchin[node] = ShBitSet(r.defsize);
00233 r.gen[node] = ShBitSet(r.defsize);
00234 r.prsv[node] = ~ShBitSet(r.defsize);
00235
00236 ShBasicBlockPtr block = node->block;
00237
00238
00239 for (unsigned int i = 0; i < r.defs.size(); i++) {
00240 ReachingDefs::Definition &d = r.defs[i];
00241 if (d.node == node) {
00242 for (int j = 0; j < d.size(); j++) {
00243
00244
00245
00246 if (!d.isDisabled(j)) {
00247 r.gen[node][d.off(j)] = true;
00248 }
00249 }
00250 }
00251 }
00252
00253 if(!block) return;
00254
00255
00256 for (ShBasicBlock::ShStmtList::iterator I = block->begin(); I != block->end(); ++I) {
00257 if (I->dest.null()
00258 || I->op == SH_OP_KIL
00259 || I->op == SH_OP_OPTBRA
00260 ) continue;
00261 for (unsigned int i = 0; i < r.defs.size(); i++) {
00262 ReachingDefs::Definition &d = r.defs[i];
00263 if (d.varnode != I->dest.node()) continue;
00264
00265 for (int j = 0; j < I->dest.size(); ++j) {
00266 for (int k = 0; k < d.size(); ++k) {
00267 if (d.index(k) == I->dest.swizzle()[j]) {
00268 r.prsv[node][d.off(k)] = false;
00269 }
00270 }
00271 }
00272 }
00273 }
00274 }
00275
00276 ReachingDefs& r;
00277 };
00278
00279 struct IterateRch {
00280 IterateRch(ReachingDefs& r, bool& changed)
00281 : r(r), changed(changed)
00282 {
00283 }
00284
00285 void operator()(const ShCtrlGraphNodePtr& node)
00286 {
00287 if (!node) return;
00288 SH_DEBUG_ASSERT(r.rchin.find(node) != r.rchin.end());
00289 ShBitSet newRchIn(r.defsize);
00290
00291 for (ShCtrlGraphNode::ShPredList::iterator I = node->predecessors.begin();
00292 I != node->predecessors.end(); ++I) {
00293 SH_DEBUG_ASSERT(r.gen.find(*I) != r.gen.end());
00294 SH_DEBUG_ASSERT(r.prsv.find(*I) != r.prsv.end());
00295 SH_DEBUG_ASSERT(r.rchin.find(*I) != r.rchin.end());
00296
00297 newRchIn |= (r.gen[*I] | (r.rchin[*I] & r.prsv[*I]));
00298 }
00299 if (newRchIn != r.rchin[node]) {
00300 r.rchin[node] = newRchIn;
00301 changed = true;
00302 }
00303 }
00304
00305 ReachingDefs& r;
00306 bool& changed;
00307 };
00308
00309
00310
00311 struct UdDuBuilder {
00312 UdDuBuilder(ReachingDefs& r, ShProgramNodePtr p)
00313 : r(r), m_exit(p->ctrlGraph->exit()), p(p),
00314 intrack(new InputValueTracking()),
00315 outtrack(new OutputValueTracking())
00316 {
00317 p->destroy_info<InputValueTracking>();
00318 p->destroy_info<OutputValueTracking>();
00319 p->add_info(intrack);
00320 p->add_info(outtrack);
00321 }
00322
00323 struct TupleElement {
00324 TupleElement(const ShVariableNodePtr& node, int index)
00325 : node(node), index(index)
00326 {
00327 }
00328
00329 bool operator<(const TupleElement& other) const
00330 {
00331 if (node < other.node) return true;
00332 if (node == other.node) return index < other.index;
00333 return false;
00334 }
00335
00336 ShVariableNodePtr node;
00337 int index;
00338 };
00339
00340 void operator()(ShCtrlGraphNodePtr node) {
00341 typedef std::set<ValueTracking::Def> DefSet;
00342 typedef std::map<TupleElement, DefSet> DefMap;
00343
00344
00345
00346 DefMap defs;
00347
00348 if (!node) return;
00349 ShBasicBlockPtr block = node->block;
00350
00351
00352
00353
00354
00355 for (std::size_t i = 0; i < r.defs.size(); i++) {
00356 for (int j = 0; j < r.defs[i].size(); j++) {
00357 if (r.rchin[node][r.defs[i].offset + j]) {
00358 ValueTracking::Def def(r.defs[i].toDef(j));
00359 defs[TupleElement(r.defs[i].varnode,
00360 r.defs[i].index(j))].insert(def);
00361 }
00362 }
00363 }
00364
00365 if(block) {
00366
00367 for (ShBasicBlock::ShStmtList::iterator I = block->begin(); I != block->end(); ++I) {
00368
00369
00370 for (int j = 0; j < opInfo[I->op].arity; j++) {
00371
00372 ValueTracking* vt = I->get_info<ValueTracking>();
00373 if (!vt) {
00374 vt = new ValueTracking(&(*I));
00375 I->add_info(vt);
00376 }
00377 ShVariableNodePtr srcNode = I->src[j].node();
00378 for (int i = 0; i < I->src[j].size(); i++) {
00379 const DefSet& ds = defs[TupleElement(srcNode, I->src[j].swizzle()[i])];
00380
00381 vt->defs[j][i] = ds;
00382 ValueTracking::Use srcUse(&(*I), j, i);
00383 for (DefSet::const_iterator J = ds.begin(); J != ds.end(); J++) {
00384 switch(J->kind) {
00385 case ValueTracking::Def::INPUT:
00386 {
00387 ValueTracking::TupleDefUseChain& inputDu =
00388 intrack->inputUses[srcNode];
00389 if(inputDu.empty()) {
00390 inputDu.resize(srcNode->size());
00391 }
00392 inputDu[J->index].insert(srcUse);
00393 break;
00394 }
00395 case ValueTracking::Def::STMT:
00396 {
00397 ValueTracking* ut = J->stmt->get_info<ValueTracking>();
00398 if (!ut) {
00399 ut = new ValueTracking(J->stmt);
00400 J->stmt->add_info(ut);
00401 }
00402 ut->uses[J->index].insert(srcUse);
00403 break;
00404 }
00405 }
00406 }
00407
00408 }
00409 }
00410
00411 for (int i = 0; i < I->dest.size(); ++i) {
00412 defs[TupleElement(I->dest.node(), I->dest.swizzle()[i])].clear();
00413 ValueTracking::Def def(&(*I), i);
00414 defs[TupleElement(I->dest.node(), I->dest.swizzle()[i])].insert(def);
00415 }
00416 }
00417 }
00418
00419
00420
00421
00422
00423 if(node == m_exit) {
00424 for(DefMap::iterator D = defs.begin(); D != defs.end(); ++D) {
00425 ShVariableNodePtr node = D->first.node;
00426 ShBindingType kind = node->kind();
00427 int index = D->first.index;
00428
00429 if(kind == SH_INOUT || kind == SH_OUTPUT) {
00430 DefSet& ds = D->second;
00431
00432 ValueTracking::TupleUseDefChain& outDef = outtrack->outputDefs[node];
00433 if(outDef.empty()) {
00434 outDef.resize(node->size());
00435 }
00436 outDef[index] = ds;
00437
00438 for(DefSet::iterator S = ds.begin(); S != ds.end(); ++S) {
00439 if(S->kind != ValueTracking::Def::STMT) continue;
00440 ValueTracking* vt = S->stmt->get_info<ValueTracking>();
00441 if (!vt) {
00442 vt = new ValueTracking(S->stmt);
00443 S->stmt->add_info(vt);
00444 }
00445 SH_DEBUG_ASSERT(vt);
00446 ValueTracking::Use use(node, S->stmt->dest.swizzle()[S->index]);
00447 vt->uses[S->index].insert(use);
00448 }
00449 }
00450 }
00451 }
00452 }
00453
00454 ReachingDefs& r;
00455 ShCtrlGraphNodePtr m_exit;
00456 ShProgramNodePtr p;
00457 InputValueTracking* intrack;
00458 OutputValueTracking* outtrack;
00459 };
00460
00461 struct UdDuClearer {
00462 void operator()(ShCtrlGraphNodePtr node) {
00463 if (!node) return;
00464 ShBasicBlockPtr block = node->block;
00465 if (!block) return;
00466
00467 for (ShBasicBlock::ShStmtList::iterator I = block->begin(); I != block->end(); ++I) {
00468 I->destroy_info<ValueTracking>();
00469 }
00470 }
00471 };
00472
00473 struct UdDuDumper {
00474 void operator()(ShCtrlGraphNodePtr node) {
00475 if (!node) return;
00476 ShBasicBlockPtr block = node->block;
00477 if (!block) return;
00478
00479 for (ShBasicBlock::ShStmtList::iterator I = block->begin(); I != block->end(); ++I) {
00480 ValueTracking* vt = I->get_info<ValueTracking>();
00481 if (!vt) {
00482 SH_DEBUG_PRINT(*I << " HAS NO VALUE TRACKING");
00483 continue;
00484 }
00485 SH_DEBUG_PRINT("Valuetracking for " << *I);
00486 for (int i = 0; i < opInfo[I->op].arity; i++) {
00487 SH_DEBUG_PRINT(" src ud" << i << "\n" << vt->defs[i]);
00488 }
00489 SH_DEBUG_PRINT(" dest du" << vt->uses);
00490 }
00491 }
00492
00493 void operator()(ShProgramNodePtr p) {
00494 InputValueTracking* ivt = p->get_info<InputValueTracking>();
00495 SH_DEBUG_ASSERT(ivt);
00496 SH_DEBUG_PRINT("Input Valuetracking:\n" << *ivt);
00497
00498 OutputValueTracking* ovt = p->get_info<OutputValueTracking>();
00499 SH_DEBUG_ASSERT(ovt);
00500 SH_DEBUG_PRINT("Output Valuetracking:\n" << *ovt);
00501 }
00502 };
00503
00504 }
00505
00506 namespace SH {
00507
00508 ValueTracking::ValueTracking(ShStatement* stmt)
00509 : uses(stmt->dest.node() ? stmt->dest.size() : 0),
00510 defs(stmt->src.size())
00511 {
00512 #ifdef SH_DEBUG_VALUETRACK
00513 SH_DEBUG_PRINT("Adding value tracking to " << *stmt);
00514 #endif
00515 for (int i = 0; i < opInfo[stmt->op].arity; i++) {
00516 for (int j = 0; j < (stmt->src[i].node() ? stmt->src[i].size() : 0); j++) {
00517 defs[i].push_back(std::set<Def>());
00518 }
00519 }
00520 }
00521
00522 ShInfo* ValueTracking::clone() const
00523 {
00524 return new ValueTracking(*this);
00525 }
00526
00527 std::ostream& operator<<(std::ostream& out, const ValueTracking::Use& use) {
00528 if(use.kind == ValueTracking::Use::STMT) {
00529 out << "(" << *use.stmt << ").src" << use.source << "[" << use.index << "]";
00530 } else {
00531 out << "(OUTPUT " << use.node->name() << ")[" << use.index << "]";
00532 }
00533 return out;
00534 }
00535
00536 std::ostream& operator<<(std::ostream& out, const ValueTracking::TupleUseDefChain& tud)
00537 {
00538 int e = 0;
00539 for (ValueTracking::TupleUseDefChain::const_iterator E = tud.begin();
00540 E != tud.end(); ++E, ++e) {
00541 out << "[" << e << "] <- {";
00542 for (ValueTracking::UseDefChain::const_iterator J = E->begin(); J != E->end(); ++J) {
00543 if(J != E->begin()) out << ", ";
00544 out << *J;
00545 }
00546 out << "}\n";
00547 }
00548 return out;
00549 }
00550
00551 std::ostream& operator<<(std::ostream& out, const ValueTracking::Def& def) {
00552 if(def.kind == ValueTracking::Def::STMT) {
00553 out << "(" << *def.stmt << ").dst" << "[" << def.index << "]";
00554 } else {
00555 out << "(INPUT " << def.node->name() << ")[" << def.index << "]";
00556 }
00557 return out;
00558 }
00559
00560 std::ostream& operator<<(std::ostream& out, const ValueTracking::TupleDefUseChain& tdu)
00561 {
00562 int e = 0;
00563 for (ValueTracking::TupleDefUseChain::const_iterator E = tdu.begin();
00564 E != tdu.end(); ++E, ++e) {
00565 out << "[" << e << "] -> {";
00566 for (ValueTracking::DefUseChain::const_iterator J = E->begin(); J != E->end(); ++J) {
00567 if(J != E->begin()) out << ", ";
00568 out << *J;
00569 }
00570 out << "}\n";
00571 }
00572 return out;
00573 }
00574
00575 ShInfo* InputValueTracking::clone() const
00576 {
00577 return new InputValueTracking(*this);
00578 }
00579
00580
00581 std::ostream& operator<<(std::ostream& out, const InputValueTracking& ivt)
00582 {
00583 InputValueTracking::InputTupleDefUseChain::const_iterator I;
00584 for(I = ivt.inputUses.begin(); I != ivt.inputUses.end(); ++I) {
00585 ShVariableNodePtr node = I->first;
00586 const ValueTracking::TupleDefUseChain& tdu = I->second;
00587 out << node->name();
00588 out << tdu;
00589 }
00590 return out;
00591 }
00592
00593
00594 ShInfo* OutputValueTracking::clone() const
00595 {
00596 return new OutputValueTracking(*this);
00597 }
00598
00599 std::ostream& operator<<(std::ostream& out, const OutputValueTracking& ovt)
00600 {
00601 OutputValueTracking::OutputTupleUseDefChain::const_iterator O;
00602 for(O = ovt.outputDefs.begin(); O != ovt.outputDefs.end(); ++O) {
00603 ShVariableNodePtr node = O->first;
00604 const ValueTracking::TupleUseDefChain& tud = O->second;
00605 out << node->name() << tud;
00606 }
00607 return out;
00608 }
00609
00610 void add_value_tracking(ShProgram& p)
00611 {
00612 ReachingDefs r;
00613
00614 ShCtrlGraphPtr graph = p.node()->ctrlGraph;
00615
00616 DefFinder finder(r, graph->entry(), p.node()->inputs);
00617 graph->dfs(finder);
00618
00619 InitRch init(r);
00620 graph->dfs(init);
00621
00622 bool changed;
00623 IterateRch iter(r, changed);
00624 do {
00625 changed = false;
00626 graph->dfs(iter);
00627 } while (changed);
00628
00629 #ifdef SH_DEBUG_VALUETRACK
00630 SH_DEBUG_PRINT("Dumping Reaching Defs");
00631 SH_DEBUG_PRINT("defsize = " << r.defsize);
00632 SH_DEBUG_PRINT("defs.size() = " << r.defs.size());
00633 for(unsigned int i = 0; i < r.defs.size(); ++i) {
00634 SH_DEBUG_PRINT(" " << i << ": " << r.defs[i]);
00635 }
00636 std::cerr << std::endl;
00637
00638 for (ReachingDefs::ReachingMap::const_iterator I = r.rchin.begin(); I != r.rchin.end(); ++I) {
00639 ShCtrlGraphNodePtr node = I->first;
00640 SH_DEBUG_PRINT(" rchin[" << node.object() << "]: " << I->second);
00641 SH_DEBUG_PRINT(" gen[" << node.object() << "]: " << r.gen[I->first]);
00642 SH_DEBUG_PRINT(" prsv[" << node.object() << "]: " << r.prsv[I->first]);
00643 std::cerr << std::endl;
00644 }
00645 #endif
00646
00647 UdDuClearer clearer;
00648 graph->dfs(clearer);
00649
00650 UdDuBuilder builder(r, p.node());
00651 graph->dfs(builder);
00652
00653 #ifdef SH_DEBUG_VALUETRACK
00654 SH_DEBUG_PRINT("Uddu Dump");
00655 UdDuDumper dumper;
00656 graph->dfs(dumper);
00657 dumper(p.node());
00658 #endif
00659 }
00660
00661
00662
00663 }