|
OpenADFortTk (basic)
|
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