00001 /* 00002 * Copyright 2003, 2004, 2005, 2006 PathScale, Inc. All Rights Reserved. 00003 */ 00004 00005 /* 00006 00007 Copyright (C) 2000, 2001 Silicon Graphics, Inc. All Rights Reserved. 00008 00009 This program is free software; you can redistribute it and/or modify it 00010 under the terms of version 2 of the GNU General Public License as 00011 published by the Free Software Foundation. 00012 00013 This program is distributed in the hope that it would be useful, but 00014 WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00016 00017 Further, this software is distributed without any warranty that it is 00018 free of the rightful claim of any third person regarding infringement 00019 or the like. Any license provided herein, whether implied or 00020 otherwise, applies only to this software file. Patent licenses, if 00021 any, provided herein do not apply to combinations of this program with 00022 other software, or any other product whatsoever. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with this program; if not, write the Free Software Foundation, Inc., 59 00026 Temple Place - Suite 330, Boston MA 02111-1307, USA. 00027 00028 Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pky, 00029 Mountain View, CA 94043, or: 00030 00031 http://www.sgi.com 00032 00033 For further information regarding this notice, see: 00034 00035 http://oss.sgi.com/projects/GenInfo/NoticeExplan 00036 00037 */ 00038 00039 00040 // ==================================================================== 00041 // ==================================================================== 00042 // 00043 // Module: ipa_solver.cxx 00044 // $Revision: 1.1.1.1 $ 00045 // $Date: 2005/10/21 19:00:00 $ 00046 // $Author: marcel $ 00047 // $Source: /proj/osprey/CVS/open64/osprey1.0/ipa/main/analyze/ipa_solver.cxx,v $ 00048 // 00049 // Revision history: 00050 // 19-Sep-95 - Original Version 00051 // 00052 // Description: 00053 // 00054 // This module contains functions required for implementation of the 00055 // template dataflow solver based on class DFBASE in ipa_solver.h. 00056 // 00057 // It also contains an instance of the solver which prints the 00058 // callgraph for tracing purposes. See the definition of the DF_PRINT 00059 // class below for an example of how to instantiate DFBASE. 00060 // 00061 // TODO: Connect_graph, Restore_graph, and Reverse_graph, with their 00062 // underlying utility functions, should be moved to the ip_graph.[ch] 00063 // module. 00064 // 00065 // ==================================================================== 00066 // ==================================================================== 00067 00068 #ifdef _KEEP_RCS_ID 00069 static char *rcs_id = "$Source: /proj/osprey/CVS/open64/osprey1.0/ipa/main/analyze/ipa_solver.cxx,v $ $Revision: 1.1.1.1 $"; 00070 #endif /* _KEEP_RCS_ID */ 00071 00072 #define __STDC_LIMIT_MACROS 00073 #include <stdint.h> 00074 #if defined(BUILD_OS_DARWIN) 00075 #include <darwin_elf.h> 00076 #else /* defined(BUILD_OS_DARWIN) */ 00077 #include <elf.h> 00078 #endif /* defined(BUILD_OS_DARWIN) */ 00079 00080 #include "assert.h" 00081 #include "defs.h" 00082 #include "dwarf_DST_mem.h" /* Needed by ipc_file.h for DST_TYPE */ 00083 #include "erglob.h" 00084 #include "mempool.h" 00085 #include "tracing.h" 00086 00087 #include "mtypes.h" /* Needed by const.h for TYPE_ID */ 00088 #include "symtab.h" 00089 #include "const.h" /* Needed by ipc_file.h for Const_Tab_Type */ 00090 #include "strtab.h" 00091 00092 #include "ip_graph.h" 00093 #include "ipc_file.h" 00094 #include "ipa_cg.h" 00095 #include "ipa_solver.h" 00096 #include "ipa_summary.h" 00097 #include "ipa_option.h" 00098 00099 static BOOL Trace_CG = FALSE; 00100 00101 // ==================================================================== 00102 // 00103 // DFBASE::DFBASE 00104 // 00105 // Constructor for the dataflow base class. The graph iterator may be 00106 // NULL, in which case the solver must provide it later. 00107 // 00108 // ==================================================================== 00109 00110 DFBASE::DFBASE ( 00111 IPA_CALL_GRAPH &cg, // The underlying call graph to use 00112 DF_DIRECTION direction, // The dataflow problem direction 00113 MEM_POOL *mpool, // Where to put new junk 00114 DFN *iter ) // An iterator over the graph 00115 { 00116 // Record the information provided: 00117 _m = mpool; 00118 _cg = &cg; 00119 _iter = iter; 00120 _entry = INVALID_NODE_INDEX; 00121 _exit = INVALID_NODE_INDEX; 00122 _dir = direction; 00123 _saved_root = INVALID_NODE_INDEX; 00124 _reversed = FALSE; 00125 _changed = FALSE; 00126 00127 // Make sure it's valid: 00128 assert ( _cg->Graph() != NULL ); 00129 assert ( (_dir == BACKWARD) || (_dir == FORWARD) ); 00130 00131 // Connect the graph to unique entry and exit nodes: 00132 Connect_graph ( mpool ); 00133 } 00134 00135 00136 // ==================================================================== 00137 // 00138 // DFBASE::~DFBASE 00139 // 00140 // Destructor for the dataflow base class. We must restore the 00141 // underlying graph and free the iterator memory. 00142 // 00143 // ==================================================================== 00144 00145 DFBASE::~DFBASE () 00146 { 00147 if ( Get_saved_root() != INVALID_NODE_INDEX ) { 00148 Restore_graph(); 00149 } 00150 if ( Get_iter() != NULL ) { 00151 Free_DFN ( Get_iter(), Get_mempool() ); 00152 } 00153 } 00154 00155 // ==================================================================== 00156 // 00157 // Forward_Visit / Backward_Visit 00158 // 00159 // Do a forward (backward) depth-first visit of the given graph from 00160 // the given vertex, marking visited nodes in the given vector. These 00161 // routines should not be called from an already-visited node. 00162 // 00163 // See the Dragon book, page 662. 00164 // 00165 // ==================================================================== 00166 00167 static void 00168 Forward_Visit ( GRAPH *g, NODE_INDEX v, mBOOL *visit ) 00169 { 00170 // This node has been visited now: 00171 visit[v] = TRUE; 00172 00173 // Create a vertex iterator: 00174 NODE_ITER v_iter ( g, v ); 00175 00176 for ( NODE_INDEX vtx = v_iter.First_Succ(); 00177 vtx != INVALID_NODE_INDEX ; 00178 vtx = v_iter.Next_Succ() ) 00179 { 00180 if ( ! visit[vtx] ) { 00181 // We haven't seen this one yet -- walk its subgraph: 00182 Forward_Visit ( g, vtx, visit ); 00183 } 00184 } 00185 } 00186 00187 // ==================================================================== 00188 00189 static void 00190 Backward_Visit ( GRAPH *g, NODE_INDEX v, mBOOL *visit ) 00191 { 00192 // This node has been visited now: 00193 visit[v] = TRUE; 00194 00195 // Create a vertex iterator: 00196 NODE_ITER v_iter(g, v); 00197 00198 for ( NODE_INDEX vtx = v_iter.First_Pred(); 00199 vtx != INVALID_NODE_INDEX ; 00200 vtx = v_iter.Next_Pred() ) 00201 { 00202 if ( ! visit[vtx] ) { 00203 // We haven't seen this one yet -- walk its subgraph: 00204 Backward_Visit ( g, vtx, visit ); 00205 } 00206 } 00207 } 00208 00209 // ==================================================================== 00210 // 00211 // DFBASE::Connect_graph 00212 // 00213 // Ensure that the entire graph is connected, with a unique entry and a 00214 // unique exit node. This requires a 3-step algorithm, after creating 00215 // the entry and exit nodes: 00216 // 00217 // 1) Go find the nodes without predecessors/successors, and connect 00218 // them to entry/exit. This is a simple enumeration of the nodes 00219 // where order is unimportant. 00220 // 00221 // 2) Do a depth-first successor walk from the entry marking 00222 // reachable nodes. 00223 // 00224 // 3) Search the nodes again for unreachable ones. When one is 00225 // found, connect it to the entry and walk its successors as in 00226 // step (2) before continuing. 00227 // 00228 // Do the predecessor dual of (2/3) to connect nodes unreachable from 00229 // the exit. 00230 // 00231 // This algorithm is not optimal in the sense that because step (3) 00232 // connects unreachable nodes to the entry (exit) in the order it sees 00233 // them in its final walk, it may connect more than necessary. 00234 // 00235 // ==================================================================== 00236 00237 void 00238 DFBASE::Connect_graph ( MEM_POOL *pool ) 00239 { 00240 GRAPH *g = this->Get_callgraph()->Graph(); 00241 NODE_INDEX entry, exit, v; 00242 NODE_INDEX vertex_max; 00243 mBOOL *reach; 00244 00245 // If it's already done, don't bother: 00246 if ( this->Get_entry() != INVALID_NODE_INDEX ) return; 00247 00248 Trace_CG = Get_Trace ( TP_IPA, IPA_TRACE_CG ); 00249 00250 // Add entry and exit nodes: 00251 Set_saved_root ( GRAPH_root (g) ); 00252 this -> Set_entry ( entry = g->Add_Node ( NULL ) ); 00253 this -> Set_exit ( exit = g->Add_Node ( NULL ) ); 00254 GRAPH_root(g) = entry; 00255 00256 // We need a vector to note reachable nodes: 00257 vertex_max = GRAPH_vmax(g); 00258 reach = (mBOOL *) MEM_POOL_Alloc ( pool, sizeof(NODE_INDEX)*vertex_max ); 00259 if ( reach == NULL ) { 00260 ErrMsg ( EC_No_Mem, "DFBASE::Connect_graph" ); 00261 } 00262 00263 // Trace: 00264 if ( Trace_CG ) { 00265 fprintf ( TFile, 00266 "<ips> Connect_Graph: entry=%d, exit=%d, count=%d (max=%d)\n", 00267 entry, exit, GRAPH_vcnt(g), vertex_max ); 00268 } 00269 00270 // Phase 1: Iterate over all the vertices: 00271 FOR_EACH_NODE ( g, v ) { 00272 00273 // If the vertex has no predecessors, create an edge from entry: 00274 if ( g->Num_Preds(v) == 0 ) { 00275 if ( v != entry ) { 00276 g->Add_Edge ( entry, v, NULL ); 00277 if ( Trace_CG ) { 00278 fprintf ( TFile, "<ips>\tAdding (1n) %d->%d\n", entry, v ); 00279 } 00280 } 00281 } 00282 00283 // If the vertex has no successors, create an edge to exit: 00284 if ( g->Num_Succs(v) == 0 ) { 00285 if ( v != exit ) { 00286 g->Add_Edge ( v, exit, NULL ); 00287 if ( Trace_CG ) { 00288 fprintf ( TFile, "<ips>\tAdding (1x) %d->%d\n", v, exit ); 00289 } 00290 } 00291 } 00292 } 00293 00294 // Phase 2: Mark nodes reachable from the entry: 00295 bzero ( reach, sizeof(mBOOL) * vertex_max ); 00296 Forward_Visit ( g, entry, reach ); 00297 00298 // Phase 3: Find unconnected components and connect them: 00299 FOR_EACH_NODE ( g, v ) { 00300 if ( ! reach[v] && v != entry ) { 00301 g->Add_Edge ( entry, v, NULL ); 00302 Forward_Visit ( g, v, reach ); 00303 if ( Trace_CG ) { 00304 fprintf ( TFile, "<ips>\tAdding (3n) %d->%d\n", entry, v ); 00305 } 00306 } 00307 } 00308 00309 // Phase 4: Mark nodes reachable from the exit: 00310 bzero ( reach, sizeof(mBOOL) * vertex_max ); 00311 Backward_Visit ( g, exit, reach ); 00312 00313 // Phase 5: Find unconnected components and connect them: 00314 FOR_EACH_NODE ( g, v ) { 00315 if ( ! reach[v] && v != exit ) { 00316 g->Add_Edge ( v, exit, NULL ); 00317 Backward_Visit ( g, v, reach ); 00318 if ( Trace_CG ) { 00319 fprintf ( TFile, "<ips>\tAdding (5x) %d->%d\n", v, exit ); 00320 } 00321 } 00322 } 00323 00324 // Free our junk memory: 00325 MEM_POOL_FREE ( pool, reach ); 00326 } 00327 00328 // ==================================================================== 00329 // 00330 // Reverse_Graph / DFBASE::Reverse_graph 00331 // 00332 // Reverse the graph for backward data flow problems. The first 00333 // function does the underlying graph reversal (i.e. changes direction 00334 // of all the edges and switches predecessor and successor lists), and 00335 // the second also switches the entry/exit indicators in the dataflow 00336 // control structure. 00337 // 00338 // ==================================================================== 00339 00340 void 00341 Reverse_Graph ( GRAPH *g ) 00342 { 00343 NODE_INDEX v; 00344 EDGE_INDEX e, e2; 00345 00346 // Switch from and to lists of vertices: from->to, to->from: 00347 for ( v=0; v<GRAPH_vmax(g); v++ ) { 00348 if ( NODE_fcnt ( &GRAPH_v_i(g,v) ) != -1 ) { 00349 e = NODE_from ( &GRAPH_v_i(g,v) ); 00350 NODE_from ( &GRAPH_v_i(g,v) ) = NODE_to ( &GRAPH_v_i(g,v) ); 00351 NODE_to ( &GRAPH_v_i(g,v) ) = e; 00352 } 00353 } 00354 00355 // Switch from and to vertices of edges: 00356 for ( e=0; e<GRAPH_emax(g); e++ ) { 00357 if ( EDGE_from ( &GRAPH_e_i(g,e) ) != INVALID_EDGE_INDEX ) { 00358 v = EDGE_from ( &GRAPH_e_i(g,e) ) ; 00359 EDGE_from ( &GRAPH_e_i(g,e) ) = EDGE_to ( &GRAPH_e_i(g,e) ); 00360 EDGE_to ( &GRAPH_e_i(g,e) ) = v; 00361 e2 = EDGE_nfrom ( &GRAPH_e_i(g,e) ); 00362 EDGE_nfrom ( &GRAPH_e_i(g,e) ) = EDGE_nto ( &GRAPH_e_i(g,e) ); 00363 EDGE_nto ( &GRAPH_e_i(g,e) ) = e2; 00364 } 00365 } 00366 } 00367 00368 // ==================================================================== 00369 00370 void 00371 DFBASE::Reverse_graph () 00372 { 00373 NODE_INDEX new_entry; 00374 00375 // Reverse the underlying graph: 00376 Reverse_Graph ( Get_callgraph()->Graph() ); 00377 00378 // Exchange the entry/exit nodes: 00379 new_entry = this->Get_exit(); 00380 Set_exit ( Get_entry() ); 00381 Set_entry ( new_entry ); 00382 00383 GRAPH_root ( Get_callgraph()->Graph() ) = new_entry; 00384 00385 _reversed = ! _reversed; 00386 } 00387 00388 // ==================================================================== 00389 // 00390 // DFBASE::Restore_graph 00391 // 00392 // Restore graph to its original form, removing the entry and exit 00393 // nodes, and reversing it for backward dataflow problems. 00394 // 00395 // ==================================================================== 00396 00397 void 00398 DFBASE::Restore_graph () 00399 { 00400 GRAPH *g = Get_callgraph()->Graph(); 00401 00402 if ( Get_reversed() ) { 00403 Reverse_Graph ( g ); 00404 } 00405 00406 // Delete those unneccesary vertices: all edges originating to and 00407 // from the vertices will be eliminated by default: 00408 g->Delete_Node ( Get_entry() ); 00409 Set_entry ( INVALID_NODE_INDEX ); 00410 g->Delete_Node ( Get_exit() ); 00411 Set_exit ( INVALID_NODE_INDEX ); 00412 00413 GRAPH_root(g) = Get_saved_root(); 00414 Set_saved_root ( INVALID_NODE_INDEX ); 00415 } 00416 00417 // ==================================================================== 00418 // ==================================================================== 00419 // 00420 // DF_PRINT -- an example instance of a dataflow solver 00421 // 00422 // This class is a derived from the dataflow solver class DFBASE using 00423 // simple instantiations of the associated function templates. Its 00424 // purpose, aside from serving as an example, is to trace the call 00425 // graph in the order implied by the solver's iterator. 00426 // 00427 // ==================================================================== 00428 // ==================================================================== 00429 00430 class DF_PRINT : public DFBASE 00431 { 00432 public: 00433 // These will in general be the types of the per-node problem data: 00434 // in this case, we don't need any, so we'll just store NULLs. 00435 typedef void IN_T; 00436 typedef void OUT_T; 00437 00438 private: 00439 // All dataflow solver instances must have these: 00440 IN_T **_in; // Input annotations -- not used 00441 OUT_T **_out; // Output annotations -- not used 00442 00443 // This field is specific to this instance: 00444 FILE *_f; // Output file 00445 00446 public: 00447 00448 // Constructor -- DFBASE's parameters plus a file: 00449 DF_PRINT ( IPA_CALL_GRAPH &cg, DF_DIRECTION df, 00450 MEM_POOL *m, DFN *iter, FILE *f ); 00451 00452 // Destructor -- free extra data: 00453 ~DF_PRINT (); 00454 00455 // ====== Field access ===== 00456 inline FILE *Get_file() const { return _f; }; 00457 00458 // The following accessors are required by the solver templates; 00459 // they can generally be identical to these given IN_T and OUT_T. 00460 inline IN_T **Get_in() const { return _in; }; 00461 inline OUT_T **Get_out() const { return _out; }; 00462 inline void Set_in ( IN_T **in ) { _in = in; }; 00463 inline void Set_out ( OUT_T **out ) { _out = out; }; 00464 inline IN_T *Get_in_elmt(NODE_INDEX i) const { return _in[i]; }; 00465 inline OUT_T *Get_out_elmt(NODE_INDEX i) const { return _out[i]; }; 00466 inline void Set_in_elmt ( NODE_INDEX i, IN_T *in ) 00467 { _in[i] = in; }; 00468 inline void Set_out_elmt ( NODE_INDEX i, OUT_T *out ) 00469 { _out[i] = out; }; 00470 00471 // Initialize the annotation of a callgraph node -- we don't need 00472 // any initialization for this example, but the function is 00473 // required by the instantiation that follows. 00474 inline void Initialize_node ( void * ) { return; }; 00475 00476 // This function, to initialize the callgraph vertex and in/out 00477 // annotations, is required by the solver. It can normally be just 00478 // an instantiation of the template, identical to this one, given 00479 // Initialize_node above. 00480 inline void Initialize_annotations () 00481 { 00482 Initialize_Annotation ( this, this->_in, this->_out ); 00483 }; 00484 00485 // The Meet function merges data from the input edges and the current 00486 // input annotation (given by the in parameter), producing a new 00487 // input annotation, which it returns. It must be able to cope with 00488 // a NULL input annotation the first time. 00489 IN_T *Meet ( IN_T *in, void *vertex_user ); 00490 00491 // The Trans function transfers data from the input annotation (the 00492 // in parameter) using the node information (vertex_user) and the old 00493 // output annotation (out), to produce a new output annotation. In 00494 // this example, we don't do anything interesting. 00495 OUT_T *Trans ( IN_T *in, OUT_T *out, void *vertex_user ); 00496 00497 // One or both of Meet and Trans must set _changed to TRUE if either 00498 // makes a change which may affect the solution for successor nodes. 00499 // In our example, neither will ever set it, so we will do a single 00500 // iteration over the call graph. 00501 00502 // A single-iteration callgraph walk occurs in the solver core, which 00503 // should be an instantiation of Iterative_Solver_Core: 00504 inline void Solver_core() 00505 { 00506 Iterative_Solver_Core ( this ); 00507 } 00508 00509 // The master solver needs to call the solver core above, as well 00510 // as the various setup/cleanup routines. As an interative solver, 00511 // it should be an instantiation of Iterative_Dataflow_Solver: 00512 inline void Solver() 00513 { 00514 Iterative_Dataflow_Solver ( this, Depth_First_Ordering ); 00515 } 00516 00517 // For output from the solver, there are two steps. The first 00518 // initializes any required data structures. Ours does nothing: 00519 inline void Init_IO() const { return; }; 00520 00521 // The second output step calls this function for each callgraph 00522 // node to extract any required information from the solution. 00523 // Generally, this routine should clean up the callgraph nodes, 00524 // although could be done in the destructor. Ours does nothing: 00525 inline void Post_process_IO ( const void * ) const { return; }; 00526 00527 // Both output steps are called from this extraction routine, which 00528 // should generally be an instantiation of Extract_Solution as here: 00529 inline void Extract_solution () { Extract_Solution ( this ); }; 00530 }; 00531 00532 // ==================================================================== 00533 // 00534 // DF_PRINT::DF_PRINT 00535 // 00536 // Constructor for the dataflow printer class. The graph iterator may 00537 // be NULL, in which case the solver must provide it later. 00538 // 00539 // ==================================================================== 00540 00541 DF_PRINT::DF_PRINT ( 00542 IPA_CALL_GRAPH &cg, // The underlying call graph to use 00543 DF_DIRECTION direction, // The dataflow problem direction 00544 MEM_POOL *mpool, // Where to put new junk 00545 DFN *iter, // An iterator over the graph 00546 FILE *f ) // File to print to 00547 : DFBASE ( cg, direction, mpool, iter ) 00548 { 00549 // Record the information provided: 00550 _f = f; 00551 _in = NULL; 00552 _out = NULL; 00553 } 00554 00555 00556 // ==================================================================== 00557 // 00558 // DF_PRINT::~DF_PRINT 00559 // 00560 // Destructor for the dataflow printer class. We must remove the 00561 // input and output annotations; the DFBASE destructor will take care 00562 // of restoring the graph and freeing the iterator memory. 00563 // 00564 // ==================================================================== 00565 00566 DF_PRINT::~DF_PRINT () 00567 { 00568 if ( _in != NULL ) { 00569 MEM_POOL_FREE ( Get_mempool(), _in ); 00570 _in = NULL; 00571 } 00572 if ( _out != NULL ) { 00573 MEM_POOL_FREE ( Get_mempool(), _out ); 00574 _out = NULL; 00575 } 00576 } 00577 00578 // ==================================================================== 00579 // 00580 // DF_PRINT::Meet 00581 // 00582 // Meet operator for the printer class. Simply print the vertex 00583 // information and the input edge names. 00584 // 00585 // ==================================================================== 00586 00587 DF_PRINT::IN_T * 00588 DF_PRINT::Meet ( IN_T *, void *vertex_user ) 00589 { 00590 IPA_NODE *v = (IPA_NODE *)vertex_user; 00591 00592 // Print the vertex: 00593 if ( v != NULL ) { 00594 fprintf ( _f, "Meet vertex: " ); 00595 v->Print ( _f ); 00596 } else { 00597 fprintf ( _f, "Meet NULL vertex\n" ); 00598 return NULL; 00599 } 00600 00601 IPA_SUCC_ITER edge_iter ( Get_callgraph(), v ); 00602 00603 for ( edge_iter.First(); 00604 ! edge_iter.Is_Empty(); 00605 edge_iter.Next()) 00606 { 00607 IPA_EDGE *e = edge_iter.Current_Edge(); 00608 if ( e != NULL ) { 00609 fprintf ( _f, "\tedge: " ); 00610 e->Trace ( Get_callgraph() ); 00611 00612 } else { 00613 fprintf ( _f, "\tNULL edge\n" ); 00614 } 00615 } 00616 if (! v->Icall_List ().empty () ) { 00617 // We've got indirect calls -- print their information, too: */ 00618 Ipl_Summary_Symbol = IPA_get_symbol_array (v); 00619 const IPA_ICALL_LIST& icall_list = v->Icall_List (); 00620 00621 for (IPA_ICALL_LIST::const_iterator icall_iter = icall_list.begin (); 00622 icall_iter != icall_list.end (); ++icall_iter) { 00623 00624 SUMMARY_CALLSITE *c = (*icall_iter)->Callsite(); 00625 if ( c != NULL ) { 00626 fprintf ( _f, "\tedge-i: " ); 00627 c->Trace (); 00628 } else { 00629 fprintf ( _f, "\tNULL edge-i\n" ); 00630 } 00631 } 00632 } 00633 00634 // We're not using the in vector -- just return NULL: 00635 return NULL; 00636 } 00637 00638 // ==================================================================== 00639 // 00640 // DF_PRINT::Trans 00641 // 00642 // Transfer operator for the printer class. Simply print a bar to 00643 // separate nodes. 00644 // 00645 // ==================================================================== 00646 00647 /*ARGSUSED*/ 00648 DF_PRINT::OUT_T * 00649 DF_PRINT::Trans ( IN_T *in, OUT_T *out, void *vertex_user ) 00650 { 00651 fprintf ( _f, "%s", SBar ); 00652 00653 // We're not using the out vector -- just return NULL: 00654 return NULL; 00655 } 00656 00657 // ==================================================================== 00658 // 00659 // Trace_Callgraph 00660 // 00661 // Instantiate a dataflow solver as a very large hammer to print a 00662 // trace of the given callgraph. 00663 // 00664 // NOTE: We carefully push and pop the memory pool here, but it should 00665 // not be necessary if we've handled everything right... 00666 // 00667 // ==================================================================== 00668 00669 void 00670 Trace_Callgraph ( IPA_CALL_GRAPH &cg, DF_DIRECTION dir, const char *msg ) 00671 { 00672 // Push the local memory pool: 00673 MEM_POOL_Push ( MEM_local_pool_ptr ); 00674 00675 // Print the heading: 00676 fprintf ( TFile, "%s%sDataflow %s Callgraph Trace -- %s\n%s%s\n", 00677 DBar, DBar, 00678 ( dir == FORWARD ) ? "Forward" : "Backward", msg, 00679 DBar, DBar ); 00680 00681 { 00682 // Create a solver class instance: 00683 DF_PRINT solver ( cg, dir, MEM_local_pool_ptr, NULL, TFile ); 00684 00685 // Run the solver: 00686 solver.Solver (); 00687 00688 // Clean up after ourselves: 00689 solver.Extract_solution (); 00690 00691 // Destructor called here... 00692 } 00693 00694 // Pop the local memory pool: 00695 MEM_POOL_Pop ( MEM_local_pool_ptr ); 00696 }
1.5.6