NestedSCR.cpp

Go to the documentation of this file.
00001 
00039 //************************** System Include Files ***************************
00040 
00041 #include <iostream>
00042 using std::cout;
00043 #include <algorithm>     // for max
00044 #include <map>
00045 #include <list>
00046 
00047 #ifdef NO_STD_CHEADERS
00048 # include <string.h>
00049 # include <stdio.h>
00050 # include <limits.h>
00051 #else
00052 # include <cstring>
00053 # include <cstdio>
00054 # include <climits>
00055 using namespace std; // For compatibility with non-std C headers
00056 #endif
00057 
00058 #include <unistd.h>
00059 
00060 //*************************** User Include Files ****************************
00061 
00062 #include <OpenAnalysis/Utils/NestedSCR.hpp>
00063 
00064 //*************************** Forward Declarations **************************
00065 
00066 const OA::NestedSCR::DFNUM_t DFNUM_ROOT = 0;
00067 const OA::NestedSCR::DFNUM_t DFNUM_NIL  = UINT_MAX;
00068 
00069 //*************************** Forward Declarations **************************
00070 
00071 namespace OA {
00072 
00073 //------------------------------------------------------------------------
00074 // TarjWork: There will be an array of TarjWorks, one for each node.
00075 // These are indexed by the DFS number of the node.  This way, there
00076 // is no dependence on the node numbering of the underlying graph.
00077 //------------------------------------------------------------------------
00078 
00079 class TarjWork {
00080 public:
00081   TarjWork();
00082   ~TarjWork();
00083 
00084   RIFG::NodeId wk_vertex;       // map from DFS# of vertex to RIFGNodeId
00085   OA::NestedSCR::DFNUM_t wk_last;   // DFS # of vertex's last descendant
00086   OA::NestedSCR::DFNUM_t wk_header; // header of the vertex's interval - HIGHPT
00087   OA::NestedSCR::DFNUM_t wk_nextP;  // next member of P set == reachunder
00088   OA::NestedSCR::DFNUM_t wk_nextQ;  // next member of Q set == worklist
00089   bool wk_inP;                  // test for membership in P == reachunder
00090   bool wk_isCyclic;             // has backedges -- to id singles
00091   bool wk_reducible;            // true if cyclic scr is reducible
00092   std::list<int> backPreds;     // List of preds that are backedges.
00093   std::list<int> nonBackPreds;  // List of preds that are non-backedges.
00094 };
00095 
00096 
00097 TarjWork::TarjWork() 
00098 {
00099   wk_vertex = RIFG::NIL;
00100   wk_last   = DFNUM_NIL;
00101   wk_header = DFNUM_ROOT;
00102   wk_nextP  = DFNUM_NIL;
00103   wk_nextQ  = DFNUM_NIL;
00104   wk_inP = false;
00105   wk_isCyclic = false;
00106   wk_reducible = true;
00107 }
00108 
00109 
00110 TarjWork::~TarjWork() 
00111 {
00112   backPreds.clear();
00113   nonBackPreds.clear();
00114 }
00115 
00116 
00117 //------------------------------------------------------------------------
00118 // Interval tree will consist of an array of TarjTreeNodes. These
00119 // are indexed (internally) by the DFS number of the node.  This way,
00120 // there is no dependence on the node numbering of the underlying graph. 
00121 //
00122 // There is also a map from RIFGNodeIds to DFS numbers, so
00123 // that tree nodes can be accessed (by the client) through their
00124 // node ids. 
00125 //------------------------------------------------------------------------
00126 
00127 class TarjTreeNode {
00128 public:
00129   TarjTreeNode();
00130   RIFG::NodeId nodeid;  // Associated RIFG::NodeId.
00131   short level;          // nesting depth -- outermost loop is 1 
00132   NestedSCR::Node_t type; // acyclic, interval or irreducible 
00133   OA::NestedSCR::DFNUM_t outer;  // DFS number of header of containing interval
00134   OA::NestedSCR::DFNUM_t inners; // DFS number of header of first nested interval
00135   OA::NestedSCR::DFNUM_t next;  // DFS number of next nested header
00136   int prenum;                   // preorder number
00137   OA::NestedSCR::DFNUM_t last;  // number of last descendent
00138   RIFG::NodeId last_id;         // id of last descendent
00139   short loopIndex;              // unique id for intervals
00140 };
00141 
00142 
00143 TarjTreeNode::TarjTreeNode()
00144 {
00145   nodeid = RIFG::NIL;
00146   level  = 0;
00147   type   = NestedSCR::NODE_ACYCLIC;
00148   outer  = DFNUM_NIL;
00149   inners = DFNUM_NIL;
00150   next   = DFNUM_NIL;
00151   prenum = -1;
00152   last   = DFNUM_NIL;   
00153   last_id = RIFG::NIL;
00154   loopIndex = -1;
00155 }
00156 
00157 } // end of namespace OA
00158 
00159 
00160 
00161 //***************************************************************************
00162 // NestedSCR
00163 //***************************************************************************
00164 
00165 namespace OA {
00166   
00167   // Refers to members in TarjTreeNode
00168 #define TARJ_nodeid(name)       (tarj[name].nodeid)
00169 #define TARJ_outer(name)        (tarj[name].outer)
00170 #define TARJ_inners(name)       (tarj[name].inners)
00171 #define TARJ_next(name)         (tarj[name].next)
00172 #define TARJ_level(name)        (tarj[name].level)
00173 #define TARJ_type(name)         (tarj[name].type)
00174 #define TARJ_last(name)         (tarj[name].last)
00175 #define TARJ_last_id(name)      (tarj[name].last_id)
00176 #define TARJ_loopIndex(name)    (tarj[name].loopIndex)
00177 #define TARJ_contains(a,b)      \
00178     ( ( tarj[a].prenum <= tarj[b].prenum ) && \
00179       ( tarj[b].prenum <= tarj[tarj[a].last].prenum ) \
00180     )
00181 
00182   // Refers to members in TarjWork
00183 #define vertex(x)       (wk[x].wk_vertex)
00184 #define TLast(x)        (wk[x].wk_last)
00185 #define header(x)       (wk[x].wk_header)
00186 #define nextP(x)        (wk[x].wk_nextP)
00187 #define nextQ(x)        (wk[x].wk_nextQ)
00188 #define inP(x)          (wk[x].wk_inP)
00189 #define isCyclic(x)     (wk[x].wk_isCyclic)
00190 #define reducible(x)    (wk[x].wk_reducible)
00191 #define backPreds(x)    (wk[x].backPreds)
00192 #define nonBackPreds(x) (wk[x].nonBackPreds)
00193 
00194 static int n;           // next DFS preorder number
00195 static int last_id;     // RIFG::NodeId whose DFS preorder number is n
00196 
00197 //
00198 // is_backedge(a,b) returns true if a is a descendant of b in DFST
00199 // (a and b are the DFS numbers of the corresponding vertices). 
00200 //
00201 // Note that this is in the local structures; corresponds somewhat
00202 // to Contains(tarj,b,a) for the public structures.
00203 //
00204 //
00205 #define is_backedge(a,b) ((b <= a) & (a <= TLast(b)))
00206 
00207 #define dfnum(v)                (nodeid_to_dfnum_map[v])
00208 
00209 
00210 NestedSCR::NestedSCR(OA::OA_ptr<OA::RIFG> rifg_)
00211   : rifg(rifg_)
00212 {
00213   Create();
00214 }
00215 
00216 
00217 NestedSCR::~NestedSCR()
00218 {
00219   if (tarj)
00220     delete[] tarj;
00221   if (uf)
00222     delete uf;
00223   if (wk)
00224     delete[] wk;
00225   rev_top_list.clear();
00226   nodeid_to_dfnum_map.clear();
00227 }
00228 
00229 
00230 // Construct tree of Tarjan intervals for the graph
00231 void 
00232 NestedSCR::Create()
00233 {
00234   RIFG::NodeId root = rifg->getSource();
00235   
00236   Init();
00237   DFS(root);
00238   FillPredLists();
00239   GetTarjans();
00240   Build();
00241   Sort();
00242   ComputeIntervalIndex();
00243   FreeWork();
00244 }
00245 
00246 
00247 //
00248 // Sort the Tarjan Tree in topological ordering
00249 //
00250 // Feb. 2002 (jle) - Removed the call to GetTopologicalMap which computes
00251 // a (breadth-first) topological ordering of the CFG. This is completely
00252 // unnecessary (and wasteful) since by virtue of performing a DFS as part of
00253 // interval building, we have a topological ordering available as a by-product.
00254 // Further, the breadth-first version in GetTopologicalMap is clumsy (in this
00255 // context) since it has to make call-backs to the tarjan code to determine
00256 // if the current edge being examined is a back-edge (to avoid cycling).
00257 //
00258 void 
00259 NestedSCR::Sort()
00260 {
00261   RIFG::NodeId gId;
00262   int parent;           // Tarj parent (loop header)
00263 
00264   // Now disconnect all "next" fields for all tarj nodes
00265 
00266   OA_ptr<RIFG::NodesIterator> ni = rifg->getNodesIterator();
00267   for ( ; (ni->isValid()); ++(*ni)) {
00268     gId = ni->current();
00269     int gdfn = dfnum(gId);
00270     // gdfn will be invalid if the node gId was unreachable.
00271     if (gdfn != DFNUM_NIL) {
00272       TARJ_inners(gdfn) = DFNUM_NIL;
00273       TARJ_next(gdfn) = DFNUM_NIL;
00274     }
00275   }
00276 
00277   // The list is sorted in reverse topological order since each child
00278   // in the loop below is prepended to the list of children.
00279   std::list<RIFG::NodeId>::iterator i;
00280   for (i = rev_top_list.begin(); i != rev_top_list.end(); i++) {
00281     gId = *i;
00282     if (gId != RIFG::NIL) {
00283       // Add new kid
00284       int gdfn = dfnum(gId);
00285       parent = TARJ_outer(gdfn);
00286       if (parent != DFNUM_NIL) {
00287         TARJ_next(gdfn) = TARJ_inners(parent);
00288         TARJ_inners(parent) = gdfn;
00289       }
00290     }
00291   }
00292 
00293   Renumber();
00294 } // end of tarj_sort()
00295 
00296 
00297 TarjTreeNode* 
00298 NestedSCR::getTree()
00299 {
00300   return tarj;
00301 }
00302 
00303 
00304 
00305 //
00306 // Allocate and initialize structures for algorithm, and UNION-FIND
00307 //
00308 void 
00309 NestedSCR::Init()
00310 {
00311   unsigned int g_size = rifg->getHighWaterMarkNodeId() + 1;
00312 
00313   n = DFNUM_ROOT;
00314 
00315   //
00316   // Local work space
00317   //
00318   wk = new TarjWork[g_size];
00319   uf = new UnionFindUniverse(g_size);
00320   tarj = new TarjTreeNode[g_size];
00321   InitArrays();
00322 }
00323 
00324 
00325 //
00326 // Initialize only nodes in current instance g
00327 //
00328 void 
00329 NestedSCR::InitArrays()
00330 {
00331   OA_ptr<RIFG::NodesIterator> ni = rifg->getNodesIterator();
00332   for ( ; ni->isValid(); ++(*ni)) {
00333     int nid = ni->current();
00334     dfnum(nid) = DFNUM_NIL;
00335   }
00336 }
00337 
00338 
00339 //
00340 // Do depth first search on control flow graph to 
00341 // initialize vertex[], dfnum[], last[]
00342 //
00343 void 
00344 NestedSCR::DFS(RIFG::NodeId v)
00345 {
00346   vertex(n) = v;
00347   dfnum(v)  = n++;
00348  
00349   RIFG::EdgeId succ;
00350   OA_ptr<RIFG::OutgoingEdgesIterator> ei = rifg->getOutgoingEdgesIterator(v);
00351   for (; (ei->isValid()); ++(*ei)) {
00352     succ = ei->current();
00353     int son = rifg->getEdgeSink(succ);
00354     if (dfnum(son) == DFNUM_NIL)
00355       DFS(son);
00356   }
00357 
00358   //
00359   // Equivalent to # of descendants -- number of last descendant
00360   //
00361   TLast(dfnum(v)) = n-1;
00362   rev_top_list.push_back(v);
00363 }
00364 
00365 
00366 // Fill in the backPreds and nonBackPreds lists for each node.
00367 void 
00368 NestedSCR::FillPredLists()
00369 {
00370   for (int i = DFNUM_ROOT; i < n; i++) {
00371     OA_ptr<RIFG::IncomingEdgesIterator> ei = 
00372       rifg->getIncomingEdgesIterator(vertex(i)  );
00373     for ( ; (ei->isValid()); ++(*ei)) {
00374       int prednum = dfnum(rifg->getEdgeSrc(ei->current()));
00375       if (is_backedge(prednum, i)) {
00376         backPreds(i).push_back(prednum); 
00377       } else {
00378         nonBackPreds(i).push_back(prednum); 
00379       }
00380     } // for preds
00381   } // for nodes
00382 }
00383 
00384 
00385 //
00386 // In bottom-up traversal of depth-first spanning tree, 
00387 // determine nested strongly connected regions and flag irreducible regions.
00388 //                                                    phh, 4 Mar 91
00389 //
00390 void 
00391 NestedSCR::GetTarjans()
00392 {
00393   int w;                        // DFS number of current vertex
00394   DFNUM_t firstP, firstQ;       // set and worklist
00395 
00396   //
00397   // Following loop should skip root (prenumbered as 0)
00398   //
00399   for (w = n - 1; w != DFNUM_ROOT; w--) // loop c
00400     //
00401     // skip any nodes freed or not reachable
00402     //
00403     if (w != DFNUM_NIL && rifg->isValid(vertex(w))) {
00404       firstP = firstQ = DFNUM_NIL;
00405       //
00406       // Add sources of cycle arcs to P -- and to worklist Q
00407       //
00408       std::list<int>::iterator prednum; 
00409       for (prednum = backPreds(w).begin(); prednum != backPreds(w).end();
00410            prednum++) { // loop d
00411         int u,v;                        // vertex names
00412         v = *prednum;
00413         // ignore predecessors not reachable
00414         if (v != DFNUM_NIL)
00415         {
00416           if (v == w) {
00417             //
00418             // Don't add w to its own P and Q sets
00419             //
00420             isCyclic(w) = true;
00421           } else {
00422             //
00423             // Add FIND(v) to P and Q
00424             //
00425             u = FIND(v);
00426             if (!inP(u)) {
00427               nextP(u) = nextQ(u) = firstP;
00428               firstP   = firstQ   = u;
00429               inP(u)   = true;
00430             } // if (!inP(u))
00431           } // if (v == w)
00432         } // if 
00433       } // for preds
00434 
00435       //
00436       // P nonempty -> w is header of a loop
00437       //
00438       if (firstP != DFNUM_NIL)
00439         isCyclic(w) = true;
00440 
00441       while (firstQ != DFNUM_NIL) {
00442         int x, y, yy;           // DFS nums of vertices
00443 
00444         x = firstQ;
00445         firstQ = nextQ(x);      // remove x from worklist
00446 
00447         //
00448         // Now look at non-cycle arcs
00449         //
00450         std::list<int>::iterator prednum;
00451         for (prednum = nonBackPreds(x).begin();
00452              prednum != nonBackPreds(x).end();
00453              prednum++) { // loop d
00454           y = *prednum;
00455 
00456           //
00457           // ignore predecessors not reachable
00458           //
00459           if (y != DFNUM_NIL)
00460           {
00461             //
00462             // Add FIND(y) to P and Q
00463             //
00464             yy = FIND(y);
00465 
00466             if (is_backedge(yy, w)) {
00467               if ((!inP(yy)) & (yy != w)) {
00468                 nextP(yy) = firstP;
00469                 nextQ(yy) = firstQ;
00470                 firstP = firstQ = yy;
00471                 inP(yy) = true;
00472               }
00473               //
00474               // Slight change to published alg'm...
00475               // moved setting of header (HIGHPT)
00476               // from here to after the union.
00477               //
00478             } else {
00479               //
00480               // Irreducible region!
00481               //
00482               reducible(w) = false;
00483 #if 1
00484               // FIXME: The DSystem version of the code did not have the
00485               // following line.  However, this line IS in the 1997 article,
00486               // and I believe it is necessary (jle, 03-02-2002).
00487               nonBackPreds(w).push_back(yy);
00488 #endif
00489             }
00490           }
00491         }
00492       }
00493       //
00494       // now P = P(w) as in Tarjan's paper
00495       //
00496       while (firstP != DFNUM_NIL) {
00497         //
00498         // First line is a change to published algorithm;
00499         // Want sources of cycle edges to have header w
00500         // and w itself not to have header w.
00501         //
00502         if ((header(firstP) == DFNUM_ROOT) & (firstP != w))
00503           header(firstP) = w;
00504         UNION(firstP, w, w);
00505         inP(firstP) = false;
00506         firstP = nextP(firstP);
00507       } // while
00508     } // if
00509 }
00510 
00511 
00512 //
00513 // Traverse df spanning tree, building tree of Tarjan intervals
00514 //
00515 void 
00516 NestedSCR::Build()
00517 {
00518   int w;                // DFS number of current vertex
00519   int outer;            // DFS number header of surrounding loop
00520 
00521   TARJ_nodeid(DFNUM_ROOT) = rifg->getSource();
00522   //
00523   // Let the root of the tree be the root of the instance...
00524   // Following loop can skip the root (prenumbered 0)
00525   //
00526   for (w = DFNUM_ROOT + 1; w < n; w++) {
00527     RIFG::NodeId wnode = vertex(w);
00528     //
00529     // skip any nodes not in current instance g
00530     //
00531     if (wnode != RIFG::NIL) {
00532       outer = header(w);
00533       TARJ_outer(w) = outer;
00534       TARJ_nodeid(w) = wnode;
00535       //
00536       // tarj[w].inners = DFNUM_NIL;  % done in InitArrays
00537       //
00538       if (isCyclic(w)) {
00539         //
00540         // Level is deeper than outer if this is a loop
00541         //
00542         if (reducible(w)) {
00543           TARJ_type(w) = NODE_INTERVAL;
00544           TARJ_level(w) = TARJ_level(outer) + 1;
00545         } else {
00546           TARJ_type(w) = NODE_IRREDUCIBLE;
00547           TARJ_level(w) = TARJ_level(outer);
00548         }
00549       } else {
00550         //
00551         // tarj[w].type  = RI_TARJ_ACYCLIC;     % done in InitArrays
00552         //
00553         TARJ_level(w) = TARJ_level(outer);
00554       }
00555       TARJ_next(w) = TARJ_inners(outer);
00556       TARJ_inners(outer) = w;
00557     }
00558   }
00559   n = 0;
00560   Prenumber(DFNUM_ROOT);
00561 }
00562 
00563 
00564 void 
00565 NestedSCR::Prenumber(int v)
00566 {
00567   int inner;
00568 
00569   tarj[v].prenum = ++n;
00570   last_id = TARJ_nodeid(v);
00571     
00572   for (inner = TARJ_inners(v); inner != DFNUM_NIL; 
00573        inner = TARJ_next(inner)) {
00574     Prenumber(inner);
00575   }
00576 
00577   /* tarj[v].last = n;  // 3/18/93 RvH: switch to RIFG::NodeId last_id */
00578   tarj[v].last_id = last_id;
00579   tarj[v].last = dfnum(last_id);
00580 }
00581 
00582 
00583 void 
00584 NestedSCR::Renumber()
00585 {
00586   tarj = tarj;
00587   n = 0;
00588   Prenumber(DFNUM_ROOT);
00589 }
00590 
00591 
00592 //  Free all space used in computation of 
00593 //  Tarjan interval tree (but not tree itself)
00594 void 
00595 NestedSCR::FreeWork()
00596 {
00597   delete[] wk;
00598   wk = 0;
00599 
00600   delete uf;
00601   uf = 0;
00602 }
00603 
00604 
00605 static int loopIndex;
00606 void 
00607 NestedSCR::ComputeIntervalIndexSubTree(int node, int value)
00608 {
00609   int kid, valKid;
00610     
00611   TARJ_loopIndex(node) = value;
00612   if (TARJ_inners(node) != DFNUM_NIL)
00613     valKid = ++loopIndex;
00614 
00615   for (kid = TARJ_inners(node); kid != DFNUM_NIL; kid = TARJ_next(kid))
00616     ComputeIntervalIndexSubTree(kid, valKid);
00617 }
00618 
00619 
00620 void 
00621 NestedSCR::ComputeIntervalIndex()
00622 {
00623   loopIndex = 0;
00624   ComputeIntervalIndexSubTree(DFNUM_ROOT, loopIndex);
00625 }
00626 
00627 
00628 void 
00629 NestedSCR::dump(std::ostream& os)
00630 {
00631   printf("Tarjan interval tree: <node id>(level,type)::IntervalIndex\n");
00632   DumpSubTree(os, DFNUM_ROOT, 0 /* Indent */);
00633 }
00634 
00635 
00636 //
00637 // Feb. 2002 (jle): Got rid of all the silly concatenating of blank
00638 // strings. The %*s format specifier is far simpler for creating indentations.
00639 //
00640 void 
00641 NestedSCR::DumpSubTree(std::ostream& os, int node, int indent)
00642 {
00643   static const char *NodeType[] = {"NOTHING", "Acyclic",
00644                                    "Interval", "Irreducible"};
00645   //
00646   // Indent by three
00647   //
00648   if (indent < 72)
00649     indent += 3;
00650   
00651   printf("%*s%d(%d,%s)::%d\n", indent, " ",
00652          TARJ_nodeid(node), TARJ_level(node),
00653          NodeType[(int) (TARJ_type(node))], TARJ_loopIndex(node));
00654   
00655   for (int kid = TARJ_inners(node); kid != DFNUM_NIL; 
00656        kid = TARJ_next(kid)) {
00657     DumpSubTree(os, kid, indent);
00658   }
00659   
00660   //
00661   // Unindent
00662   //
00663   if (indent >= 3)
00664     indent -= 3;
00665 }
00666 
00667 
00668 int 
00669 NestedSCR::FIND(int v)
00670 {
00671   return uf->Find(v);
00672 }
00673 
00674 
00675 void 
00676 NestedSCR::UNION(int i, int j, int k)
00677 {
00678   uf->Union(i,j,k);
00679 }
00680 
00681 
00682 //
00683 // Return number of loops exited in traversing g edge from src to sink
00684 // (0 is normal).
00685 //
00686 int 
00687 NestedSCR::getExits(RIFG::NodeId src, RIFG::NodeId sink)
00688 {
00689   RIFG::NodeId lca = LCA(src, sink);
00690   if (lca == RIFG::NIL)
00691     return 0;
00692 
00693   int dfn_src = dfnum(src);
00694   int dfn_lca = dfnum(lca);
00695   return std::max(0, TARJ_level(dfn_src) - TARJ_level(dfn_lca));
00696 }
00697 
00698 
00699 //
00700 // Return outermost loop exited in traversing g edge from src to sink
00701 // (RIFG::NIL if no loops exited).
00702 //
00703 RIFG::NodeId 
00704 NestedSCR::getLoopExited(RIFG::NodeId src, RIFG::NodeId sink)
00705 {
00706   RIFG::NodeId lca = LCA(src, sink);
00707   if (lca == RIFG::NIL)
00708     return RIFG::NIL;
00709 
00710   if (lca == src)
00711     return RIFG::NIL;
00712 
00713   int dfn_src = dfnum(src);
00714   while (!Contains(TARJ_nodeid(TARJ_outer(dfn_src)), sink))
00715     dfn_src = TARJ_outer(dfn_src);
00716     
00717   if (TARJ_type(dfn_src) == NODE_INTERVAL
00718       || TARJ_type(dfn_src) == NODE_IRREDUCIBLE)
00719     return TARJ_nodeid(dfn_src);
00720 
00721   return RIFG::NIL;
00722 }
00723 
00724 
00725 //
00726 // Return type of g edge from src to sink, one of
00727 //   RI_TARJ_NORMAL
00728 //   RI_TARJ_LOOP_ENTRY
00729 //   RI_TARJ_IRRED_ENTRY
00730 //   RI_TARJ_ITERATE (back edge)
00731 //
00732 NestedSCR::Edge_t 
00733 NestedSCR::getEdgeType(RIFG::NodeId src, RIFG::NodeId sink)
00734 {
00735   RIFG::NodeId anc = LCA(src, sink);
00736   int dfn_sink = dfnum(sink);
00737   int dfn_anc = dfnum(anc);
00738 
00739   if (dfn_anc == dfn_sink) {
00740     return EDGE_ITERATE;
00741   } 
00742   else if (TARJ_outer(dfn_sink) != DFNUM_NIL
00743            && (TARJ_type(TARJ_outer(dfn_sink)) == NODE_IRREDUCIBLE)
00744            && (dfn_anc != TARJ_outer(dfn_sink))) {
00745     //
00746     // Entering irreducible region not through the "header"
00747     //
00748     return EDGE_IRRED_ENTRY;
00749   } 
00750   else {
00751     switch (TARJ_type(dfn_sink)) {
00752     case NODE_INTERVAL:
00753       return EDGE_LOOP_ENTRY;
00754     case NODE_IRREDUCIBLE:
00755       //
00756       // Entering irreducible region through the "header"
00757       //
00758       return EDGE_IRRED_ENTRY;
00759     case NODE_ACYCLIC:
00760     case NODE_NOTHING:
00761     default:
00762       return EDGE_NORMAL;
00763     }
00764   }
00765 }
00766 
00767 
00768 //
00769 // LCA = least common ancestor
00770 //
00771 RIFG::NodeId 
00772 NestedSCR::LCA(RIFG::NodeId a, RIFG::NodeId b)
00773 {
00774   if ((a == RIFG::NIL) || (b == RIFG::NIL))
00775     return RIFG::NIL;
00776 
00777   if (Contains(a,b))
00778     return a;
00779 
00780   int dfn_b = dfnum(b);
00781   while ((dfn_b != DFNUM_NIL) && !Contains(b,a)) {
00782     dfn_b = TARJ_outer(dfn_b);
00783     b = TARJ_nodeid(dfn_b);
00784   }
00785 
00786   return b;
00787 }
00788 
00789 
00790 //
00791 // Return true if the CFG edge passed in is an backedge.
00792 //
00793 //   Precondition: Tarjan tree must be built already.
00794 //
00795 bool 
00796 NestedSCR::isBackEdge(RIFG::EdgeId edgeId)
00797 {
00798   RIFG::NodeId src, dest;
00799   src = rifg->getEdgeSrc(edgeId);
00800   dest = rifg->getEdgeSink(edgeId);
00801   return is_backedge(dfnum(src), dfnum(dest));
00802 } 
00803 
00804 
00805 RIFG::NodeId 
00806 NestedSCR::getInners(RIFG::NodeId id)
00807 {
00808   int dfn_inners = TARJ_inners(dfnum(id));
00809   return dfn_inners == DFNUM_NIL ? RIFG::NIL : TARJ_nodeid(dfn_inners);
00810 }
00811 
00812 
00813 RIFG::NodeId 
00814 NestedSCR::getInnersLast(RIFG::NodeId id)
00815 {
00816   int dfn_last_id = TARJ_last_id(dfnum(id));
00817   return TARJ_nodeid(dfn_last_id);
00818 }
00819 
00820 
00821 RIFG::NodeId
00822 NestedSCR::getOuter(RIFG::NodeId id)
00823 {
00824   int dfn_outer = TARJ_outer(dfnum(id));
00825   return dfn_outer == DFNUM_NIL ? RIFG::NIL : TARJ_nodeid(dfn_outer);
00826 }
00827 
00828 
00829 RIFG::NodeId 
00830 NestedSCR::getNext(RIFG::NodeId id)
00831 {
00832   int dfn_next = TARJ_next(dfnum(id));
00833   return dfn_next == DFNUM_NIL ? RIFG::NIL : TARJ_nodeid(dfn_next);
00834 }
00835 
00836 
00837 
00838 bool 
00839 NestedSCR::isHeader(RIFG::NodeId id)
00840 {
00841   return (getInners(dfnum(id)) != DFNUM_NIL);
00842 }
00843 
00844 
00845 bool 
00846 NestedSCR::isFirst(RIFG::NodeId id)
00847 {
00848   int dfn_id = dfnum(id);
00849 
00850   if (getOuter(dfn_id) == DFNUM_NIL)
00851     return true;
00852 
00853   return (getInners(getOuter(dfn_id)) == dfn_id);
00854 }
00855 
00856 
00857 bool 
00858 NestedSCR::isLast(RIFG::NodeId id)
00859 {
00860   return (getNext(dfnum(id)) == DFNUM_NIL);
00861 }
00862 
00863 
00864 int 
00865 NestedSCR::getLevel(RIFG::NodeId id)
00866 {
00867   return TARJ_level(dfnum(id));
00868 }
00869 
00870 
00871 NestedSCR::Node_t 
00872 NestedSCR::getNodeType(RIFG::NodeId id)
00873 {
00874   return TARJ_type(dfnum(id));
00875 }
00876 
00877 
00878 bool 
00879 NestedSCR::Contains(RIFG::NodeId a, RIFG::NodeId b)
00880 {
00881   return (TARJ_contains(dfnum(a), dfnum(b)));
00882 }
00883 
00884 
00885 int 
00886 NestedSCR::getLoopIndex(RIFG::NodeId id)
00887 {
00888   return TARJ_loopIndex(dfnum(id));
00889 }
00890 
00891 
00892 } // end of namespace OA
00893