Open64 (mfef90, whirl2f, and IR tools)  TAG: version-openad; SVN changeset: 916
PUinfo.cxx
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines