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

ShStructural.cpp

00001 // Sh: A GPU metaprogramming language. 00002 // 00003 // Copyright (c) 2003 University of Waterloo Computer Graphics Laboratory 00004 // Project administrator: Michael D. McCool 00005 // Authors: Zheng Qin, Stefanus Du Toit, Kevin Moule, Tiberiu S. Popa, 00006 // Michael D. McCool 00007 // 00008 // This software is provided 'as-is', without any express or implied 00009 // warranty. In no event will the authors be held liable for any damages 00010 // arising from the use of this software. 00011 // 00012 // Permission is granted to anyone to use this software for any purpose, 00013 // including commercial applications, and to alter it and redistribute it 00014 // freely, subject to the following restrictions: 00015 // 00016 // 1. The origin of this software must not be misrepresented; you must 00017 // not claim that you wrote the original software. If you use this 00018 // software in a product, an acknowledgment in the product documentation 00019 // would be appreciated but is not required. 00020 // 00021 // 2. Altered source versions must be plainly marked as such, and must 00022 // not be misrepresented as being the original software. 00023 // 00024 // 3. This notice may not be removed or altered from any source 00025 // distribution. 00027 #include "ShStructural.hpp" 00028 #include <iostream> 00029 #include <sstream> 00030 #include <map> 00031 #include <set> 00032 #include <algorithm> 00033 #include "ShDebug.hpp" 00034 00035 // #define SH_STRUCTURAL_DEBUG 00036 00037 #ifdef SH_STRUCTURAL_DEBUG 00038 # define SH_STR_DEBUG_PRINT(x) SH_DEBUG_PRINT(x) 00039 #else 00040 # define SH_STR_DEBUG_PRINT(x) 00041 #endif 00042 00043 namespace { 00044 const char* nodetypename[] ={ 00045 "CFGNODE", 00046 "BLOCK", 00047 "IF", 00048 "IFELSE", 00049 "SELFLOOP", 00050 "WHILELOOP" 00051 }; 00052 00053 std::string gvname(const SH::ShStructuralNode* p) 00054 { 00055 std::ostringstream s; 00056 if (p->type == SH::ShStructuralNode::UNREDUCED) { 00057 s << '\"'; 00058 s << p; 00059 s << '\"'; 00060 } else { 00061 s << "cluster_"; 00062 s << p; 00063 } 00064 return s.str(); 00065 } 00066 00067 std::string gvfrom(const SH::ShStructuralNode* p) 00068 { 00069 if (p->type == SH::ShStructuralNode::UNREDUCED) { 00070 return gvname(p); 00071 } else { 00072 return gvname(p) + "_exit_node"; 00073 } 00074 } 00075 00076 std::string gvto(const SH::ShStructuralNode* p) 00077 { 00078 if (p->type == SH::ShStructuralNode::UNREDUCED) { 00079 return gvname(p); 00080 } else { 00081 return gvname(p) + "_entry_node"; 00082 } 00083 } 00084 00085 // Return true if b is a descendent of a 00086 bool descendent(const SH::ShStructuralNodePtr& a, 00087 const SH::ShStructuralNodePtr& b) 00088 { 00089 SH::ShStructuralNode* n = b.object(); 00090 00091 while (n && n != a.object()) { 00092 n = n->parent; 00093 } 00094 00095 return n; 00096 } 00097 00098 template<typename Container, typename T> 00099 bool contains(const Container& c, 00100 const T& v) 00101 { 00102 return find(c.begin(), c.end(), v) != c.end(); 00103 } 00104 00105 template<typename Container> 00106 void reach_under_traverse(SH::ShStructuralNode* head, 00107 SH::ShStructuralNode* node, 00108 Container& r) 00109 { 00110 if (contains(r, node)) return; 00111 if (node == head) return; 00112 00113 r.push_front(node); 00114 for (SH::ShStructuralNode::PredecessorList::iterator I = node->preds.begin(); 00115 I != node->preds.end(); ++I) { 00116 reach_under_traverse(head, I->second, r); 00117 } 00118 } 00119 00120 template<typename T> 00121 void reach_under(const SH::ShStructuralNodePtr& a, 00122 T& container) 00123 { 00124 using namespace SH; 00125 bool backedge = false; 00126 for (ShStructuralNode::PredecessorList::iterator I = a->preds.begin(); 00127 I != a->preds.end(); ++I) { 00128 ShStructuralNode* p = I->second; 00129 // Check that p->a is a backedge 00130 00131 if (!descendent(a, p)) continue; 00132 00133 reach_under_traverse(a.object(), p, container); 00134 00135 backedge = true; 00136 } 00137 00138 if (backedge) container.push_front(a.object()); 00139 } 00140 00141 } 00142 00143 namespace SH { 00144 00145 ShStructuralNode::ShStructuralNode(const ShCtrlGraphNodePtr& node) 00146 : type(UNREDUCED), 00147 container(0), 00148 cfg_node(node), 00149 parent(0) 00150 { 00151 } 00152 00153 ShStructuralNode::ShStructuralNode(NodeType type) 00154 : type(type), 00155 container(0), 00156 cfg_node(0), 00157 parent(0) 00158 { 00159 } 00160 00161 00162 std::ostream& ShStructuralNode::dump(std::ostream& out, int noedges) const 00163 { 00164 if (noedges != 0) { 00165 if (type == UNREDUCED) { 00166 out << gvname(this) << " "; 00167 if (cfg_node->block) { 00168 out << "[label=\""; 00169 cfg_node->block->graphvizDump(out); 00170 out << "\", shape=box]"; 00171 } else { 00172 out << " [label=\"\", shape=circle, height=0.25]"; 00173 } 00174 out << ";" << std::endl; 00175 } else { 00176 out << "subgraph " << gvname(this) << " {" << std::endl; 00177 out << "subgraph " << gvname(this) << "_entry { "; 00178 out << " " << gvname(this) << "_entry_node [label=\"\",shape=box,fillcolor=green,style=filled];"; 00179 out << " label=\"\";" << std::endl; 00180 out << " }" << std::endl; 00181 for (StructNodeList::const_iterator I = structnodes.begin(); I != structnodes.end(); ++I) { 00182 (*I)->dump(out, 1); 00183 } 00184 out << " label=\"" << nodetypename[type]; 00185 // out << " [" << gvname(this) << "]"; 00186 out << "\";" << std::endl; 00187 out << "subgraph " << gvname(this) << "_exit { "; 00188 out << " " << gvname(this) << "_exit_node [label=\"\",shape=box,fillcolor=red,style=filled];"; 00189 out << " label=\"\";" << std::endl; 00190 out << " }" << std::endl; 00191 out << "}" << std::endl; 00192 } 00193 } 00194 00195 if (noedges <= 0) { 00196 for (SuccessorList::const_iterator I = succs.begin(); I != succs.end(); ++I) { 00197 //if (find(children.begin(), children.end(), I->second) != children.end()) continue; 00198 out << gvfrom(this) << " -> " << gvto(I->second.object()); 00199 if (I->first.node()) { 00200 out << " [style=dashed,label=\"" << I->first.name() << "\"]"; 00201 } 00202 out << ";" << std::endl; 00203 } 00204 for (StructNodeList::const_iterator I = structnodes.begin(); I != structnodes.end(); ++I) { 00205 (*I)->dump(out, 0); 00206 } 00207 00208 } 00209 00210 #if 0 00211 out << gvname(this) << " "; 00212 out << " [shape=circle]"; 00213 out << ";" << std::endl; 00214 00215 for (ChildList::const_iterator I = children.begin(); I != children.end(); ++I) { 00216 (*I)->dump(out); 00217 out << gvname(this) << " -> " << gvname(I->object()) << ";" << std::endl; 00218 } 00219 #endif 00220 return out; 00221 } 00222 00223 ShStructural::ShStructural(const ShCtrlGraphPtr& graph) 00224 : m_graph(graph), 00225 m_head(0) 00226 { 00227 // Build DFS spanning tree, and postorder traversal stack 00228 00229 graph->entry()->clearMarked(); 00230 m_head = build_tree(graph->entry()); 00231 graph->entry()->clearMarked(); 00232 00233 bool changed; 00234 do { 00235 changed = false; 00236 build_postorder(m_head); 00237 00238 while (!m_postorder.empty()) { 00239 SH_STR_DEBUG_PRINT("Considering a node"); 00240 00241 ShStructuralNode* node = m_postorder.front(); 00242 m_postorder.pop_front(); 00243 00244 typedef std::list<ShStructuralNodePtr> NodeSet; 00245 NodeSet nodeset; 00246 ShStructuralNodePtr newnode = 0; 00247 00248 if (!newnode) { 00249 // Check for blocks 00250 00251 ShStructuralNodePtr n = node; 00252 00253 bool p = true; 00254 bool s = n->succs.size() == 1; 00255 00256 while (p && s) { 00257 nodeset.push_back(n); 00258 n = n->succs.begin()->second; 00259 p = n->preds.size() == 1; 00260 s = n->succs.size() == 1; 00261 } 00262 00263 if (p && n != node) nodeset.push_back(n); 00264 n = node; p = n->preds.size() == 1; s = true; 00265 while (p && s) { 00266 if (n != node) nodeset.push_front(n); 00267 n = n->preds.begin()->second; 00268 p = n->preds.size() == 1; 00269 s = n->succs.size() == 1; 00270 } 00271 if (s && n != node) nodeset.push_front(n); 00272 00273 if (nodeset.size() >= 2) { 00274 SH_STR_DEBUG_PRINT("FOUND BLOCK of size " << nodeset.size()); 00275 for (NodeSet::iterator I = nodeset.begin(); I != nodeset.end(); ++I) { 00276 SH_STR_DEBUG_PRINT(" node " << I->object()); 00277 } 00278 //node = n.object(); 00279 newnode = new ShStructuralNode(ShStructuralNode::BLOCK); 00280 } else { 00281 nodeset.clear(); 00282 } 00283 } else { 00284 SH_STR_DEBUG_PRINT("Not a block. |succs| = " << node->succs.size()); 00285 if (!node->succs.empty()) { 00286 ShStructuralNodePtr next = (node->succs.begin()->second); 00287 SH_STR_DEBUG_PRINT("|next->preds| = " << next->preds.size()); 00288 for (ShStructuralNode::PredecessorList::iterator P = next->preds.begin(); 00289 P != next->preds.end(); ++P) { 00290 SH_STR_DEBUG_PRINT("next pred = " << P->second); 00291 } 00292 } 00293 } 00294 if (!newnode 00295 && node->succs.size() == 2) { 00296 // Check for if-else 00297 ShStructuralNode::SuccessorList::iterator S = node->succs.begin(); 00298 ShStructuralNodePtr m = S->second; 00299 ShStructuralNodePtr n = (++S)->second; 00300 if (m->succs == n->succs && m->succs.size() == 1) { 00301 SH_STR_DEBUG_PRINT("FOUND IF-ELSE"); 00302 nodeset.push_back(node); 00303 nodeset.push_back(m); 00304 nodeset.push_back(n); 00305 newnode = new ShStructuralNode(ShStructuralNode::IFELSE); 00306 } 00307 } 00308 00309 // Find cyclic regions 00310 if (!newnode) { 00311 /* 00312 typedef std::list<ShStructuralNode*> ReachUnder; 00313 // typedef NodeSet ReachUnder; 00314 ReachUnder ru; 00315 reach_under(node, ru); 00316 SH_STR_DEBUG_PRINT("Reach under set for " << node); 00317 for (ReachUnder::iterator I = ru.begin(); I != ru.end(); ++I) { 00318 SH_STR_DEBUG_PRINT(" " << *I); 00319 } 00320 00321 if (ru.size() == 1) { 00322 SH_STR_DEBUG_PRINT("FOUND SELFLOOP"); 00323 SH_DEBUG_ASSERT(ru.front() == node); 00324 newnode = new ShStructuralNode(ShStructuralNode::SELFLOOP); 00325 } else 00326 if (ru.size() == 2 && ru.back()->succs.size() == 1) { 00327 SH_STR_DEBUG_PRINT("FOUND WHILELOOP"); 00328 SH_DEBUG_ASSERT(ru.front() == node); 00329 SH_DEBUG_ASSERT(ru.back() != node); 00330 newnode = new ShStructuralNode(ShStructuralNode::WHILELOOP); 00331 } 00332 if (newnode) { 00333 for (ReachUnder::iterator I = ru.begin(); I != ru.end(); ++I) { 00334 nodeset.push_back(*I); 00335 } 00336 } 00337 */ 00338 00339 for (ShStructuralNode::SuccessorList::iterator S = node->succs.begin(); 00340 S != node->succs.end(); ++S) { 00341 if (S->second->preds.size() == 1 00342 && S->second->succs.size() == 1 00343 && S->second->succs.begin()->second == node) { 00344 // found while loop 00345 nodeset.push_back(node); 00346 nodeset.push_back(S->second); 00347 newnode = new ShStructuralNode(ShStructuralNode::WHILELOOP); 00348 break; 00349 } 00350 // self loop? 00351 if (S->second == node) { 00352 nodeset.push_back(node); 00353 newnode = new ShStructuralNode(ShStructuralNode::SELFLOOP); 00354 break; 00355 } 00356 } 00357 } 00358 00359 // Fix up the graph. 00360 if (newnode) { 00361 changed = true; 00362 newnode->structnodes = nodeset; 00363 00364 for (NodeSet::iterator N = nodeset.begin(); N != nodeset.end(); ++N) { 00365 (*N)->container = newnode.object(); 00366 } 00367 00368 SH_STR_DEBUG_PRINT("Parent, preds and succs"); 00369 00370 newnode->parent = nodeset.front()->parent; 00371 00372 00373 for (NodeSet::iterator N = nodeset.begin(); N != nodeset.end(); ++N) { 00374 ShStructuralNodePtr n = *N; 00375 00376 for (ShStructuralNode::PredecessorList::iterator P = n->preds.begin(); 00377 P != n->preds.end(); ++P) { 00378 if (N == nodeset.begin() && newnode->type == ShStructuralNode::BLOCK 00379 && P->second == nodeset.back().object()) { 00380 ShStructuralNode::PredecessorEdge e = *P; 00381 e.second = newnode.object(); 00382 newnode->preds.push_back(e); 00383 continue; 00384 } 00385 if (contains(newnode->preds, *P)) continue; 00386 if (contains(nodeset, P->second)) continue; 00387 00388 newnode->preds.push_back(*P); 00389 } 00390 for (ShStructuralNode::SuccessorList::iterator S = n->succs.begin(); 00391 S != n->succs.end(); ++S) { 00392 if (contains(newnode->succs, *S)) continue; 00393 if (n == nodeset.back() && newnode->type == ShStructuralNode::BLOCK 00394 && S->second == nodeset.front()) { 00395 ShStructuralNode::SuccessorEdge e = *S; 00396 e.second = newnode; 00397 newnode->succs.push_back(e); 00398 continue; 00399 } 00400 if (contains(nodeset, S->second)) continue; 00401 newnode->succs.push_back(*S); 00402 } 00403 for (ShStructuralNode::ChildList::iterator C = n->children.begin(); 00404 C != n->children.end(); ++C) { 00405 if (contains(nodeset, *C)) continue; 00406 newnode->children.push_back(*C); 00407 } 00408 00409 // Replace children of parent 00410 if (n->parent && !contains(nodeset, n->parent)) { 00411 SH_STR_DEBUG_PRINT("Replace children of parent"); 00412 for (ShStructuralNode::ChildList::iterator I = n->parent->children.begin(); 00413 I != n->parent->children.end(); ++I) { 00414 if (*I == n) *I = newnode; 00415 } 00416 } 00417 m_postorder.remove(n.object()); 00418 } 00419 00420 SH_STR_DEBUG_PRINT("Replace parent of children"); 00421 // Replace parent of children 00422 for (ShStructuralNode::ChildList::iterator I = newnode->children.begin(); 00423 I != newnode->children.end(); ++I) { 00424 (*I)->parent = newnode.object(); 00425 } 00426 00427 SH_STR_DEBUG_PRINT("Replace preds of succs"); 00428 // Replace preds of succs 00429 for (ShStructuralNode::SuccessorList::iterator I = newnode->succs.begin(); 00430 I != newnode->succs.end(); ++I) { 00431 ShStructuralNodePtr s = I->second; 00432 for (ShStructuralNode::PredecessorList::iterator J = s->preds.begin(); 00433 J != s->preds.end(); ++J) { 00434 if (contains(nodeset, J->second)) J->second = newnode.object(); 00435 } 00436 // Make preds unique. 00437 for (ShStructuralNode::PredecessorList::iterator J = s->preds.begin(); 00438 J != s->preds.end(); ++J) { 00439 ShStructuralNode::PredecessorList::iterator K = J; 00440 ++K; 00441 if (std::find(K, s->preds.end(), *J) != s->preds.end()) { 00442 J = s->preds.erase(J); 00443 J--; 00444 } 00445 } 00446 } 00447 00448 SH_STR_DEBUG_PRINT("Replace succs of preds"); 00449 // Replace succs of preds 00450 for (ShStructuralNode::PredecessorList::iterator I = newnode->preds.begin(); 00451 I != newnode->preds.end(); ++I) { 00452 ShStructuralNode* p = I->second; 00453 for (ShStructuralNode::SuccessorList::iterator J = p->succs.begin(); 00454 J != p->succs.end(); ++J) { 00455 if (contains(nodeset, J->second)) J->second = newnode; 00456 } 00457 // Make succs unique. 00458 for (ShStructuralNode::SuccessorList::iterator J = p->succs.begin(); 00459 J != p->succs.end(); ++J) { 00460 ShStructuralNode::SuccessorList::iterator K = J; 00461 ++K; 00462 if (std::find(K, p->succs.end(), *J) != p->succs.end()) { 00463 J = p->succs.erase(J); 00464 J--; 00465 } 00466 } 00467 } 00468 00469 SH_STR_DEBUG_PRINT("Add to postorder"); 00470 m_postorder.push_back(newnode.object()); 00471 00472 if (nodeset.front() == m_head) { 00473 SH_STR_DEBUG_PRINT("Replace head"); 00474 m_head = newnode; 00475 } 00476 } 00477 } 00478 } while (changed); 00479 } 00480 00481 std::ostream& ShStructural::dump(std::ostream& out) const 00482 { 00483 out << "digraph structural {" << std::endl; 00484 m_head->dump(out); 00485 00486 int counter = 1; 00487 for (PostorderList::const_iterator I = m_postorder.begin(); I != m_postorder.end(); ++I) { 00488 out << "\"" << *I << "\" [label=\"" << counter << "\"];" << std::endl; 00489 counter++; 00490 } 00491 out << "}" << std::endl; 00492 return out; 00493 } 00494 00495 ShStructuralNodePtr ShStructural::build_tree(const ShCtrlGraphNodePtr& node) 00496 { 00497 static std::map<ShCtrlGraphNodePtr, ShStructuralNodePtr> nodemap; 00498 using std::make_pair; 00499 00500 if (!node) return 0; 00501 if (node->marked()) return 0; 00502 node->mark(); 00503 00504 ShStructuralNodePtr snode = new ShStructuralNode(node); 00505 00506 nodemap[node] = snode; 00507 00508 for (ShCtrlGraphNode::SuccessorList::iterator I = node->successors.begin(); 00509 I != node->successors.end(); ++I) { 00510 if (!I->node) continue; // should never happen 00511 ShStructuralNodePtr child = build_tree(I->node); 00512 if (child) { 00513 child->parent = snode.object(); 00514 snode->children.push_back(child); 00515 } 00516 00517 snode->succs.push_back(make_pair(I->cond, nodemap[I->node])); 00518 nodemap[I->node]->preds.push_back(make_pair(I->cond, snode.object())); 00519 } 00520 00521 if (node->follower) { 00522 ShStructuralNodePtr fchild = build_tree(node->follower); 00523 if (fchild) { 00524 fchild->parent = snode.object(); 00525 snode->children.push_back(fchild); 00526 } 00527 snode->succs.push_back(make_pair(ShVariable(), nodemap[node->follower])); 00528 nodemap[node->follower]->preds.push_back(make_pair(ShVariable(), snode.object())); 00529 } 00530 00531 return snode; 00532 } 00533 00534 void ShStructural::build_postorder(const ShStructuralNodePtr& node) 00535 { 00536 if (node == m_head) { 00537 m_postorder.clear(); 00538 } 00539 00540 for (ShStructuralNode::ChildList::iterator I = node->children.begin(); 00541 I != node->children.end(); ++I) { 00542 build_postorder(*I); 00543 } 00544 00545 m_postorder.push_back(node.object()); 00546 } 00547 00548 const ShStructuralNodePtr& ShStructural::head() 00549 { 00550 return m_head; 00551 } 00552 00553 }

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