ManagerICFG.cpp

Go to the documentation of this file.
00001 
00015 #include <OpenAnalysis/ICFG/ManagerICFG.hpp>
00016 #include <OpenAnalysis/Utils/Util.hpp>
00017 #include <OpenAnalysis/Utils/OutputBuilderDOT.hpp>
00018 
00019 static bool debug = false;
00020 
00021 namespace OA {
00022   namespace ICFG {
00023 
00024 
00027 ManagerICFGStandard::ManagerICFGStandard(OA_ptr<ICFGIRInterface> _ir) 
00028     : mIR(_ir)
00031 { 
00032     OA_DEBUG_CTRL_MACRO("DEBUG_ManagerICFGStandard:ALL", debug);
00033 }
00034 
00035 bool ManagerICFGStandard::stmt_has_call(StmtHandle stmt)
00036 {
00037     bool callflag = false;
00038     OA_ptr<IRCallsiteIterator> callsiteItPtr = mIR->getCallsites(stmt);
00039     for ( ; callsiteItPtr->isValid(); ++(*callsiteItPtr)) {
00040         CallHandle call = callsiteItPtr->current();
00041         OA_ptr<ProcHandleIterator> procIter;
00042         procIter = mCallGraph->getCalleeProcIter(call);
00043         for ( ; procIter->isValid(); ++(*procIter)) {
00044           ProcHandle proc = procIter->current();
00045           if (debug) {
00046             std::cout << "called proc = " 
00047                       << mIR->toString(proc) << std::endl;
00048           }
00049           if (proc != ProcHandle(0)) {
00050             callflag = true;
00051           }
00052         }
00053     }
00054     return callflag;
00055 }
00056 
00057 StmtHandle 
00058 ManagerICFGStandard::get_call_stmt(OA_ptr<CFG::Node> cfgNode)
00059 {
00060   // assumes that there is at most one call stmt within a cfgNode
00061     OA_ptr<StmtHandleIterator> stmtIter;
00062     stmtIter = cfgNode->getNodeStatementsIterator();
00063     for ( ; stmtIter->isValid(); (*stmtIter)++ ) {
00064         StmtHandle stmt = stmtIter->current();
00065         if ( stmt_has_call(stmt) ) {
00066             return stmt; 
00067         }
00068     }
00069     return StmtHandle(0);
00070 }
00071 
00072 OA_ptr<Node> ManagerICFGStandard::create_icfg_node(
00073         OA_ptr<ICFG> icfg, ProcHandle proc, NodeType pType, 
00074         OA_ptr<CFG::Node> cfgNode)
00075 {
00076   OA_ptr<Node> icfgNode; 
00077   icfgNode = new Node(icfg, proc, pType, cfgNode);
00078   icfg->addNode(icfgNode);
00079   mCFGNodeToICFGNode[cfgNode] = icfgNode;
00080   return icfgNode;
00081 }
00082 
00086 OA_ptr<Node>
00087 ManagerICFGStandard::handle_call_node(OA_ptr<ICFG> icfg, 
00088         ProcHandle proc, OA_ptr<CFG::Node> cfgNodeNew,
00089         OA_ptr<Node> prevICFGNode, 
00090         OA_ptr<Node>& firstICFGNode,
00091         std::list<ProcHandle>& worklist)
00092 {
00093     OA_ptr<Node> callICFGNode;
00094     OA_ptr<Edge> icfgEdge;
00095     StmtHandle stmt = get_call_stmt(cfgNodeNew);
00096 
00097     // Call node and matched return node
00098     firstICFGNode = callICFGNode 
00099         = create_icfg_node(icfg,proc,CALL_NODE,cfgNodeNew);
00100 
00101     // edge between prevICFGNode and callICFGNode 
00102     if (!prevICFGNode.ptrEqual(0)) {
00103         icfgEdge = new Edge(icfg, 
00104                 prevICFGNode, callICFGNode, CFLOW_EDGE, CallHandle(0));
00105         icfg->addEdge(icfgEdge);
00106     }
00107 
00108     // return node
00109     OA_ptr<CFG::Node> emptyNode;
00110     emptyNode = new CFG::Node;
00111     prevICFGNode = create_icfg_node(icfg,proc,RETURN_NODE,emptyNode);
00112 
00113     // edge between callnode and return node
00114     //icfgEdge = new Edge(icfg, 
00115     //           callICFGNode, prevICFGNode, CALL_RETURN_EDGE, CallHandle(0));
00116     //icfg->addEdge(icfgEdge);
00117 
00118     // CALL_RETURN_EDGE should have valid CallHandle.
00119     // Passing CallHandle(0) in order to create Calll_RETURN_EDGE is Invalid.
00120     OA_ptr<IRCallsiteIterator>
00121         callsiteIt = mIR->getCallsites(stmt);
00122     CallHandle call;
00123     for ( ; callsiteIt->isValid(); ++(*callsiteIt)) {
00124        call = callsiteIt->current();
00125     }
00126     icfgEdge = new Edge(icfg,
00127                         callICFGNode, prevICFGNode, CALL_RETURN_EDGE, call);
00128     icfg->addEdge(icfgEdge);
00129 
00130     // for each call, add a call Edge and return edge to each
00131     // may-called defined-procedure
00132     OA_ptr<IRCallsiteIterator> 
00133         callsiteItPtr = mIR->getCallsites(stmt);
00134     for ( ; callsiteItPtr->isValid(); ++(*callsiteItPtr)) {
00135         CallHandle call = callsiteItPtr->current();
00136         OA_ptr<ProcHandleIterator> procIter;
00137         procIter = mCallGraph->getCalleeProcIter(call);
00138         for ( ; procIter->isValid(); ++(*procIter)) {
00139           ProcHandle callee = procIter->current();
00140           if (callee==ProcHandle(0)) { continue; }
00141           worklist.push_back(callee);
00142           // get CFG
00143           OA_ptr<CFG::CFGInterface> calleeCFGInterface 
00144             = mEachCFG->getCFGResults(callee);
00145           OA_ptr<CFG::CFG> calleeCFG 
00146             = calleeCFGInterface.convert<CFG::CFG>();
00147           // get entry and exit node
00148           OA_ptr<CFG::NodeInterface> temp
00149             = calleeCFG->getEntry();
00150           OA_ptr<CFG::Node> entryNode 
00151             = temp.convert<CFG::Node>();
00152           temp = calleeCFG->getExit();
00153           OA_ptr<CFG::Node> exitNode 
00154             = temp.convert<CFG::Node>();
00155           // make an ICFG node for these if necessary
00156           if (mCFGNodeToICFGNode[entryNode].ptrEqual(0)) {
00157             mCFGNodeToICFGNode[entryNode] 
00158               = new Node(icfg, callee, ENTRY_NODE, entryNode);
00159             icfg->addNode(mCFGNodeToICFGNode[entryNode]);
00160           }
00161           if (mCFGNodeToICFGNode[exitNode].ptrEqual(0)) {
00162             mCFGNodeToICFGNode[exitNode] 
00163               = new Node(icfg, callee, EXIT_NODE, exitNode);
00164             icfg->addNode(mCFGNodeToICFGNode[exitNode]);
00165           }
00166           
00167           // edge to link callICFGNode to entryNode
00168           icfgEdge = new Edge(icfg, callICFGNode, 
00169                                             mCFGNodeToICFGNode[entryNode], 
00170                                             CALL_EDGE, call);
00171           icfg->addEdge(icfgEdge);
00172           
00173           // edge to link exitNode to prevICFGNode
00174           icfgEdge = new Edge(icfg, 
00175                                             mCFGNodeToICFGNode[exitNode], 
00176                                             prevICFGNode, RETURN_EDGE, call);
00177           icfg->addEdge(icfgEdge);
00178 
00179         } // end of loop for each may-called ProcHandle for this CallHandle
00180 
00181     } // end of loop for each CallHandle within this call StmtHandle
00182         
00183     return prevICFGNode;
00184 }
00185 
00186 OA_ptr<std::list<OA_ptr<CFG::Node> > > 
00187 ManagerICFGStandard::break_out_calls(OA_ptr<CFG::Node> cfgNode)
00188 {
00189     OA_ptr<std::list<OA_ptr<CFG::Node> > > retval;
00190     retval = new std::list<OA_ptr<CFG::Node> >;
00191 
00192     OA_ptr<CFG::Node> prevNode;
00193     prevNode = new CFG::Node;
00194 
00195     // loop through statements in original cfgNode
00196     // inserting them into prevNode until hit a call stmt
00197     // when hit a call statement make a new node for the call stmt
00198     // and then a new prevNode and loop
00199     OA_ptr<StmtHandleIterator> stmtIter;
00200     stmtIter = cfgNode->getNodeStatementsIterator();
00201     for ( ; stmtIter->isValid(); (*stmtIter)++ ) {
00202         StmtHandle stmt = stmtIter->current();
00203         if ( stmt_has_call(stmt) ) {
00204             if (prevNode->size() > 0) {
00205                 retval->push_back(prevNode);
00206                 prevNode = new CFG::Node;
00207             }
00208             prevNode->add(stmt);
00209             retval->push_back(prevNode);
00210             prevNode = new CFG::Node;
00211         } else {
00212             prevNode->add(stmt);
00213         }
00214     }
00215     retval->push_back(prevNode);
00216 
00217     return retval;
00218 }
00219 
00223 OA_ptr<ICFG> ManagerICFGStandard::performAnalysis( 
00224     OA_ptr<IRProcIterator> procIter,
00225     OA_ptr<CFG::EachCFGInterface> eachCFG,
00226     OA_ptr<CallGraph::CallGraphInterface> cGraph)
00227 {
00228   OA_ptr<Edge> icfgEdge;
00229   OA_ptr<ICFG> icfg; icfg = new ICFG();
00230 
00231   // for use within helper functions
00232   mEachCFG = eachCFG;
00233   mCallGraph = cGraph;
00234 
00235   // list of edges that are needed, the ICFGStandard::Node is the
00236   // sink of the edge and the CFGNodes are predecessors
00237   // have to keep these until the end and all CFG nodes are mapped
00238   // to ICFG nodes
00239   std::map<OA_ptr<Node>,
00240            std::set<OA_ptr<CFG::Node> > > edgeMap;
00241 
00242 
00243   /*
00244   // get the CFG for the root procedure
00245   OA_ptr<CFG::Interface> rootCFGInterface = eachCFG->getCFGResults(rootProc);
00246   OA_ptr<CFG::CFGStandard> rootCFG 
00247       = rootCFGInterface.convert<CFG::CFGStandard>();
00248   if (debug) {
00249       std::cout << "--- rootCFG" << std::endl;
00250       rootCFG->dumpdot(std::cout, mIR);
00251   }
00252 
00253   // get entry and exit node for cfg
00254   OA_ptr<CFG::Interface::Node> temp = rootCFG->getEntry();
00255   OA_ptr<CFG::CFGStandard::Node> cfgNode 
00256       = temp.convert<CFG::CFGStandard::Node>();
00257   OA_ptr<ICFGStandard::Node> icfgNode 
00258       = create_icfg_node(icfg, rootProc, ENTRY_NODE, cfgNode);
00259 
00260   temp = rootCFG->getExit();
00261   cfgNode = temp.convert<CFG::CFGStandard::Node>();
00262   icfgNode = create_icfg_node(icfg, rootProc, EXIT_NODE, cfgNode);
00263   */
00264 
00265   // worklist and set of procs that have already been visited
00266   std::list<ProcHandle> worklist;
00267   std::set<ProcHandle> alreadyVisited;
00268   for ( procIter->reset(); procIter->isValid(); (*procIter)++ ) {
00269     worklist.push_back(procIter->current());
00270   }
00271 
00272   // while there is a proc in the worklist
00273   while ( ! worklist.empty() ) {
00274     
00275     // get next proc and make sure it hasn't already been visited
00276     ProcHandle proc = worklist.front();
00277     worklist.pop_front();
00278     if (alreadyVisited.find(proc)!=alreadyVisited.end()) {
00279         continue;
00280     } else {
00281         alreadyVisited.insert(proc);
00282     }
00283 
00284     // get cfg 
00285     OA_ptr<CFG::CFGInterface> cfgInterface = eachCFG->getCFGResults(proc);
00286     //cfgInterface->output(*mIR);
00287  
00288     OA_ptr<CFG::CFG> cfg = cfgInterface.convert<CFG::CFG>();
00289     if (debug) {
00290       std::cout << "\n\n\n--- cfg" << std::endl;
00291       cfg->output(*mIR);
00292       // dot output
00293       OA::OA_ptr<OA::OutputBuilder> outBuild;
00294       outBuild = new OA::OutputBuilderDOT;
00295       cfg->configOutput(outBuild);
00296       cfg->output(*mIR);
00297       std::cout << "\n\n\n";
00298       
00299       //cfg->dumpdot(std::cout, mIR);
00300       //cfg->dumpdot(std::cout, mIR);
00301     }
00302 
00303     // for each node in cfg create an icfg node
00304     OA_ptr<DGraph::NodesIteratorInterface> cfgNodeIter
00305         = cfg->getNodesIterator();
00306     for ( ; cfgNodeIter->isValid(); (*cfgNodeIter)++ ) {
00307         OA_ptr<DGraph::NodeInterface> dNode = cfgNodeIter->current();
00308         OA_ptr<CFG::Node> cfgNode = dNode.convert<CFG::Node>();
00309 
00310         if (debug) {
00311             std::cout << "cfgNode = ";
00312             //cfgNode->dumpdot(*cfg,std::cout,mIR);
00313         }
00314 
00315         // determine if any of the statements contain a call
00316         OA_ptr<StmtHandleIterator> stmtIter;
00317         stmtIter = cfgNode->getNodeStatementsIterator();
00318         bool callflag = false;
00319         for ( ; stmtIter->isValid(); (*stmtIter)++ ) {
00320             StmtHandle stmt = stmtIter->current();
00321             if (debug) { std::cout << "stmt = " 
00322                                    << mIR->toString(stmt) << std::endl;}
00323             if ( stmt_has_call(stmt) ) {
00324                 callflag = true;
00325                 if (debug) { std::cout << "\tcallflag = true" << std::endl;}
00326             }
00327         }
00328 
00329         // if there were any calls in any of the statements
00330         if (callflag) {
00331             // get list of new CFG nodes, will NOT have empty ones for
00332             // return nodes
00333             OA_ptr<std::list<OA_ptr<CFG::Node> > > newCFGList
00334                 = break_out_calls(cfgNode);
00335             std::list<OA_ptr<CFG::Node> >::iterator newCFGNodeIter;
00336             newCFGNodeIter = newCFGList->begin();
00337 
00338             // for first one, create associated ICFG node and link that
00339             // associated ICFG with all predecessors for original CFG node
00340             OA_ptr<CFG::Node> firstCFGNode = *newCFGNodeIter;
00341             if (debug) {
00342                 std::cout << "firstCFGNode = ";
00343                 //firstCFGNode->dumpdot(*cfg,std::cout,mIR);
00344             }
00345             OA_ptr<Node> firstICFGNode, prevICFGNode;
00346             // Call node and matched return node
00347             if ( get_call_stmt(firstCFGNode) != StmtHandle(0) ) {
00348                 prevICFGNode = handle_call_node(icfg, proc, firstCFGNode,
00349                                                 prevICFGNode, firstICFGNode,
00350                                                 worklist);
00351             // regular cfg node
00352             } else if (firstCFGNode->size() > 0) {
00353                 firstICFGNode = create_icfg_node(icfg,proc,CFLOW_NODE, 
00354                                                  firstCFGNode);
00355                                                  
00356                 prevICFGNode = firstICFGNode;
00357             }
00358 
00359             if (debug) {
00360                 std::cout << "firstICFGNode = ";
00361                 //firstICFGNode->dumpdot(*icfg,std::cout,mIR);
00362             }
00363 
00364             // get predecessors for original CFG node
00365             OA_ptr<DGraph::NodesIteratorInterface> predIter
00366                 = cfgNode->getSourceNodesIterator();
00367             for ( ; predIter->isValid(); (*predIter)++ ) {
00368                 OA_ptr<DGraph::NodeInterface> dNode = predIter->current();
00369                 OA_ptr<CFG::Node> predNode = dNode.convert<CFG::Node>();
00370                 // temporarily record
00371                 // edge between predecessor ICFG node and firstICFGNode
00372                 edgeMap[firstICFGNode].insert(predNode);
00373             }
00374 
00375             // for middle ones create appropriate ICFG and link to previous
00376             newCFGNodeIter++;
00377             for ( ; newCFGNodeIter!=newCFGList->end(); newCFGNodeIter++ )
00378             {
00379                 OA_ptr<CFG::Node> cfgNodeNew = *newCFGNodeIter;
00380 
00381                 // Call node and matched return node
00382                 if ( get_call_stmt(cfgNodeNew) != StmtHandle(0) ) {
00383                     prevICFGNode = handle_call_node(icfg, proc, cfgNodeNew,
00384                                                   prevICFGNode, firstICFGNode,
00385                                                   worklist);
00386 
00387                 // regular cfg node
00388                 } else if (cfgNodeNew->size() > 0) {
00389 
00390                     OA_ptr<Node> currICFGNode;
00391                     currICFGNode  
00392                         = create_icfg_node(icfg,proc,CFLOW_NODE,cfgNodeNew);
00393 
00394                     // edge between prevICFGNode and this one
00395                     icfgEdge = new Edge(icfg, 
00396                                 prevICFGNode, currICFGNode, CFLOW_EDGE,
00397                                 CallHandle(0));
00398                     icfg->addEdge(icfgEdge);
00399 
00400                     prevICFGNode = currICFGNode;
00401                 }
00402 
00403             } 
00404             
00405             // for last one, associate with original CFG node
00406             // so correct linkages will occur later when successors
00407             // are linking with predecessors
00408             mCFGNodeToICFGNode[cfgNode] = prevICFGNode; 
00409 
00410         // CFG node that doesn't have a call stmt
00411         } else {
00412             OA_ptr<Node> icfgNode; 
00413             if (mCFGNodeToICFGNode[cfgNode].ptrEqual(0)) {
00414                 if (cfg->getEntry() == cfgNode) {
00415                     icfgNode = create_icfg_node(icfg,proc,ENTRY_NODE,cfgNode);
00416                 } else if (cfg->getExit() == cfgNode) {
00417                     icfgNode = create_icfg_node(icfg,proc,EXIT_NODE,cfgNode);
00418                 } else {
00419                     icfgNode = create_icfg_node(icfg,proc,CFLOW_NODE,cfgNode);
00420                 }
00421             } else {
00422                 icfgNode = mCFGNodeToICFGNode[cfgNode];
00423             }
00424 
00425             OA_ptr<DGraph::NodesIteratorInterface> predIter
00426                 = cfgNode->getSourceNodesIterator();
00427             for ( ; predIter->isValid(); (*predIter)++ ) {
00428                 OA_ptr<DGraph::NodeInterface> dNode = predIter->current();
00429                 OA_ptr<CFG::Node> predNode = dNode.convert<CFG::Node>();
00430                 // temporarily record
00431                 // edge between predecessor ICFG node and firstICFGNode
00432                 edgeMap[icfgNode].insert(predNode);
00433             }
00434         }
00435 
00436     } // end of loop over CFG nodes 
00437 
00438 
00439   } // worklist loop for procedures          
00440   
00441   // loop over edges and generate ICFG edges
00442   std::map<OA_ptr<Node>,
00443            std::set<OA_ptr<CFG::Node> > >::iterator mapIter;
00444   for (mapIter=edgeMap.begin(); mapIter!=edgeMap.end(); mapIter++ ) {
00445       OA_ptr<Node> icfgNode = mapIter->first;
00446       std::set<OA_ptr<CFG::Node> >& nodeSet = mapIter->second;
00447       std::set<OA_ptr<CFG::Node> >::iterator nodeIter;
00448       for (nodeIter=nodeSet.begin(); nodeIter!=nodeSet.end(); nodeIter++) {
00449           icfgEdge = new Edge(icfg, 
00450                   mCFGNodeToICFGNode[*nodeIter], 
00451                   icfgNode, CFLOW_EDGE, CallHandle(0));
00452           icfg->addEdge(icfgEdge);
00453       }
00454   }
00455 
00456   return icfg;
00457 }
00458 
00459 
00460   } // end of namespace MPICFG
00461 } // end of namespace OA