OpenADFortTk (including Open64 and OpenAnalysis references)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
NestedSCR.cpp
Go to the documentation of this file.
1 
39 //************************** System Include Files ***************************
40 
41 #include <iostream>
42 using std::cout;
43 #include <algorithm> // for max
44 #include <map>
45 #include <list>
46 
47 #ifdef NO_STD_CHEADERS
48 # include <string.h>
49 # include <stdio.h>
50 # include <limits.h>
51 #else
52 # include <cstring>
53 # include <cstdio>
54 # include <climits>
55 using namespace std; // For compatibility with non-std C headers
56 #endif
57 
58 #include <unistd.h>
59 
60 //*************************** User Include Files ****************************
61 
63 
64 //*************************** Forward Declarations **************************
65 
68 
69 //*************************** Forward Declarations **************************
70 
71 namespace OA {
72 
73 //------------------------------------------------------------------------
74 // TarjWork: There will be an array of TarjWorks, one for each node.
75 // These are indexed by the DFS number of the node. This way, there
76 // is no dependence on the node numbering of the underlying graph.
77 //------------------------------------------------------------------------
78 
79 class TarjWork {
80 public:
81  TarjWork();
82  ~TarjWork();
83 
84  RIFG::NodeId wk_vertex; // map from DFS# of vertex to RIFGNodeId
85  OA::NestedSCR::DFNUM_t wk_last; // DFS # of vertex's last descendant
86  OA::NestedSCR::DFNUM_t wk_header; // header of the vertex's interval - HIGHPT
87  OA::NestedSCR::DFNUM_t wk_nextP; // next member of P set == reachunder
88  OA::NestedSCR::DFNUM_t wk_nextQ; // next member of Q set == worklist
89  bool wk_inP; // test for membership in P == reachunder
90  bool wk_isCyclic; // has backedges -- to id singles
91  bool wk_reducible; // true if cyclic scr is reducible
92  std::list<int> backPreds; // List of preds that are backedges.
93  std::list<int> nonBackPreds; // List of preds that are non-backedges.
94 };
95 
96 
97 TarjWork::TarjWork()
98 {
99  wk_vertex = RIFG::NIL;
100  wk_last = DFNUM_NIL;
101  wk_header = DFNUM_ROOT;
102  wk_nextP = DFNUM_NIL;
103  wk_nextQ = DFNUM_NIL;
104  wk_inP = false;
105  wk_isCyclic = false;
106  wk_reducible = true;
107 }
108 
109 
110 TarjWork::~TarjWork()
111 {
112  backPreds.clear();
113  nonBackPreds.clear();
114 }
115 
116 
117 //------------------------------------------------------------------------
118 // Interval tree will consist of an array of TarjTreeNodes. These
119 // are indexed (internally) by the DFS number of the node. This way,
120 // there is no dependence on the node numbering of the underlying graph.
121 //
122 // There is also a map from RIFGNodeIds to DFS numbers, so
123 // that tree nodes can be accessed (by the client) through their
124 // node ids.
125 //------------------------------------------------------------------------
126 
128 public:
129  TarjTreeNode();
130  RIFG::NodeId nodeid; // Associated RIFG::NodeId.
131  short level; // nesting depth -- outermost loop is 1
132  NestedSCR::Node_t type; // acyclic, interval or irreducible
133  OA::NestedSCR::DFNUM_t outer; // DFS number of header of containing interval
134  OA::NestedSCR::DFNUM_t inners; // DFS number of header of first nested interval
135  OA::NestedSCR::DFNUM_t next; // DFS number of next nested header
136  int prenum; // preorder number
137  OA::NestedSCR::DFNUM_t last; // number of last descendent
138  RIFG::NodeId last_id; // id of last descendent
139  short loopIndex; // unique id for intervals
140 };
141 
142 
143 TarjTreeNode::TarjTreeNode()
144 {
145  nodeid = RIFG::NIL;
146  level = 0;
147  type = NestedSCR::NODE_ACYCLIC;
148  outer = DFNUM_NIL;
149  inners = DFNUM_NIL;
150  next = DFNUM_NIL;
151  prenum = -1;
152  last = DFNUM_NIL;
153  last_id = RIFG::NIL;
154  loopIndex = -1;
155 }
156 
157 } // end of namespace OA
158 
159 
160 
161 //***************************************************************************
162 // NestedSCR
163 //***************************************************************************
164 
165 namespace OA {
166 
167  // Refers to members in TarjTreeNode
168 #define TARJ_nodeid(name) (tarj[name].nodeid)
169 #define TARJ_outer(name) (tarj[name].outer)
170 #define TARJ_inners(name) (tarj[name].inners)
171 #define TARJ_next(name) (tarj[name].next)
172 #define TARJ_level(name) (tarj[name].level)
173 #define TARJ_type(name) (tarj[name].type)
174 #define TARJ_last(name) (tarj[name].last)
175 #define TARJ_last_id(name) (tarj[name].last_id)
176 #define TARJ_loopIndex(name) (tarj[name].loopIndex)
177 #define TARJ_contains(a,b) \
178  ( ( tarj[a].prenum <= tarj[b].prenum ) && \
179  ( tarj[b].prenum <= tarj[tarj[a].last].prenum ) \
180  )
181 
182  // Refers to members in TarjWork
183 #define vertex(x) (wk[x].wk_vertex)
184 #define TLast(x) (wk[x].wk_last)
185 #define header(x) (wk[x].wk_header)
186 #define nextP(x) (wk[x].wk_nextP)
187 #define nextQ(x) (wk[x].wk_nextQ)
188 #define inP(x) (wk[x].wk_inP)
189 #define isCyclic(x) (wk[x].wk_isCyclic)
190 #define reducible(x) (wk[x].wk_reducible)
191 #define backPreds(x) (wk[x].backPreds)
192 #define nonBackPreds(x) (wk[x].nonBackPreds)
193 
194 static int n; // next DFS preorder number
195 static int last_id; // RIFG::NodeId whose DFS preorder number is n
196 
197 //
198 // is_backedge(a,b) returns true if a is a descendant of b in DFST
199 // (a and b are the DFS numbers of the corresponding vertices).
200 //
201 // Note that this is in the local structures; corresponds somewhat
202 // to Contains(tarj,b,a) for the public structures.
203 //
204 //
205 #define is_backedge(a,b) ((b <= a) & (a <= TLast(b)))
206 
207 #define dfnum(v) (nodeid_to_dfnum_map[v])
208 
209 
210 NestedSCR::NestedSCR(OA::OA_ptr<OA::RIFG> rifg_)
211  : rifg(rifg_)
212 {
213  Create();
214 }
215 
216 
218 {
219  if (tarj)
220  delete[] tarj;
221  if (uf)
222  delete uf;
223  if (wk)
224  delete[] wk;
225  rev_top_list.clear();
226  nodeid_to_dfnum_map.clear();
227 }
228 
229 
230 // Construct tree of Tarjan intervals for the graph
231 void
233 {
234  RIFG::NodeId root = rifg->getSource();
235 
236  Init();
237  DFS(root);
238  FillPredLists();
239  GetTarjans();
240  Build();
241  Sort();
243  FreeWork();
244 }
245 
246 
247 //
248 // Sort the Tarjan Tree in topological ordering
249 //
250 // Feb. 2002 (jle) - Removed the call to GetTopologicalMap which computes
251 // a (breadth-first) topological ordering of the CFG. This is completely
252 // unnecessary (and wasteful) since by virtue of performing a DFS as part of
253 // interval building, we have a topological ordering available as a by-product.
254 // Further, the breadth-first version in GetTopologicalMap is clumsy (in this
255 // context) since it has to make call-backs to the tarjan code to determine
256 // if the current edge being examined is a back-edge (to avoid cycling).
257 //
258 void
260 {
261  RIFG::NodeId gId;
262  int parent; // Tarj parent (loop header)
263 
264  // Now disconnect all "next" fields for all tarj nodes
265 
266  OA_ptr<RIFG::NodesIterator> ni = rifg->getNodesIterator();
267  for ( ; (ni->isValid()); ++(*ni)) {
268  gId = ni->current();
269  int gdfn = dfnum(gId);
270  // gdfn will be invalid if the node gId was unreachable.
271  if (gdfn != DFNUM_NIL) {
272  TARJ_inners(gdfn) = DFNUM_NIL;
273  TARJ_next(gdfn) = DFNUM_NIL;
274  }
275  }
276 
277  // The list is sorted in reverse topological order since each child
278  // in the loop below is prepended to the list of children.
279  std::list<RIFG::NodeId>::iterator i;
280  for (i = rev_top_list.begin(); i != rev_top_list.end(); i++) {
281  gId = *i;
282  if (gId != RIFG::NIL) {
283  // Add new kid
284  int gdfn = dfnum(gId);
285  parent = TARJ_outer(gdfn);
286  if (parent != DFNUM_NIL) {
287  TARJ_next(gdfn) = TARJ_inners(parent);
288  TARJ_inners(parent) = gdfn;
289  }
290  }
291  }
292 
293  Renumber();
294 } // end of tarj_sort()
295 
296 
297 TarjTreeNode*
299 {
300  return tarj;
301 }
302 
303 
304 
305 //
306 // Allocate and initialize structures for algorithm, and UNION-FIND
307 //
308 void
310 {
311  unsigned int g_size = rifg->getHighWaterMarkNodeId() + 1;
312 
313  n = DFNUM_ROOT;
314 
315  //
316  // Local work space
317  //
318  wk = new TarjWork[g_size];
319  uf = new UnionFindUniverse(g_size);
320  tarj = new TarjTreeNode[g_size];
321  InitArrays();
322 }
323 
324 
325 //
326 // Initialize only nodes in current instance g
327 //
328 void
330 {
331  OA_ptr<RIFG::NodesIterator> ni = rifg->getNodesIterator();
332  for ( ; ni->isValid(); ++(*ni)) {
333  int nid = ni->current();
334  dfnum(nid) = DFNUM_NIL;
335  }
336 }
337 
338 
339 //
340 // Do depth first search on control flow graph to
341 // initialize vertex[], dfnum[], last[]
342 //
343 void
345 {
346  vertex(n) = v;
347  dfnum(v) = n++;
348 
349  RIFG::EdgeId succ;
350  OA_ptr<RIFG::OutgoingEdgesIterator> ei = rifg->getOutgoingEdgesIterator(v);
351  for (; (ei->isValid()); ++(*ei)) {
352  succ = ei->current();
353  int son = rifg->getEdgeSink(succ);
354  if (dfnum(son) == DFNUM_NIL)
355  DFS(son);
356  }
357 
358  //
359  // Equivalent to # of descendants -- number of last descendant
360  //
361  TLast(dfnum(v)) = n-1;
362  rev_top_list.push_back(v);
363 }
364 
365 
366 // Fill in the backPreds and nonBackPreds lists for each node.
367 void
369 {
370  for (int i = DFNUM_ROOT; i < n; i++) {
372  rifg->getIncomingEdgesIterator(vertex(i) );
373  for ( ; (ei->isValid()); ++(*ei)) {
374  int prednum = dfnum(rifg->getEdgeSrc(ei->current()));
375  if (is_backedge(prednum, i)) {
376  backPreds(i).push_back(prednum);
377  } else {
378  nonBackPreds(i).push_back(prednum);
379  }
380  } // for preds
381  } // for nodes
382 }
383 
384 
385 //
386 // In bottom-up traversal of depth-first spanning tree,
387 // determine nested strongly connected regions and flag irreducible regions.
388 // phh, 4 Mar 91
389 //
390 void
392 {
393  int w; // DFS number of current vertex
394  DFNUM_t firstP, firstQ; // set and worklist
395 
396  //
397  // Following loop should skip root (prenumbered as 0)
398  //
399  for (w = n - 1; w != DFNUM_ROOT; w--) // loop c
400  //
401  // skip any nodes freed or not reachable
402  //
403  if (w != DFNUM_NIL && rifg->isValid(vertex(w))) {
404  firstP = firstQ = DFNUM_NIL;
405  //
406  // Add sources of cycle arcs to P -- and to worklist Q
407  //
408  std::list<int>::iterator prednum;
409  for (prednum = backPreds(w).begin(); prednum != backPreds(w).end();
410  prednum++) { // loop d
411  int u,v; // vertex names
412  v = *prednum;
413  // ignore predecessors not reachable
414  if (v != DFNUM_NIL)
415  {
416  if (v == w) {
417  //
418  // Don't add w to its own P and Q sets
419  //
420  isCyclic(w) = true;
421  } else {
422  //
423  // Add FIND(v) to P and Q
424  //
425  u = FIND(v);
426  if (!inP(u)) {
427  nextP(u) = nextQ(u) = firstP;
428  firstP = firstQ = u;
429  inP(u) = true;
430  } // if (!inP(u))
431  } // if (v == w)
432  } // if
433  } // for preds
434 
435  //
436  // P nonempty -> w is header of a loop
437  //
438  if (firstP != DFNUM_NIL)
439  isCyclic(w) = true;
440 
441  while (firstQ != DFNUM_NIL) {
442  int x, y, yy; // DFS nums of vertices
443 
444  x = firstQ;
445  firstQ = nextQ(x); // remove x from worklist
446 
447  //
448  // Now look at non-cycle arcs
449  //
450  std::list<int>::iterator prednum;
451  for (prednum = nonBackPreds(x).begin();
452  prednum != nonBackPreds(x).end();
453  prednum++) { // loop d
454  y = *prednum;
455 
456  //
457  // ignore predecessors not reachable
458  //
459  if (y != DFNUM_NIL)
460  {
461  //
462  // Add FIND(y) to P and Q
463  //
464  yy = FIND(y);
465 
466  if (is_backedge(yy, w)) {
467  if ((!inP(yy)) & (yy != w)) {
468  nextP(yy) = firstP;
469  nextQ(yy) = firstQ;
470  firstP = firstQ = yy;
471  inP(yy) = true;
472  }
473  //
474  // Slight change to published alg'm...
475  // moved setting of header (HIGHPT)
476  // from here to after the union.
477  //
478  } else {
479  //
480  // Irreducible region!
481  //
482  reducible(w) = false;
483 #if 1
484  // FIXME: The DSystem version of the code did not have the
485  // following line. However, this line IS in the 1997 article,
486  // and I believe it is necessary (jle, 03-02-2002).
487  nonBackPreds(w).push_back(yy);
488 #endif
489  }
490  }
491  }
492  }
493  //
494  // now P = P(w) as in Tarjan's paper
495  //
496  while (firstP != DFNUM_NIL) {
497  //
498  // First line is a change to published algorithm;
499  // Want sources of cycle edges to have header w
500  // and w itself not to have header w.
501  //
502  if ((header(firstP) == DFNUM_ROOT) & (firstP != w))
503  header(firstP) = w;
504  UNION(firstP, w, w);
505  inP(firstP) = false;
506  firstP = nextP(firstP);
507  } // while
508  } // if
509 }
510 
511 
512 //
513 // Traverse df spanning tree, building tree of Tarjan intervals
514 //
515 void
517 {
518  int w; // DFS number of current vertex
519  int outer; // DFS number header of surrounding loop
520 
521  TARJ_nodeid(DFNUM_ROOT) = rifg->getSource();
522  //
523  // Let the root of the tree be the root of the instance...
524  // Following loop can skip the root (prenumbered 0)
525  //
526  for (w = DFNUM_ROOT + 1; w < n; w++) {
527  RIFG::NodeId wnode = vertex(w);
528  //
529  // skip any nodes not in current instance g
530  //
531  if (wnode != RIFG::NIL) {
532  outer = header(w);
533  TARJ_outer(w) = outer;
534  TARJ_nodeid(w) = wnode;
535  //
536  // tarj[w].inners = DFNUM_NIL; % done in InitArrays
537  //
538  if (isCyclic(w)) {
539  //
540  // Level is deeper than outer if this is a loop
541  //
542  if (reducible(w)) {
544  TARJ_level(w) = TARJ_level(outer) + 1;
545  } else {
547  TARJ_level(w) = TARJ_level(outer);
548  }
549  } else {
550  //
551  // tarj[w].type = RI_TARJ_ACYCLIC; % done in InitArrays
552  //
553  TARJ_level(w) = TARJ_level(outer);
554  }
555  TARJ_next(w) = TARJ_inners(outer);
556  TARJ_inners(outer) = w;
557  }
558  }
559  n = 0;
561 }
562 
563 
564 void
566 {
567  int inner;
568 
569  tarj[v].prenum = ++n;
570  last_id = TARJ_nodeid(v);
571 
572  for (inner = TARJ_inners(v); inner != DFNUM_NIL;
573  inner = TARJ_next(inner)) {
574  Prenumber(inner);
575  }
576 
577  /* tarj[v].last = n; // 3/18/93 RvH: switch to RIFG::NodeId last_id */
578  tarj[v].last_id = last_id;
579  tarj[v].last = dfnum(last_id);
580 }
581 
582 
583 void
585 {
586  tarj = tarj;
587  n = 0;
589 }
590 
591 
592 // Free all space used in computation of
593 // Tarjan interval tree (but not tree itself)
594 void
596 {
597  delete[] wk;
598  wk = 0;
599 
600  delete uf;
601  uf = 0;
602 }
603 
604 
605 static int loopIndex;
606 void
608 {
609  int kid, valKid;
610 
611  TARJ_loopIndex(node) = value;
612  if (TARJ_inners(node) != DFNUM_NIL)
613  valKid = ++loopIndex;
614 
615  for (kid = TARJ_inners(node); kid != DFNUM_NIL; kid = TARJ_next(kid))
616  ComputeIntervalIndexSubTree(kid, valKid);
617 }
618 
619 
620 void
622 {
623  loopIndex = 0;
625 }
626 
627 
628 void
629 NestedSCR::dump(std::ostream& os)
630 {
631  printf("Tarjan interval tree: <node id>(level,type)::IntervalIndex\n");
632  DumpSubTree(os, DFNUM_ROOT, 0 /* Indent */);
633 }
634 
635 
636 //
637 // Feb. 2002 (jle): Got rid of all the silly concatenating of blank
638 // strings. The %*s format specifier is far simpler for creating indentations.
639 //
640 void
641 NestedSCR::DumpSubTree(std::ostream& os, int node, int indent)
642 {
643  static const char *NodeType[] = {"NOTHING", "Acyclic",
644  "Interval", "Irreducible"};
645  //
646  // Indent by three
647  //
648  if (indent < 72)
649  indent += 3;
650 
651  printf("%*s%d(%d,%s)::%d\n", indent, " ",
652  TARJ_nodeid(node), TARJ_level(node),
653  NodeType[(int) (TARJ_type(node))], TARJ_loopIndex(node));
654 
655  for (int kid = TARJ_inners(node); kid != DFNUM_NIL;
656  kid = TARJ_next(kid)) {
657  DumpSubTree(os, kid, indent);
658  }
659 
660  //
661  // Unindent
662  //
663  if (indent >= 3)
664  indent -= 3;
665 }
666 
667 
668 int
670 {
671  return uf->Find(v);
672 }
673 
674 
675 void
676 NestedSCR::UNION(int i, int j, int k)
677 {
678  uf->Union(i,j,k);
679 }
680 
681 
682 //
683 // Return number of loops exited in traversing g edge from src to sink
684 // (0 is normal).
685 //
686 int
688 {
689  RIFG::NodeId lca = LCA(src, sink);
690  if (lca == RIFG::NIL)
691  return 0;
692 
693  int dfn_src = dfnum(src);
694  int dfn_lca = dfnum(lca);
695  return std::max(0, TARJ_level(dfn_src) - TARJ_level(dfn_lca));
696 }
697 
698 
699 //
700 // Return outermost loop exited in traversing g edge from src to sink
701 // (RIFG::NIL if no loops exited).
702 //
705 {
706  RIFG::NodeId lca = LCA(src, sink);
707  if (lca == RIFG::NIL)
708  return RIFG::NIL;
709 
710  if (lca == src)
711  return RIFG::NIL;
712 
713  int dfn_src = dfnum(src);
714  while (!Contains(TARJ_nodeid(TARJ_outer(dfn_src)), sink))
715  dfn_src = TARJ_outer(dfn_src);
716 
717  if (TARJ_type(dfn_src) == NODE_INTERVAL
718  || TARJ_type(dfn_src) == NODE_IRREDUCIBLE)
719  return TARJ_nodeid(dfn_src);
720 
721  return RIFG::NIL;
722 }
723 
724 
725 //
726 // Return type of g edge from src to sink, one of
727 // RI_TARJ_NORMAL
728 // RI_TARJ_LOOP_ENTRY
729 // RI_TARJ_IRRED_ENTRY
730 // RI_TARJ_ITERATE (back edge)
731 //
734 {
735  RIFG::NodeId anc = LCA(src, sink);
736  int dfn_sink = dfnum(sink);
737  int dfn_anc = dfnum(anc);
738 
739  if (dfn_anc == dfn_sink) {
740  return EDGE_ITERATE;
741  }
742  else if (TARJ_outer(dfn_sink) != DFNUM_NIL
743  && (TARJ_type(TARJ_outer(dfn_sink)) == NODE_IRREDUCIBLE)
744  && (dfn_anc != TARJ_outer(dfn_sink))) {
745  //
746  // Entering irreducible region not through the "header"
747  //
748  return EDGE_IRRED_ENTRY;
749  }
750  else {
751  switch (TARJ_type(dfn_sink)) {
752  case NODE_INTERVAL:
753  return EDGE_LOOP_ENTRY;
754  case NODE_IRREDUCIBLE:
755  //
756  // Entering irreducible region through the "header"
757  //
758  return EDGE_IRRED_ENTRY;
759  case NODE_ACYCLIC:
760  case NODE_NOTHING:
761  default:
762  return EDGE_NORMAL;
763  }
764  }
765 }
766 
767 
768 //
769 // LCA = least common ancestor
770 //
773 {
774  if ((a == RIFG::NIL) || (b == RIFG::NIL))
775  return RIFG::NIL;
776 
777  if (Contains(a,b))
778  return a;
779 
780  int dfn_b = dfnum(b);
781  while ((dfn_b != DFNUM_NIL) && !Contains(b,a)) {
782  dfn_b = TARJ_outer(dfn_b);
783  b = TARJ_nodeid(dfn_b);
784  }
785 
786  return b;
787 }
788 
789 
790 //
791 // Return true if the CFG edge passed in is an backedge.
792 //
793 // Precondition: Tarjan tree must be built already.
794 //
795 bool
797 {
798  RIFG::NodeId src, dest;
799  src = rifg->getEdgeSrc(edgeId);
800  dest = rifg->getEdgeSink(edgeId);
801  return is_backedge(dfnum(src), dfnum(dest));
802 }
803 
804 
807 {
808  int dfn_inners = TARJ_inners(dfnum(id));
809  return dfn_inners == DFNUM_NIL ? RIFG::NIL : TARJ_nodeid(dfn_inners);
810 }
811 
812 
815 {
816  int dfn_last_id = TARJ_last_id(dfnum(id));
817  return TARJ_nodeid(dfn_last_id);
818 }
819 
820 
823 {
824  int dfn_outer = TARJ_outer(dfnum(id));
825  return dfn_outer == DFNUM_NIL ? RIFG::NIL : TARJ_nodeid(dfn_outer);
826 }
827 
828 
831 {
832  int dfn_next = TARJ_next(dfnum(id));
833  return dfn_next == DFNUM_NIL ? RIFG::NIL : TARJ_nodeid(dfn_next);
834 }
835 
836 
837 
838 bool
840 {
841  return (getInners(dfnum(id)) != DFNUM_NIL);
842 }
843 
844 
845 bool
847 {
848  int dfn_id = dfnum(id);
849 
850  if (getOuter(dfn_id) == DFNUM_NIL)
851  return true;
852 
853  return (getInners(getOuter(dfn_id)) == dfn_id);
854 }
855 
856 
857 bool
859 {
860  return (getNext(dfnum(id)) == DFNUM_NIL);
861 }
862 
863 
864 int
866 {
867  return TARJ_level(dfnum(id));
868 }
869 
870 
873 {
874  return TARJ_type(dfnum(id));
875 }
876 
877 
878 bool
880 {
881  return (TARJ_contains(dfnum(a), dfnum(b)));
882 }
883 
884 
885 int
887 {
888  return TARJ_loopIndex(dfnum(id));
889 }
890 
891 
892 } // end of namespace OA
893