00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
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
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
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
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
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
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
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
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
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
00310
if (!newnode) {
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
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
00345 nodeset.push_back(node);
00346 nodeset.push_back(S->second);
00347 newnode =
new ShStructuralNode(ShStructuralNode::WHILELOOP);
00348
break;
00349 }
00350
00351
if (S->second == node) {
00352 nodeset.push_back(node);
00353 newnode =
new ShStructuralNode(ShStructuralNode::SELFLOOP);
00354
break;
00355 }
00356 }
00357 }
00358
00359
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
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
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
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
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
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
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;
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 }