Open64 (mfef90, whirl2f, and IR tools)
TAG: version-openad; SVN changeset: 916
|
00001 /* 00002 00003 Copyright (C) 2000, 2001 Silicon Graphics, Inc. All Rights Reserved. 00004 00005 This program is free software; you can redistribute it and/or modify it 00006 under the terms of version 2 of the GNU General Public License as 00007 published by the Free Software Foundation. 00008 00009 This program is distributed in the hope that it would be useful, but 00010 WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00012 00013 Further, this software is distributed without any warranty that it is 00014 free of the rightful claim of any third person regarding infringement 00015 or the like. Any license provided herein, whether implied or 00016 otherwise, applies only to this software file. Patent licenses, if 00017 any, provided herein do not apply to combinations of this program with 00018 other software, or any other product whatsoever. 00019 00020 You should have received a copy of the GNU General Public License along 00021 with this program; if not, write the Free Software Foundation, Inc., 59 00022 Temple Place - Suite 330, Boston MA 02111-1307, USA. 00023 00024 Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pky, 00025 Mountain View, CA 94043, or: 00026 00027 http://www.sgi.com 00028 00029 For further information regarding this notice, see: 00030 00031 http://oss.sgi.com/projects/GenInfo/NoticeExplan 00032 00033 */ 00034 00035 00036 /* ==================================================================== 00037 * ==================================================================== 00038 * 00039 * 00040 * Revision history: 00041 * 07-Oct-94 - Original Version 00042 * 00043 * Description: 00044 * 00045 * Maintains information pertaining to the translation of compilation 00046 * units, and provides routines for collecting such information: 00047 * 00048 * * Symbol-name and Symbol-id information 00049 * 00050 * * Preg usage information 00051 * 00052 * * Function call and return site information 00053 * 00054 * The details of the information collected here may vary between 00055 * whirl2f and whirl2c, but every collection of information 00056 * pertains to both. A collection of information pertaining only 00057 * to one or the other should be maintained in a module specific 00058 * to one or the other, not here. 00059 * 00060 * ==================================================================== 00061 * ==================================================================== 00062 */ 00063 00064 #ifdef _KEEP_RCS_ID 00065 #endif /* _KEEP_RCS_ID */ 00066 00067 #include <string.h> 00068 00069 #include "common_include.h" 00070 #include "w2cf_parentize.h" /* For W2CF_Parent_Map */ 00071 #include "mempool.h" 00072 #include "const.h" 00073 #include "wn_util.h" 00074 #include "PUinfo.h" 00075 #include "targ_sim.h" 00076 #include "unparse_target.h" 00077 00078 #define IS_RETURN_PREG(wn) \ 00079 (ST_class(WN_st(wn)) == CLASS_PREG \ 00080 && (Is_Return_Preg(WN_load_offset(wn)) \ 00081 || WN_st(wn) == Return_Val_Preg ) ) 00082 00083 /*------------------ Some PU state variables --------------------------* 00084 *---------------------------------------------------------------------*/ 00085 00086 const WN *PUinfo_current_func = NULL; /* OPR_FUNC_ENTRY node */ 00087 const RETURN_PREG *PUinfo_return_preg = NULL; /* Pregs for return type */ 00088 TOKEN_BUFFER PUinfo_local_decls = NULL; /* Tokens for local decls */ 00089 TOKEN_BUFFER PUinfo_pragmas = NULL; /* Tokens for PU level pragmas */ 00090 UINT PUinfo_local_decls_indent = 0;/*Indentation for local decls*/ 00091 00092 00093 /*---------------- Information about the usage if pregs --------------- 00094 * 00095 * We accumulate information about usage of CLASS_PREG symbols, such 00096 * that we can declare them as local variables of suitable type and 00097 * minimize the need to cast them to other types. We use a very 00098 * simple hash-table of 73 elements, indexed by the preg offset, to 00099 * reduce search times. Note that all uses of pregs must be determined 00100 * before we start translating a PU, while declarations of pregs occur 00101 * upon actual use. We cannot refer to or declare pregs until all 00102 * information has been accumulated, since we otherwise do not know 00103 * what types of pregs we need (in particular, we only declare one type 00104 * of integral pregs). Each entry in this preg-table may represent 00105 * multiple preg declarations. 00106 * 00107 * We enter the pregs for a PU into the name-disambiguation symbol table 00108 * before attempting any translation of the PU. This ensures that the 00109 * preg names remain invariant regardless whether or not we only 00110 * translate a small portion of the PU. 00111 * 00112 *---------------------------------------------------------------------*/ 00113 00114 typedef enum Preg_Usage_Kind 00115 { 00116 PREG_AS_UNKNOWN, 00117 PREG_AS_INT8, /* FIRST_PREG_USAGE_KIND, SMALLEST_iPREG_USAGE_KIND */ 00118 PREG_AS_UINT8, 00119 PREG_AS_INT16, 00120 PREG_AS_UINT16, 00121 PREG_AS_INT32, 00122 PREG_AS_UINT32, 00123 PREG_AS_INT64, 00124 PREG_AS_UINT64, /* LARGEST_iPREG_USAGE_KIND */ 00125 PREG_AS_IEEE32, 00126 PREG_AS_IEEE64, 00127 PREG_AS_QUAD, 00128 PREG_AS_C4, 00129 PREG_AS_C8, 00130 PREG_AS_CQ /* LAST_PREG_USAGE_KIND */ 00131 } PREG_USAGE_KIND; 00132 00133 #define FIRST_PREG_USAGE_KIND PREG_AS_INT8 00134 #define SMALLEST_iPREG_USAGE_KIND FIRST_PREG_USAGE_KIND 00135 #define LARGEST_iPREG_USAGE_KIND PREG_AS_UINT64 00136 #define LAST_PREG_USAGE_KIND PREG_AS_CQ 00137 00138 static const MTYPE Ukind_to_Mtype[LAST_PREG_USAGE_KIND+1] = 00139 { 00140 MTYPE_UNKNOWN, /* PREG_AS_UNKNOWN */ 00141 MTYPE_I1, /* PREG_AS_INT8 */ 00142 MTYPE_U1, /* PREG_AS_UINT8 */ 00143 MTYPE_I2, /* PREG_AS_INT16 */ 00144 MTYPE_U2, /* PREG_AS_UINT16 */ 00145 MTYPE_I4, /* PREG_AS_INT32 */ 00146 MTYPE_U4, /* PREG_AS_UINT32 */ 00147 MTYPE_I8, /* PREG_AS_INT64 */ 00148 MTYPE_U8, /* PREG_AS_UINT64 */ 00149 MTYPE_F4, /* PREG_AS_IEEE32 */ 00150 MTYPE_F8, /* PREG_AS_IEEE64 */ 00151 MTYPE_FQ, /* PREG_AS_QUAD */ 00152 MTYPE_C4, /* PREG_AS_C4 */ 00153 MTYPE_C8, /* PREG_AS_C8 */ 00154 MTYPE_CQ /* PREG_AS_CQ */ 00155 }; 00156 00157 typedef struct Preg_Info PREG_INFO; 00158 struct Preg_Info 00159 { 00160 BOOL use[LAST_PREG_USAGE_KIND+1]; /* prepass analysis use-profile */ 00161 BOOL decl[LAST_PREG_USAGE_KIND+1]; /* preg declaration status */ 00162 INT16 preg_num; /* preg number */ 00163 PREG_INFO *next; /* next in table entry */ 00164 }; 00165 #define PREG_INFO_use(info, ukind) (info)->use[ukind] 00166 #define PREG_INFO_decl(info, ukind) (info)->decl[ukind] 00167 #define PREG_INFO_preg_num(info) (info)->preg_num 00168 #define PREG_INFO_next(info) (info)->next 00169 00170 #define PREG_INFO_HASH_TABLE_SIZE 73 00171 #define PREG_INFO_HASH_IDX(offset) \ 00172 (UINT32)(offset % PREG_INFO_HASH_TABLE_SIZE) 00173 00174 static PREG_INFO *Preg_Info_Hash_Tbl[PREG_INFO_HASH_TABLE_SIZE]; 00175 static PREG_INFO *Free_Preg_Info = NULL; 00176 00177 00178 static BOOL 00179 WN_in_ioitem(const WN *wn) 00180 { 00181 /* This assumes we cannot have a region with an IO_ITEM. 00182 */ 00183 BOOL found_io = FALSE, found_region = FALSE; 00184 00185 wn = W2CF_Get_Parent(wn); 00186 while (wn != NULL && !found_io && !found_region) 00187 { 00188 if (WN_opc_operator(wn) == OPR_IO_ITEM) 00189 found_io = TRUE; 00190 else if (WN_opc_operator(wn) == OPR_REGION) 00191 found_region = TRUE; 00192 wn = W2CF_Get_Parent(wn); 00193 } 00194 return (found_io); 00195 } /* WN_in_ioitem */ 00196 00197 00198 static PREG_USAGE_KIND 00199 Mtype_to_Ukind(MTYPE mtype) 00200 { 00201 /* While PREG_USAGE_KIND --> MTYPE is a complete one-to-one 00202 * mapping, and therefore can be represented as table, the 00203 * reverse mapping is a partial mapping (e.g. we do not expect 00204 * to see MTYPE_V uses of pregs), and the safest way to handle 00205 * this is by means of a switch statment. 00206 */ 00207 PREG_USAGE_KIND ukind; 00208 00209 switch (mtype) 00210 { 00211 case MTYPE_I1: 00212 ukind = PREG_AS_INT8; 00213 break; 00214 case MTYPE_U1: 00215 ukind = PREG_AS_UINT8; 00216 break; 00217 case MTYPE_I2: 00218 ukind = PREG_AS_INT16; 00219 break; 00220 case MTYPE_U2: 00221 ukind = PREG_AS_UINT16; 00222 break; 00223 case MTYPE_I4: 00224 ukind = PREG_AS_INT32; 00225 break; 00226 case MTYPE_U4: 00227 ukind = PREG_AS_UINT32; 00228 break; 00229 case MTYPE_I8: 00230 ukind = PREG_AS_INT64; 00231 break; 00232 case MTYPE_U8: 00233 ukind = PREG_AS_UINT64; 00234 break; 00235 case MTYPE_F4: 00236 ukind = PREG_AS_IEEE32; 00237 break; 00238 case MTYPE_F8: 00239 ukind = PREG_AS_IEEE64; 00240 break; 00241 case MTYPE_FQ: 00242 ukind = PREG_AS_QUAD; 00243 break; 00244 case MTYPE_C4: 00245 ukind = PREG_AS_C4; 00246 break; 00247 case MTYPE_C8: 00248 ukind = PREG_AS_C8; 00249 break; 00250 case MTYPE_CQ: 00251 ukind = PREG_AS_CQ; 00252 break; 00253 default: 00254 ukind = PREG_AS_UNKNOWN; 00255 00256 /* fix a bug here,if don't give a value to ukind in this 00257 * case,will cause segmentation fault in Linux version and 00258 * Solaris version,but it's OK for Irix version.Since Irix 00259 * version give this variable "0" value,this is exactly what we 00260 * give it here 00261 */ 00262 Is_True(FALSE, ("Illegal MTYPE for Mtype_to_Ukind mapping")); 00263 break; 00264 } 00265 return ukind; 00266 } /* Mtype_to_Ukind */ 00267 00268 00269 static PREG_INFO * 00270 Get_Preg_Info(INT16 preg_num) 00271 { 00272 PREG_INFO *preg_info = NULL; 00273 00274 /* Linear search for a matching entry in the hash table list */ 00275 for (preg_info = Preg_Info_Hash_Tbl[PREG_INFO_HASH_IDX(preg_num)]; 00276 preg_info != NULL && PREG_INFO_preg_num(preg_info) != preg_num; 00277 preg_info = PREG_INFO_next(preg_info)); 00278 return preg_info; 00279 } /* Get_Preg_Info */ 00280 00281 00282 static void 00283 Accumulate_Preg_Info(TY_IDX preg_ty, INT16 preg_num) 00284 { 00285 /* Given a preg with a certain number, update the information we 00286 * have about it. 00287 */ 00288 PREG_INFO *preg_info; 00289 INT usage_kind; 00290 00291 if (preg_num == -1) 00292 return; 00293 00294 Is_True(TY_Is_Scalar(preg_ty), 00295 ("Expected KIND_SCALAR symbol in Accumulate_Preg_Info()")); 00296 00297 /* Get the preg info record corresponding to this usage. Create one 00298 * if none exists. 00299 */ 00300 preg_info = Get_Preg_Info(preg_num); 00301 if (preg_info == NULL) 00302 { 00303 /* Add a new entry to the hash-table */ 00304 if (Free_Preg_Info == NULL) 00305 preg_info = TYPE_ALLOC_N(PREG_INFO, 1); 00306 else 00307 { 00308 preg_info = Free_Preg_Info; 00309 Free_Preg_Info = PREG_INFO_next(Free_Preg_Info); 00310 } 00311 00312 /* Reset the usage and also set the other fields */ 00313 for (usage_kind = (INT)FIRST_PREG_USAGE_KIND; 00314 usage_kind <= (INT)LAST_PREG_USAGE_KIND; 00315 usage_kind++) 00316 { 00317 PREG_INFO_decl(preg_info, usage_kind) = FALSE; 00318 PREG_INFO_use(preg_info, usage_kind) = FALSE; 00319 } 00320 PREG_INFO_preg_num(preg_info) = preg_num; 00321 PREG_INFO_next(preg_info) = 00322 Preg_Info_Hash_Tbl[PREG_INFO_HASH_IDX(preg_num)]; 00323 Preg_Info_Hash_Tbl[PREG_INFO_HASH_IDX(preg_num)] = preg_info; 00324 } 00325 00326 /* Record this usage */ 00327 usage_kind = (INT)Mtype_to_Ukind(TY_mtype(preg_ty)); 00328 PREG_INFO_use(preg_info, usage_kind) = TRUE; 00329 } /* Accumulate_Preg_Info */ 00330 00331 00332 static void 00333 Enter_Pregs_Into_Symtab(void) 00334 { 00335 /* Assuming all preg_info has been accumulated and the PU symtab 00336 * has been pushed, this will enter the pregs accumulated into 00337 * the current symtab. Note that this should be done prior to 00338 * translation of the PU, but typically after entering symbols for 00339 * other variables local to the PU. The pregs entered into the 00340 * symtab will be a superset of the pregs we actually need to declare. 00341 */ 00342 TY_IDX preg_ty; 00343 PREG_INFO *preg_info; 00344 INT hash_idx; 00345 INT usage_kind; 00346 00347 for (hash_idx = 0; hash_idx < PREG_INFO_HASH_TABLE_SIZE; hash_idx++) 00348 for (preg_info = Preg_Info_Hash_Tbl[hash_idx]; 00349 preg_info != NULL; 00350 preg_info = PREG_INFO_next(preg_info)) 00351 { 00352 /* Only define one (largest) preg-type for integral pregs 00353 * at the same preg-number. 00354 */ 00355 for (usage_kind = (INT)LARGEST_iPREG_USAGE_KIND; 00356 (usage_kind >= (INT)SMALLEST_iPREG_USAGE_KIND && 00357 !PREG_INFO_use(preg_info, usage_kind)); 00358 usage_kind--); 00359 00360 if (usage_kind >= (INT)SMALLEST_iPREG_USAGE_KIND) 00361 { 00362 preg_ty = Stab_Mtype_To_Ty(Ukind_to_Mtype[usage_kind]); 00363 W2CF_Symtab_Nameof_Preg(preg_ty, PREG_INFO_preg_num(preg_info)); 00364 } 00365 00366 /* Define all the non-integral pregs as separate variables */ 00367 for (usage_kind = (INT)LARGEST_iPREG_USAGE_KIND + 1; 00368 usage_kind <= (INT)LAST_PREG_USAGE_KIND; 00369 usage_kind++) 00370 { 00371 if (PREG_INFO_use(preg_info, usage_kind)) 00372 { 00373 preg_ty = Stab_Mtype_To_Ty(Ukind_to_Mtype[usage_kind]); 00374 W2CF_Symtab_Nameof_Preg(preg_ty, PREG_INFO_preg_num(preg_info)); 00375 } 00376 } 00377 } /* for each preg in this hash-table bucket */ 00378 } /* Enter_Pregs_Into_Symtab */ 00379 00380 00381 /*--------------- Information about the local PU symbols -------------- 00382 * 00383 * We enter the local declarations for a PU into the name-disambiguation 00384 * symbol table before attempting any translation of the PU. This 00385 * ensures that the symbol names remain invariant regardless whether or 00386 * not we translate only a small portion of the PU. 00387 *---------------------------------------------------------------------*/ 00388 00389 static void 00390 Enter_Local_Syms_Into_Symtab(const ST *func_st) 00391 { 00392 ST_IDX st_idx; 00393 const ST *st; 00394 00395 (void)W2CF_Symtab_Nameof_St(func_st); 00396 FOREACH_SYMBOL(CURRENT_SYMTAB, st, st_idx) 00397 { 00398 if ((ST_sym_class(st) == CLASS_VAR || ST_sym_class(st) == CLASS_FUNC) && 00399 !Stab_Is_Based_At_Common_Or_Equivalence(st)) 00400 { 00401 if (W2X_Unparse_Target->Enter_Symtab_Pointee_Names() && 00402 TY_Is_Pointer(ST_type(st))) 00403 (void)W2CF_Symtab_Nameof_St_Pointee(st); 00404 (void)W2CF_Symtab_Nameof_St(st); 00405 } 00406 } 00407 } /* Enter_Local_Syms_Into_Symtab */ 00408 00409 00410 /*--------- Information about function call and return sites --------- 00411 * 00412 * We accumulate information about call sites and the associated 00413 * stores of return-registers by means of an inorder traversal 00414 * (Accumulate_Stmt_PUinfo) of the statement tree for a PU. We try 00415 * to match an OPR_CALL (or OPR_ICALL or OPR_PICCALL or 00416 * OPR_INTRINSIC_CALL) node, immediately followed by one or two 00417 * OPR_ISTORE of return registers, with a pattern we can simplify. 00418 * E.g.: 00419 * 00420 * (OPR_CALL f) 00421 * (OPR_ISTORE (LDID return_preg1) (LDA "x")) 00422 * (OPR_ISTORE (LDID return_preg2) (LDA "x")) 00423 * 00424 * can be translated into the C code: 00425 * 00426 * x = f(); 00427 * 00428 * We also need to identify references to return registers outside 00429 * of the patterns we recognize, since such occurrences of return 00430 * registers mean we must assign the appropriate values to the 00431 * corresponding "register" variables. To handle this, we set the 00432 * call-site attribute "in_regs" during Accumulate_Expr_PUinfo() 00433 * to indicate that we have seen such an irregular reference to a 00434 * return register. 00435 * 00436 * Similarly, we accumulate information about the return sites and 00437 * the associated store of a value into return-registers. 00438 * 00439 * For a function returning a struct, we expect the return-registers 00440 * to be stored into a (temporary) variable at the call sites. At the 00441 * return sites we expect the values to be loaded from a (temporary) 00442 * variable into the return-registers. When these expectations are 00443 * met, we can eliminate the intermediate step of the loading from and 00444 * storing to return-registers, and instead return directly from/to the 00445 * (temporary) variable. 00446 * 00447 * For a function returning character strings, we always assume these 00448 * are returned through a first argument. 00449 * 00450 * A few utility routines, not to be called other than through 00451 * Append_CallSite() and Append_ReturnSite() are defined: 00452 * 00453 * Var_Loaded_From: 00454 * Get the ST and offset when a variable is loaded (LDID or ILOAD), 00455 * returning a NULL ST when no variable is found to be loaded. 00456 * Var_Stored_In: 00457 * Get the ST and offset when a variable is stored (STID or ISTORE), 00458 * returning a NULL ST when no variable is found to be stored into. 00459 * Does_Stmt_Store_Into_Preg: 00460 * Return the given wn when it stores into a preg with the given 00461 * preg_num. 00462 * Does_Stmt_Store_From_Preg: 00463 * Return the given wn when it stores from a preg with the given 00464 * preg_num. 00465 * New_CallSite: 00466 * Creates a new CALLSITE entry, and appends it to the end of 00467 * the CALLSITE list. 00468 * New_ReturnSite: 00469 * Creates a new RETURNSITE entry, and appends it to the end of 00470 * the RETURNSITE list. 00471 * 00472 * The interface to record CALLSITE and RETURNSITE is as follows: 00473 * 00474 * Append_CallSite: 00475 * Invariably appends a new CALLSITE to our list of CALLSITEs. 00476 * If a pattern match for storing the function-call value to an 00477 * lvalue is found, then we note this in the new CALLSITE. 00478 * 00479 * Append_ReturnSite: 00480 * Appends a new RETURNSITE to our list of RETURNSITEs, 00481 * provided a (possibly empty) sequence of stores from an 00482 * lvalue to the return-registers preceeds an OPR_RETURN 00483 * statement. We should end up with one RETURNSITE per 00484 * OPR_RETURN statement. 00485 * 00486 *---------------------------------------------------------------------*/ 00487 00488 /* Safer tree walking routines than those provided through 00489 * common/com/wn_util.h 00490 */ 00491 #define PUINFO_WN_ITER_wn(iter) \ 00492 (iter != NULL? WN_ITER_wn(iter) : NULL) 00493 #define PUINFO_WN_WALK_TreeNext(iter) \ 00494 (iter != NULL? WN_WALK_TreeNext(iter) : NULL) 00495 #define PUINFO_WN_WALK_StmtNext(iter) \ 00496 (iter != NULL? WN_WALK_StmtNext(iter) : NULL) 00497 00498 static CALLSITE *CallSite_First = NULL; /* First entry in list */ 00499 static CALLSITE *CallSite_Last = NULL; /* Last entry in list */ 00500 static CALLSITE *CallSite_Free = NULL; /* Free list */ 00501 00502 static RETURNSITE *ReturnSite_First = NULL; /* First entry in list */ 00503 static RETURNSITE *ReturnSite_Last = NULL; /* Last entry in list */ 00504 static RETURNSITE *ReturnSite_Free = NULL; /* Free list */ 00505 00506 00507 static void 00508 Var_Loaded_From(const WN *wn, /* in: arbitrary expression */ 00509 const ST **st, /* out: var loaded from (NULL if none) */ 00510 STAB_OFFSET *offset) /* out: offset of var loaded from */ 00511 { 00512 Is_True(wn != NULL, ("wn==NULL in Var_Loaded_From()")); 00513 if (WN_opc_operator(wn) == OPR_LDID) 00514 { 00515 *st = WN_st(wn); 00516 *offset = WN_load_offset(wn); 00517 } 00518 else if (WN_opc_operator(wn) == OPR_ILOAD && 00519 WN_opc_operator(WN_kid0(wn)) == OPR_LDA) 00520 { 00521 *st = WN_st(WN_kid0(wn)); 00522 *offset = WN_load_offset(wn) + WN_lda_offset(WN_kid0(wn)); 00523 } 00524 else 00525 { 00526 *st = NULL; 00527 *offset = -1; 00528 } 00529 } /* Var_Loaded_From */ 00530 00531 00532 static void 00533 Var_Stored_In(const WN *wn, /* in: arbitrary expression */ 00534 const ST **st, /* out: var stored into (NULL if none) */ 00535 STAB_OFFSET *offset) /* out: offset of var stored into */ 00536 { 00537 Is_True(wn != NULL, ("wn==NULL in Var_Stored_In()")); 00538 if (WN_opc_operator(wn) == OPR_STID) 00539 { 00540 *st = WN_st(wn); 00541 *offset = WN_store_offset(wn); 00542 } 00543 else if (WN_opc_operator(wn) == OPR_ISTORE && 00544 WN_opc_operator(WN_kid1(wn)) == OPR_LDA) 00545 { 00546 *st = WN_st(WN_kid1(wn)); 00547 *offset = WN_store_offset(wn) + WN_lda_offset(WN_kid1(wn)); 00548 } 00549 else 00550 { 00551 *st = NULL; 00552 *offset = -1; 00553 } 00554 } /* Var_Stored_In */ 00555 00556 00557 static const WN * 00558 Does_Stmt_Store_From_Preg(const WN *wn, STAB_OFFSET preg_num) 00559 { 00560 if ((WN_opc_operator(wn) == OPR_STID || 00561 WN_opc_operator(wn) == OPR_ISTORE) && 00562 WN_opc_operator(WN_kid0(wn)) == OPR_LDID && 00563 ST_sym_class(WN_st(WN_kid0(wn))) == CLASS_PREG && 00564 WN_load_offset(WN_kid0(wn)) == preg_num) 00565 return wn; 00566 else 00567 return NULL; 00568 } /* Does_Stmt_Store_From_Preg */ 00569 00570 00571 static const WN * 00572 Does_Stmt_Store_Into_Preg(const WN *wn, STAB_OFFSET preg_num) 00573 { 00574 if (WN_opc_operator(wn) == OPR_STID && 00575 ST_sym_class(WN_st(wn)) == CLASS_PREG && 00576 WN_store_offset(wn) == preg_num) 00577 return wn; 00578 else 00579 return NULL; 00580 } /* Does_Stmt_Store_Into_Preg */ 00581 00582 00583 static CALLSITE * 00584 New_CallSite(const WN *call_wn, 00585 TY_IDX return_ty, /* Return type of the called function */ 00586 const WN *store1_wn, /* Store from return register1 (or NULL) */ 00587 const WN *store2_wn, /* Store from return register2 (or NULL) */ 00588 const ST *return_var, /* Returned value is stored in this ST...*/ 00589 STAB_OFFSET var_offset) /* ... at this offset */ 00590 { 00591 CALLSITE *callsite; 00592 00593 if (CallSite_Free != NULL) 00594 { 00595 callsite = CallSite_Free; 00596 CallSite_Free = CALLSITE_next(CallSite_Free); 00597 } 00598 else 00599 { 00600 callsite = TYPE_ALLOC_N(CALLSITE, 1); 00601 } 00602 if (CallSite_Last == NULL) 00603 { 00604 CallSite_Last = callsite; 00605 CallSite_First = callsite; 00606 } 00607 else 00608 { 00609 CALLSITE_next(CallSite_Last) = callsite; 00610 CallSite_Last = callsite; 00611 } 00612 CALLSITE_call(callsite) = call_wn; 00613 CALLSITE_return_ty(callsite) = return_ty; 00614 CALLSITE_store1(callsite) = store1_wn; 00615 CALLSITE_store2(callsite) = store2_wn; 00616 CALLSITE_return_var(callsite) = return_var; 00617 CALLSITE_var_offset(callsite) = var_offset; 00618 CALLSITE_in_regs(callsite) = FALSE; 00619 CALLSITE_next(callsite) = NULL; 00620 00621 return callsite; 00622 } /* New_CallSite */ 00623 00624 00625 static RETURNSITE * 00626 New_ReturnSite(const WN *return_wn, 00627 const WN *store1_wn, /* Store into return register1 (or NULL) */ 00628 const WN *store2_wn, /* Store into return register2 (or NULL) */ 00629 const ST *return_var, /*Return registers loaded from this ST...*/ 00630 STAB_OFFSET var_offset) /* ...at this offset */ 00631 { 00632 RETURNSITE *return_info; 00633 00634 if (ReturnSite_Free != NULL) 00635 { 00636 return_info = ReturnSite_Free; 00637 ReturnSite_Free = RETURNSITE_next(ReturnSite_Free); 00638 } 00639 else 00640 { 00641 return_info = TYPE_ALLOC_N(RETURNSITE, 1); 00642 } 00643 if (ReturnSite_Last == NULL) 00644 { 00645 ReturnSite_Last = return_info; 00646 ReturnSite_First = return_info; 00647 } 00648 else 00649 { 00650 RETURNSITE_next(ReturnSite_Last) = return_info; 00651 ReturnSite_Last = return_info; 00652 } 00653 RETURNSITE_return(return_info) = return_wn; 00654 RETURNSITE_store1(return_info) = store1_wn; 00655 RETURNSITE_store2(return_info) = store2_wn; 00656 RETURNSITE_return_var(return_info) = return_var; 00657 RETURNSITE_var_offset(return_info) = var_offset; 00658 RETURNSITE_next(return_info) = NULL; 00659 00660 return return_info; 00661 } /* New_ReturnSite */ 00662 00663 00664 static WN_ITER * 00665 Append_CallSite(WN_ITER *stmt_iter, const WN *next_stmt) 00666 { 00667 /* The "next_stmt" is initially an OPR_CALL, OPR_ICALL, OPR_PICCALL 00668 * or OPR_INTRINSIC_CALL node, while "wn_iter" is set to point 00669 * to the next statement node in sequence. 00670 */ 00671 TY_IDX return_ty; /* Return type of called function */ 00672 00673 RETURN_PREG return_preg; /* Info about return registers */ 00674 const RETURN_PREG * const return_preg_ptr = &return_preg; 00675 00676 const ST *save_var1 = NULL; /* Var to hold value of call */ 00677 const ST *save_var2; 00678 STAB_OFFSET save_offset1 = 0; /* Offset of value in save_var */ 00679 STAB_OFFSET save_offset2; 00680 const WN *store1 = NULL; /* Storing 1st return register */ 00681 const WN *store2 = NULL; /* Storing 2nd return register */ 00682 00683 const WN * const call_wn = next_stmt; /* The call node */ 00684 00685 /* Get the function return type */ 00686 if (WN_opc_operator(call_wn) == OPR_CALL || 00687 WN_opc_operator(call_wn) == OPR_PICCALL) 00688 { 00689 Is_True(WN_entry_name(call_wn) != 0, 00690 ("Missing WN_entry_name() for %s", 00691 OPCODE_name(WN_opcode(call_wn)))); 00692 return_ty = 00693 W2X_Unparse_Target->Func_Return_Type(ST_pu_type(&St_Table[WN_entry_name(call_wn)])); 00694 } 00695 else if (WN_opc_operator(call_wn) == OPR_ICALL) 00696 { 00697 /* Used to be: 00698 * 00699 * TY_pointed( 00700 * WN_Tree_Type(WN_kid(call_wn, WN_kid_count(call_wn) - 1)))); 00701 */ 00702 return_ty = W2X_Unparse_Target->Func_Return_Type(WN_ty(call_wn)); 00703 } 00704 else 00705 { 00706 Is_True(WN_opc_operator(call_wn) == OPR_INTRINSIC_CALL, 00707 ("Expected OPR_INTRINSIC_CALL node in Append_CallSite()")); 00708 00709 return_ty = WN_intrinsic_return_ty(WN_opcode(call_wn), 00710 (INTRINSIC)WN_intrinsic(call_wn), 00711 call_wn); 00712 } 00713 00714 /* Determine how the return value is distributed between return 00715 * registers to hold the value of the function call. 00716 */ 00717 return_preg = PUinfo_Get_ReturnPreg(return_ty); 00718 00719 /* Update next_stmt to denote the statement following the call_wn */ 00720 next_stmt = PUINFO_WN_ITER_wn(stmt_iter); 00721 00722 /* If the return info makes sense, update the CallSite information */ 00723 if (RETURN_PREG_num_pregs(return_preg_ptr) > 0 && next_stmt != NULL) 00724 { 00725 /* Check if the first return register is stored off in the next_stmt */ 00726 store1 = 00727 Does_Stmt_Store_From_Preg(next_stmt, 00728 RETURN_PREG_offset(return_preg_ptr, 0)); 00729 00730 /* If the return-value is composed of two return-registers, then 00731 * see if both return registers are stored into a temporary variable. 00732 */ 00733 if (store1 != NULL) 00734 { 00735 /* Check if the first return register is stored off into a variable */ 00736 Var_Stored_In(next_stmt, &save_var1, &save_offset1); 00737 00738 /* Get the statement following the first store. This is alright, 00739 * since even if we end up having to generate code for the first 00740 * store, we do not record usage of pregs in this traversal, nor 00741 * any other info about store stmts. 00742 */ 00743 stmt_iter = PUINFO_WN_WALK_StmtNext(stmt_iter); /* next statement */ 00744 next_stmt = PUINFO_WN_ITER_wn(stmt_iter); 00745 00746 /* We only eliminate references to two return registers when both 00747 * return registers are stored into the same variable. 00748 */ 00749 if (RETURN_PREG_num_pregs(return_preg_ptr) > 1 && 00750 next_stmt != NULL && 00751 save_var1 != NULL && 00752 ST_sym_class(save_var1) != CLASS_PREG) 00753 { 00754 store2 = 00755 Does_Stmt_Store_From_Preg(next_stmt, 00756 RETURN_PREG_offset(return_preg_ptr, 00757 1 /* 2nd preg */)); 00758 00759 if (store2 != NULL) 00760 { 00761 Var_Stored_In(next_stmt, &save_var2, &save_offset2); 00762 if (save_var1 == save_var2 && save_offset1 < save_offset2) 00763 stmt_iter = PUINFO_WN_WALK_StmtNext(stmt_iter); /* move on */ 00764 else /* No second store that matches our pattern */ 00765 { 00766 store1 = store2 = NULL; 00767 save_var1 = NULL; 00768 } 00769 } 00770 else 00771 { 00772 save_var1 = NULL; 00773 store1 = NULL; 00774 } /* Second store matches our pattern */ 00775 } 00776 else if (RETURN_PREG_num_pregs(return_preg_ptr) > 1) 00777 { 00778 /* We do not care about the first store if we are missing a 00779 * second store. 00780 */ 00781 save_var1 = NULL; 00782 store1 = NULL; 00783 } /* A second store is expected */ 00784 } /* First store matches our pattern */ 00785 } /* A first store is expected */ 00786 00787 (void)New_CallSite(call_wn, return_ty, store1, store2, 00788 save_var1, save_offset1); 00789 00790 return stmt_iter; 00791 } /* Append_CallSite */ 00792 00793 00794 static WN_ITER * 00795 Append_ReturnSite(WN_ITER *stmt_iter, const WN *first_stmt) 00796 { 00797 /* The "next_stmt" is an OPR_RETURN, or an OPR_STID node; "stmt_iter" 00798 * points to the next statement node in sequence. 00799 */ 00800 const WN *stmt = first_stmt; /* Current statement */ 00801 const ST *load_var1 = NULL; /* Variable to holding return value */ 00802 const ST *load_var2; 00803 STAB_OFFSET load_offset1 = 0; /* Offset of value in load_var */ 00804 STAB_OFFSET load_offset2; 00805 00806 const WN *store1 = NULL; /* Storing first return register */ 00807 const WN *store2 = NULL; /* Storing second return register */ 00808 00809 /* If the return info makes sense, update the ReturnSite information 00810 * accordingly. 00811 */ 00812 if (RETURN_PREG_num_pregs(PUinfo_return_preg) > 0 && 00813 WN_opc_operator(stmt) == OPR_STID) 00814 { 00815 /* Check if the first return register is set in the next_stmt */ 00816 store1 = 00817 Does_Stmt_Store_Into_Preg(stmt, 00818 RETURN_PREG_offset(PUinfo_return_preg, 0)); 00819 00820 /* If the return-value is composed of two return-registers, then 00821 * see if both return registers are set from the same variable base. 00822 */ 00823 if (store1 != NULL) 00824 { 00825 /* Check if the first return register is set from a variable 00826 * base. 00827 */ 00828 Var_Loaded_From(WN_kid0(stmt), &load_var1, &load_offset1); 00829 00830 /* Update next_stmt to denote the stmt following the first store */ 00831 stmt = PUINFO_WN_ITER_wn(stmt_iter); 00832 00833 /* We only eliminate references to two return registers when both 00834 * return registers are loaded from the same variable. 00835 */ 00836 if (RETURN_PREG_num_pregs(PUinfo_return_preg) > 1 && 00837 stmt != NULL && 00838 WN_opc_operator(stmt) == OPR_STID && 00839 load_var1 != NULL && 00840 ST_sym_class(load_var1) != CLASS_PREG) 00841 { 00842 store2 = 00843 Does_Stmt_Store_Into_Preg(stmt, 00844 RETURN_PREG_offset(PUinfo_return_preg, 00845 1 /* 2nd preg */)); 00846 if (store2 != NULL) 00847 { 00848 Var_Loaded_From(WN_kid0(stmt), &load_var2, &load_offset2); 00849 if (load_var1 == load_var2 && load_offset1 < load_offset2) 00850 { 00851 stmt_iter = PUINFO_WN_WALK_StmtNext(stmt_iter); /* move on */ 00852 stmt = PUINFO_WN_ITER_wn(stmt_iter); 00853 } 00854 else /* No second store that matches our pattern */ 00855 { 00856 store1 = store2 = NULL; 00857 load_var1 = NULL; 00858 stmt = first_stmt; 00859 } 00860 } 00861 else 00862 { 00863 store1 = NULL; 00864 load_var1 = NULL; 00865 stmt = first_stmt; 00866 } /* Second store matches our pattern */ 00867 } 00868 else if (RETURN_PREG_num_pregs(PUinfo_return_preg) > 1) 00869 { 00870 /* We do not care about the first store if we are missing a 00871 * second store. 00872 */ 00873 store1 = NULL; 00874 load_var1 = NULL; 00875 stmt = first_stmt; 00876 } /* A second store is expected */ 00877 } /* First store matches our pattern */ 00878 } /* Need a first store */ 00879 00880 /* See if we have a return as the next statement */ 00881 if (stmt != NULL && WN_opc_operator(stmt) == OPR_RETURN) 00882 { 00883 (void)New_ReturnSite(stmt, store1, store2, load_var1, load_offset1); 00884 00885 if (stmt != first_stmt) 00886 stmt_iter = PUINFO_WN_WALK_StmtNext(stmt_iter); 00887 } 00888 00889 return stmt_iter; 00890 } /* Append_ReturnSite */ 00891 00892 00893 /*------- Prepass phases over WN tree to record information -----------*/ 00894 /*---------------------------------------------------------------------*/ 00895 00896 static void 00897 Accumulate_Stmt_PUinfo(WN *wn) 00898 { 00899 /* This is a preorder prepass over all the statements rooted at wn, 00900 * before we actually begin the translation to C. We accumulate 00901 * information about function calls and return statements. 00902 */ 00903 WN_ITER *stmt_iter = WN_WALK_StmtIter(wn); 00904 const WN *parent; 00905 const WN *gparent; 00906 00907 /* Iterate over all statements */ 00908 while (stmt_iter != NULL) 00909 { 00910 const WN *stmt = PUINFO_WN_ITER_wn(stmt_iter); 00911 00912 if (stmt != NULL) 00913 { 00914 switch(WN_opc_operator(stmt)) 00915 { 00916 case OPR_CALL: 00917 case OPR_ICALL: 00918 case OPR_PICCALL: 00919 case OPR_INTRINSIC_CALL: 00920 /* Ignore C++ calls in WN_region_pragmas(). This iterator will 00921 * currently ignore calls in IO_ITEMs, but we check explicitly 00922 * anyway to safeguard against future changes in the iterator 00923 * definition. 00924 */ 00925 parent = W2CF_Get_Parent(stmt); 00926 gparent = W2CF_Get_Parent(parent); 00927 if (!WN_in_ioitem(stmt) && 00928 (WN_opc_operator(gparent) != OPR_REGION || 00929 WN_region_pragmas(gparent) != parent)) 00930 { 00931 /* Note that here we will skip the call node and any 00932 * sequence of stores that fits the form expected for a 00933 * call statement. 00934 */ 00935 stmt_iter = 00936 Append_CallSite(PUINFO_WN_WALK_StmtNext(stmt_iter), stmt); 00937 } 00938 else 00939 stmt_iter = PUINFO_WN_WALK_StmtNext(stmt_iter); 00940 break; 00941 00942 case OPR_STID: 00943 /* Note that here we will skip any sequence of stores that 00944 * fits the form expected for a return statement, including 00945 * the OPR_RETURN we expect to immediately follow the stores. 00946 */ 00947 stmt_iter = 00948 Append_ReturnSite(PUINFO_WN_WALK_StmtNext(stmt_iter), stmt); 00949 break; 00950 00951 case OPR_RETURN: 00952 /* A return statement without the expected sequence of 00953 * preceeding store operations. 00954 */ 00955 stmt_iter = 00956 Append_ReturnSite(PUINFO_WN_WALK_StmtNext(stmt_iter), stmt); 00957 break; 00958 00959 default: 00960 stmt_iter = PUINFO_WN_WALK_StmtNext(stmt_iter); 00961 break; 00962 } 00963 } 00964 } /* while */ 00965 } /* Accumulate_Stmt_PUinfo */ 00966 00967 00968 static void 00969 Accumulate_Expr_PUinfo(WN *root) 00970 { 00971 /* This is a preorder prepass over all the nodes rooted at the wn, 00972 * including statements and expressions. We accumulate information 00973 * about return-register and other preg uses. NOTE: we expect this 00974 * to be done after having done Accumulate_Stmt_Info(wn)! 00975 */ 00976 WN_ITER *wn_iter; 00977 const WN *wn; 00978 const WN *parent; 00979 const WN *gparent; 00980 const WN *next_return_ldid = NULL; 00981 CALLSITE *last_callsite = NULL; 00982 00983 /* Walk the entire tree to get expression-level information */ 00984 for (wn_iter = WN_WALK_TreeIter(root); 00985 wn_iter != NULL; 00986 wn_iter = PUINFO_WN_WALK_TreeNext(wn_iter)) 00987 { 00988 /* Record preg usage; even record uses that will be eliminated by 00989 * simplification of call-/return-sites. Also, note any unexpected 00990 * uses of return-registers (only LDID uses, not STID uses) for 00991 * every call-site. 00992 */ 00993 wn = PUINFO_WN_ITER_wn(wn_iter); 00994 if (wn != NULL) 00995 switch(WN_opc_operator(wn)) 00996 { 00997 case OPR_STID: 00998 if (ST_sym_class(WN_st(wn)) == CLASS_PREG) 00999 Accumulate_Preg_Info(ST_type(WN_st(wn)), WN_store_offset(wn)); 01000 01001 /* Fall through to the OPR_ISTORE case, where we indicate 01002 * which LDID node is next expected to load a return-register, 01003 * based on the information we have retrieved about the last 01004 * OPR_CALL statement ... 01005 */ 01006 01007 case OPR_ISTORE: 01008 if (last_callsite != NULL && 01009 (CALLSITE_store1(last_callsite) == wn || 01010 CALLSITE_store2(last_callsite) == wn)) 01011 { 01012 /* Next expected ldid of a return register is WN_kid0(tree) */ 01013 Is_True(WN_operator(WN_kid0(wn)) == OPR_LDID && 01014 IS_RETURN_PREG(WN_kid0(wn)), 01015 ("Unexpected CALLSITE in Accumulate_Expr_PUinfo()")); 01016 01017 next_return_ldid = WN_kid0(wn); 01018 } 01019 break; 01020 01021 case OPR_LDID: 01022 if (ST_sym_class(WN_st(wn)) == CLASS_PREG) 01023 { 01024 Accumulate_Preg_Info(ST_type(WN_st(wn)), WN_load_offset(wn)); 01025 01026 /* If we encounter an unexpected load of a return 01027 * register, then update the CALLSITE to indicate that 01028 * the return-registers must be written for the call. 01029 */ 01030 01031 if (next_return_ldid == wn) 01032 next_return_ldid = NULL; 01033 else if (last_callsite != NULL && IS_RETURN_PREG(wn)) 01034 CALLSITE_in_regs(last_callsite) = TRUE; 01035 } 01036 break; 01037 01038 case OPR_LDA: 01039 /* Make certain this never occurs for pregs! */ 01040 Is_True(ST_sym_class(WN_st(wn)) != CLASS_PREG, 01041 ("Attempt to LDA a PREG in Accumulate_Expr_PUinfo()")); 01042 break; 01043 01044 case OPR_CALL: 01045 case OPR_ICALL: 01046 case OPR_PICCALL: 01047 case OPR_INTRINSIC_CALL: 01048 /* Ignore C++ calls in WN_region_pragmas() and calls in IO items. 01049 */ 01050 parent = W2CF_Get_Parent(wn); 01051 gparent = W2CF_Get_Parent(parent); 01052 if (!WN_in_ioitem(wn) && 01053 (WN_opc_operator(gparent) != OPR_REGION || 01054 WN_region_pragmas(gparent) != parent)) 01055 { 01056 /* Note that we need not accumulate information about return 01057 * pregs here, since such information will be appropriately 01058 * accumulated when we encounter such references in LDID or 01059 * STID nodes. 01060 */ 01061 if (last_callsite == NULL) 01062 last_callsite = PUinfo_Get_CallSites(); 01063 else 01064 last_callsite = CALLSITE_next(last_callsite); 01065 01066 Is_True(CALLSITE_call(last_callsite) == wn, 01067 ("Unexpected callsite order in Accumulate_Expr_PUinfo()")); 01068 } 01069 break; 01070 01071 case OPR_RETURN: 01072 /* Make certain the appropriate return-registers are defined, 01073 * since it may be that a function returns an undefined value 01074 * and no explicit references to the return register occurs in 01075 * the WHIRL representation. 01076 */ 01077 if (RETURN_PREG_num_pregs(PUinfo_return_preg) > 0) 01078 { 01079 TY_IDX preg_ty; 01080 STAB_OFFSET preg_offset; 01081 01082 preg_offset = RETURN_PREG_offset(PUinfo_return_preg, 0); 01083 preg_ty = 01084 Stab_Mtype_To_Ty(RETURN_PREG_mtype(PUinfo_return_preg, 0)); 01085 Accumulate_Preg_Info(preg_ty, preg_offset); 01086 if (RETURN_PREG_num_pregs(PUinfo_return_preg) > 1) 01087 { 01088 preg_offset = RETURN_PREG_offset(PUinfo_return_preg, 1); 01089 preg_ty = 01090 Stab_Mtype_To_Ty(RETURN_PREG_mtype(PUinfo_return_preg, 1)); 01091 Accumulate_Preg_Info(preg_ty, preg_offset); 01092 } 01093 } 01094 break; 01095 01096 default: 01097 break; 01098 } /* switch on node OPR */ 01099 } /* for each node */ 01100 } /* Accumulate_Expr_PUinfo */ 01101 01102 01103 /*------------------------ exported routines --------------------------*/ 01104 /*---------------------------------------------------------------------*/ 01105 01106 void 01107 PUinfo_initialize(void) 01108 { 01109 Is_True(PUinfo_local_decls == NULL && 01110 PUinfo_current_func == NULL && 01111 PUinfo_return_preg == NULL, 01112 ("Unexpected state in PUinfo_init()")); 01113 01114 } /* PUinfo_initialize */ 01115 01116 01117 void 01118 PUinfo_finalize(void) 01119 { 01120 /* Free up all memory */ 01121 CALLSITE *callsite; 01122 RETURNSITE *returnsite; 01123 01124 /* Free up the entries in the CallSite_Free list */ 01125 while (CallSite_Free != NULL) 01126 { 01127 callsite = CallSite_Free; 01128 CallSite_Free = CALLSITE_next(callsite); 01129 FREE(callsite); 01130 } 01131 01132 /* Free up the entries in the ReturnSite_Free list */ 01133 while (ReturnSite_Free != NULL) 01134 { 01135 returnsite = ReturnSite_Free; 01136 ReturnSite_Free = CALLSITE_next(returnsite); 01137 FREE(returnsite); 01138 } 01139 } /* PUinfo_finalize */ 01140 01141 01142 void 01143 PUinfo_init_pu(const WN *pu, WN *body_part_of_interest) 01144 { 01145 /* TODO: Handle nested procedures and call/return list stacks. 01146 * NOTE: This should never cause side-effects to the incoming 01147 * PU (e.g. creating a pointer type), without making 01148 * sure this is handled by W2C_Pop_Pu() in w2c_driver.c 01149 * and W2F_Pop_Pu() in w2f_driver.c.xc 01150 */ 01151 static RETURN_PREG preg_info; 01152 01153 Is_True(WN_operator(pu) == OPR_FUNC_ENTRY, 01154 ("Expected an OPR_FUNC_ENTRY node in PUinfo_init()")); 01155 01156 /* Set the PU state: MUST BE DONE BEFORE ANYTHING ELSE! */ 01157 Is_True(PUinfo_local_decls == NULL && 01158 PUinfo_pragmas == NULL && 01159 PUinfo_current_func == NULL && 01160 PUinfo_return_preg == NULL, 01161 ("Unexpected state in PUinfo_init_pu()")); 01162 01163 PUinfo_current_func = pu; /* PUINFO_RETURN_TY uses this! */ 01164 preg_info = PUinfo_Get_ReturnPreg(PUINFO_RETURN_TY); 01165 PUinfo_return_preg = &preg_info; 01166 PUinfo_local_decls = New_Token_Buffer(); 01167 PUinfo_pragmas = New_Token_Buffer(); 01168 01169 /* Traverse the statements in the current PU, accumulating 01170 * information about every function call-site and every function 01171 * return-site. 01172 */ 01173 if (!OPCODE_is_expression(WN_opcode(body_part_of_interest))) 01174 Accumulate_Stmt_PUinfo(body_part_of_interest); 01175 01176 /* Traverse the statements and expressions in the current PU, 01177 * accumulating information about pseudo register usage and 01178 * refining the information about call-sites to account for 01179 * unexpected uses of return-registers. 01180 */ 01181 Accumulate_Expr_PUinfo(body_part_of_interest); 01182 01183 /* Push a new symbol-table for name-disambiguation, and enter 01184 * every pseudo-register, variable, function, constant, and type 01185 * of this PU scope into the symbol-table. The former 01186 * accumulative prepass over the expression trees should have 01187 * determined all preg uses. 01188 */ 01189 W2CF_Symtab_Push(); 01190 Enter_Local_Syms_Into_Symtab(&St_Table[WN_entry_name(pu)]); 01191 Enter_Pregs_Into_Symtab(); 01192 01193 } /* PUinfo_init_pu */ 01194 01195 01196 void 01197 PUinfo_exit_pu(void) 01198 { 01199 /* Free up memory and reset the state to prepare for processing the 01200 * next PU. 01201 */ 01202 UINT32 hash_idx; 01203 CALLSITE *callsite; 01204 RETURNSITE *returnsite; 01205 01206 /* Pop the current symbol-table for name-disambiguation */ 01207 W2CF_Symtab_Pop(); 01208 01209 /* Free up the entries in the Preg_Info_Tbl and reset the table */ 01210 for (hash_idx = 0; hash_idx < PREG_INFO_HASH_TABLE_SIZE; hash_idx++) 01211 { 01212 PREG_INFO *preg_info = Preg_Info_Hash_Tbl[hash_idx]; 01213 if (preg_info != NULL) 01214 { 01215 while (PREG_INFO_next(preg_info) != NULL) 01216 preg_info = PREG_INFO_next(preg_info); 01217 PREG_INFO_next(preg_info) = Free_Preg_Info; 01218 Free_Preg_Info = Preg_Info_Hash_Tbl[hash_idx]; 01219 Preg_Info_Hash_Tbl[hash_idx] = NULL; 01220 } 01221 } /* for */ 01222 01223 /* Free up the entries in the CallSite list */ 01224 for (callsite = CallSite_First; 01225 callsite != NULL; 01226 callsite = CALLSITE_next(callsite)) 01227 { 01228 CALLSITE_next(callsite) = CallSite_Free; 01229 CallSite_Free = callsite; 01230 } 01231 CallSite_First = NULL; 01232 CallSite_Last = NULL; 01233 01234 /* Free up the entries in the ReturnSite list */ 01235 for (returnsite = ReturnSite_First; 01236 returnsite != NULL; 01237 returnsite = RETURNSITE_next(returnsite)) 01238 { 01239 RETURNSITE_next(returnsite) = ReturnSite_Free; 01240 ReturnSite_Free = returnsite; 01241 } 01242 ReturnSite_First = NULL; 01243 ReturnSite_Last = NULL; 01244 01245 /* Reset the PU state */ 01246 PUinfo_current_func = NULL; 01247 PUinfo_return_preg = NULL; 01248 if (PUinfo_local_decls != NULL) 01249 Reclaim_Token_Buffer(&PUinfo_local_decls); 01250 if (PUinfo_pragmas != NULL) 01251 Reclaim_Token_Buffer(&PUinfo_pragmas); 01252 01253 } /* PUinfo_exit_pu */ 01254 01255 01256 TY_IDX 01257 PUinfo_Preg_Type(TY_IDX preg_ty, INT16 preg_num) 01258 { 01259 /* Return the TY_IDX which should be used to refer to and to declare 01260 * a variable for the given preg number. The ty argument is the 01261 * type with which the preg is referenced in WHIRL, which is not 01262 * necessarily the same type we wish to refer to the preg in the 01263 * high-level language to which we translate (C or Fortran). 01264 */ 01265 TY_IDX ty; 01266 PREG_INFO *preg_info; 01267 INT usage_kind, this_ukind; 01268 01269 /* Preg types other than integral types can be referred to and used 01270 * as they are. Integral preg types may be "larger" than in WHIRL. 01271 */ 01272 if (!TY_Is_Integral(preg_ty)) 01273 ty = preg_ty; 01274 else 01275 { 01276 preg_info = Get_Preg_Info(preg_num); 01277 if (preg_info == NULL) 01278 { 01279 Accumulate_Preg_Info(preg_ty, preg_num); /* Just to make sure */ 01280 preg_info = Get_Preg_Info(preg_num); 01281 } 01282 01283 this_ukind = (INT)Mtype_to_Ukind(TY_mtype(preg_ty)); 01284 for (usage_kind = (INT)LARGEST_iPREG_USAGE_KIND; 01285 (usage_kind >= this_ukind && 01286 !PREG_INFO_use(preg_info, usage_kind)); 01287 usage_kind--); 01288 ty = Stab_Mtype_To_Ty(Ukind_to_Mtype[usage_kind]); 01289 } 01290 return ty; 01291 } /* PUinfo_Preg_Type */ 01292 01293 01294 BOOL 01295 PUinfo_Is_Preg_Declared(TY_IDX preg_ty, INT16 preg_num) 01296 { 01297 if (preg_ty == 0 || preg_num == -1) 01298 return TRUE; 01299 01300 PREG_INFO *preg_info = Get_Preg_Info(preg_num); 01301 01302 if (preg_info == NULL) 01303 { 01304 Accumulate_Preg_Info(preg_ty, preg_num); /* Just to make sure */ 01305 preg_info = Get_Preg_Info(preg_num); 01306 } 01307 01308 return PREG_INFO_decl(preg_info, Mtype_to_Ukind(TY_mtype(preg_ty))); 01309 } /* PUinfo_Is_Preg_Declared */ 01310 01311 01312 void 01313 PUinfo_Set_Preg_Declared(TY_IDX preg_ty, INT16 preg_num) 01314 { 01315 PREG_INFO *preg_info = Get_Preg_Info(preg_num); 01316 01317 if (preg_info == NULL) 01318 { 01319 Accumulate_Preg_Info(preg_ty, preg_num); /* Just to make sure */ 01320 preg_info = Get_Preg_Info(preg_num); 01321 } 01322 01323 PREG_INFO_decl(preg_info, Mtype_to_Ukind(TY_mtype(preg_ty))) = TRUE; 01324 } /* PUinfo_Set_Preg_Declared */ 01325 01326 01327 CALLSITE * 01328 PUinfo_Get_CallSites(void) 01329 { 01330 return CallSite_First; 01331 } /* PUinfo_Get_CallSites */ 01332 01333 01334 RETURNSITE * 01335 PUinfo_Get_ReturnSites(void) 01336 { 01337 return ReturnSite_First; 01338 } /* PUinfo_Get_ReturnSites */ 01339 01340 01341 RETURN_PREG 01342 PUinfo_Get_ReturnPreg(TY_IDX return_ty) 01343 { 01344 /* Use the generic routines from "targ_sim.h" to get information 01345 * about how a return-type is split up between return registers. 01346 */ 01347 RETURN_PREG return_preg; 01348 RETURN_PREG * const return_preg_ptr = &return_preg; 01349 PREG_NUM preg_num1, preg_num2; 01350 01351 if (WHIRL_Return_Info_On ) { 01352 01353 RETURN_INFO return_info = Get_Return_Info (return_ty, 01354 Use_Simulated); 01355 01356 if (RETURN_INFO_count(return_info) <= 2) { 01357 01358 RETURN_PREG_mtype(return_preg_ptr, 0) = RETURN_INFO_mtype (return_info, 0); 01359 RETURN_PREG_mtype(return_preg_ptr, 1) = RETURN_INFO_mtype (return_info, 1); 01360 preg_num1 = RETURN_INFO_preg (return_info, 0); 01361 preg_num2 = RETURN_INFO_preg (return_info, 1); 01362 } 01363 01364 else { 01365 Fail_FmtAssertion ("PUinfo_Get_ReturnPreg: more than 2 return registers"); 01366 } 01367 } 01368 else { 01369 /* Get the mtypes of the return registers */ 01370 Get_Return_Mtypes(return_ty, /* in */ 01371 Use_Simulated, /* in */ 01372 &RETURN_PREG_mtype(return_preg_ptr, 0), /* out */ 01373 &RETURN_PREG_mtype(return_preg_ptr, 1)); /* out */ 01374 01375 /* Get the PREG_NUM of the return registers */ 01376 Get_Return_Pregs(RETURN_PREG_mtype(return_preg_ptr, 0), /* in */ 01377 RETURN_PREG_mtype(return_preg_ptr, 1), /* in */ 01378 &preg_num1, /* out */ 01379 &preg_num2); /* out */ 01380 } 01381 RETURN_PREG_offset(return_preg_ptr, 0) = preg_num1; 01382 RETURN_PREG_offset(return_preg_ptr, 1) = preg_num2; 01383 01384 if (RETURN_PREG_mtype(return_preg_ptr, 0) == MTYPE_V) 01385 RETURN_PREG_num_pregs(return_preg_ptr) = 0; 01386 else if (RETURN_PREG_mtype(return_preg_ptr, 1) == MTYPE_V) 01387 RETURN_PREG_num_pregs(return_preg_ptr) = 1; 01388 else 01389 RETURN_PREG_num_pregs(return_preg_ptr) = 2; 01390 01391 return return_preg; 01392 } /* PUinfo_Get_ReturnPreg */ 01393 01394