OpenADFortTk (basic)
src/testers/inline.cxx
Go to the documentation of this file.
00001 
00002 //***************************************************************************
00003 // 
00004 //***************************************************************************
00005 
00006 #include "clone.h"          /* Open64: IPO_CLONE */
00007 #include <lib/support/WhirlParentize.h>
00008 #include <vector>
00009 using std::vector;
00010 
00011 static WN* 
00012 FindCallToInlinedFn(const char* callee_nm, WN* wn);
00013 
00014 void 
00015 InlineTest(PU_Info* pu_forest)
00016 {
00017   // Given a PU forest 'pu_forest'
00018   //   * searches for the first pu named 'inline_*'.  This is
00019   //     assumed to be the subroutine for inlining.
00020   //   * searches the program pu for the first call of this subroutine.
00021   //   * inlines the subroutine into the main pu
00022   // 
00023   // Limitations: can only inline subroutines that
00024   //   - have one return statement (or none)
00025   //   - are called with variables as actual parameters (as opposed to
00026   //     an expression like sin(x)).
00027   //
00028   // Note: if we create entirely new functions, we will need to update
00029   //   pu->sym_tab map.
00030   
00031   // -------------------------------------------------------
00032   // 1. Find inlined functions (callee) named inline_x
00033   // -------------------------------------------------------
00034   const char* calleeNm = NULL;
00035   PU_Info*    calleePU = NULL;
00036   WN*         calleeWN = NULL; // OPR_FUNC_ENTRY
00037   WN_MAP_TAB* calleeMaptab = NULL;
00038   SCOPE*      calleeStab = NULL;
00039   SYMTAB_IDX  calleeStabIdx = 0;
00040   
00041   Pro64IRProcIterator procIt(pu_forest);
00042   for ( ; procIt.IsValid(); ++procIt) { 
00043     PU_Info* pu = (PU_Info*)procIt.Current();
00044     ST_IDX st = PU_Info_proc_sym(pu);
00045     const char* nm = ST_name(st);
00046 
00047     if (strncmp(nm, "inline_", 7) == 0) {
00048       calleeNm = nm;
00049       calleePU = pu;
00050       calleeWN = PU_Info_tree_ptr(calleePU);
00051       calleeMaptab = PU_Info_maptab(pu);
00052       calleeStab = Scope_tab;
00053       calleeStabIdx = PU_lexical_level(PU_Info_pu(pu));
00054       break;
00055     }
00056   } // global state set for calleePU
00057   
00058   // -------------------------------------------------------
00059   // 2. Find the caller, i.e. callsites to inline_x. In the MainPU
00060   // -------------------------------------------------------
00061   PU_Info*    callerPU = NULL;
00062   WN*         callsiteWN = NULL;
00063   WN_MAP_TAB* callerMaptab = NULL;
00064   SCOPE*      callerStab = NULL;
00065   SYMTAB_IDX  callerStabIdx = 0;
00066   
00067   procIt.Reset();
00068   for ( ; procIt.IsValid(); ++procIt) { 
00069     PU_Info* pu = (PU_Info*)procIt.Current();
00070     if (PU_is_mainpu(PU_Info_pu(pu))) {
00071       callerPU = pu;
00072       callsiteWN = FindCallToInlinedFn(calleeNm, PU_Info_tree_ptr(callerPU));
00073       callerMaptab = PU_Info_maptab(pu);
00074       callerStab = Scope_tab;
00075       callerStabIdx = PU_lexical_level(PU_Info_pu(pu));
00076       break;
00077     }
00078   } // global state set for callerPU
00079   
00080   if (!callsiteWN) {
00081     return;
00082   }
00083 
00084   // * Gather actual parameters (at callsite)
00085   INT nparam = WN_kid_count(callsiteWN);
00086   vector<ST*> callsiteParams(nparam);
00087   for (int i = 0; i < nparam; ++i) {
00088     WN* parm = WN_kid(callsiteWN, i);
00089     ST* st = WN_st(WN_kid0(parm));
00090     callsiteParams[i] = st;
00091   }
00092   
00093   // For the below, compare to
00094   // IPO_INLINE::Process(), ipa/main/optimize/ipo_inline.cxx.
00095   
00096   // -------------------------------------------------------
00097   // 1. Create a copy of the callee
00098   // -------------------------------------------------------
00099   // IPO_INLINE::Process_Callee(...)
00100   //   IPO_INLINE::Clone_Callee(...)
00101   
00102   // Global tables should point to callee
00103   PU_SetGlobalState(calleePU);
00104   
00105   // FIXME: allocates WN_mem_pool_ptr, which is used in IPO_CLONE::Copy_Node
00106   WN* bogus_wn = WN_CreateIntconst(OPC_I4INTCONST, 0);
00107   
00108   WN_MAP parentmap = WN_MAP_Create(MEM_pu_pool_ptr);
00109   IPO_SYMTAB ipo_symtab(calleeStab, callerStab, calleeStabIdx, callerStabIdx,
00110                         MEM_pu_pool_ptr, TRUE /*same_file*/);
00111   IPO_CLONE cloner(callerMaptab, calleeMaptab, parentmap,
00112                    calleeStab, callerStab, calleeStabIdx, callerStabIdx,
00113                    &ipo_symtab, MEM_pu_pool_ptr, TRUE /*same_file*/, 0);  
00114   
00115   // * Copy symtabs of callee into caller's
00116   //cloner.Promote_Statics();
00117   cloner.Get_sym()->Update_Symtab(FALSE /*label_only*/);
00118     
00119   // * Clone, setting symtab indices to reference caller's tables
00120   WN* inlinedBodyWn = cloner.Clone_Tree(WN_func_body(calleeWN));
00121   
00122   // * Gather formals parameters (at callee)
00123   nparam = WN_num_formals(calleeWN);
00124   vector<ST*> calleeParams(nparam);
00125   for (int i = 0; i < nparam; ++i) {
00126     ST* st = WN_st(WN_formal(calleeWN, i));
00127     st = ipo_symtab.Get_ST(st); // get the version on the caller side
00128     calleeParams[i] = st;
00129   }
00130   assert(callsiteParams.size() == calleeParams.size());
00131   
00132   // -------------------------------------------------------
00133   // 2. Update and patch body of inlined function
00134   // -------------------------------------------------------
00135   // IPO_INLINE::Process_Callee(...)
00136   //   IPO_INLINE::Clone_Callee(...) and
00137   //   IPO_INLINE::Walk_and_Update_Callee(...)
00138 
00139   // Global tables should point to caller (cloned tree uses caller's symtab)
00140   PU_SetGlobalState(callerPU);
00141   
00142   // * Recreate parent pointers
00143   // W2CF_Parentize(inlinedBodyWn); // WN_Parentize() - ipo_parent.cxx
00144   
00145   // Prepare map: formal params -> actual params
00146   map<ST*, ST*> formals2actuals;
00147   for (int i = 0; i < nparam; ++i) {
00148     ST* formalST = calleeParams[i];
00149     ST* actualST = callsiteParams[i];
00150     formals2actuals[formalST] = actualST;
00151   }
00152   
00153   // * Replace any formal parameters with actual parameters
00154   //   Cf. IPO_INLINE::Process_Formals(...) (actually only preparation
00155   //   for Process_Op_Code(...)
00156   // * Remove RETURN in body of inlined function
00157   //   Cf. IPO_INLINE::Process_Op_Code(...)
00158   WN_TREE_CONTAINER<PRE_ORDER> wnIt(inlinedBodyWn);
00159   WN_TREE_CONTAINER<PRE_ORDER>::iterator it;
00160   for (it = wnIt.begin(); it != wnIt.end(); ++it) {
00161     WN* curWN = it.Wn();
00162     OPERATOR opr = WN_operator(curWN);
00163     
00164     // Replace reference to a formal param with actual param
00165     if (OPERATOR_has_sym(opr)) {
00166       ST* curST = WN_st(curWN);
00167       ST* actualST = formals2actuals[curST];
00168       if (actualST) {
00169         WN_st_idx(curWN) = ST_st_idx(actualST);
00170       }
00171     }
00172 
00173     // Remove returns
00174     if (opr == OPR_RETURN) {
00175       WN* blkWN = FindParentWNBlock(inlinedBodyWn, curWN);
00176       WN_DELETE_FromBlock(blkWN, curWN);
00177       break; // should only be one, at end of block (FIXME)
00178     }
00179   }
00180   
00181   // -------------------------------------------------------
00182   // 3. Replace callsite with body of inlined function
00183   // -------------------------------------------------------
00184   // IPO_INLINE::Post_Process_Caller(...)
00185   if (WN_first (inlinedBodyWn) != NULL) {
00186     // Replace callsite with body of inlined function
00187     WN_next(WN_prev(callsiteWN)) = WN_first(inlinedBodyWn);
00188     WN_prev(WN_first(inlinedBodyWn)) = WN_prev(callsiteWN);
00189     
00190     WN_next(WN_last(inlinedBodyWn)) = WN_next(callsiteWN);
00191     WN_prev(WN_next(callsiteWN)) = WN_last(inlinedBodyWn);
00192   } else {
00193     // Replace callsite with (empty) body of inlined function
00194     WN_next(WN_prev(callsiteWN)) = WN_next(callsiteWN);
00195     WN_prev(WN_next(callsiteWN)) = WN_prev(callsiteWN);
00196   }
00197 
00198 #if 0  
00199   WN* callerWN = PU_Info_tree_ptr(callerPU);
00200   dump_tree(callerWN);
00201 #endif  
00202 }
00203 
00204 static WN* 
00205 FindCallToInlinedFn(const char* calleeNm, WN* wn)
00206 {
00207   WN_TREE_CONTAINER<PRE_ORDER> wnIt(wn);
00208   WN_TREE_CONTAINER<PRE_ORDER>::iterator it;
00209   for (it = wnIt.begin(); it != wnIt.end(); ++it) {
00210     WN* curWN = it.Wn();
00211     
00212     OPERATOR opr = WN_operator(curWN);
00213     if (opr == OPR_CALL && (strcmp(ST_name(WN_st(curWN)), calleeNm) == 0)) {
00214       return curWN;
00215     }
00216   }
00217   
00218   return NULL;
00219 }
00220 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines