Open64 (mfef90, whirl2f, and IR tools)  TAG: version-openad; SVN changeset: 916
wn2c.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  *   Translate a WN subtree to C by means of an inorder recursive
00046  *   descent traversal of the WHIRL IR.
00047  *
00048  *   Handle declarations, variable references, type-casts, and
00049  *   constants by using st2c.h, ty2c.h, and tcon2c.h respectively.
00050  *
00051  * ====================================================================
00052  * ====================================================================
00053  */
00054 
00055 #ifdef _KEEP_RCS_ID
00056 #endif /* _KEEP_RCS_ID */
00057 
00058 
00059 #include <alloca.h>
00060 #include "whirl2c_common.h"
00061 #include "mempool.h"
00062 #include "const.h"
00063 #include "pf_cg.h"
00064 #include "region_util.h"
00065 #include "w2cf_parentize.h"
00066 #include "PUinfo.h"
00067 #include "wn2c.h"
00068 #include "wn2c_pragma.h"
00069 #include "st2c.h"
00070 #include "ty2c.h"
00071 #include "tcon2c.h"
00072 #include "wn2c_pragma.h"
00073 #include "unparse_target.h"
00074 
00075 #if defined(__GNUC__) && (__GNUC__ == 3) 
00076 # define USING_HASH_SET 1
00077 # include <ext/hash_set>
00078   using namespace __gnu_cxx;
00079 #elif defined(__sgi) && !defined(__GNUC__)
00080 # define USING_HASH_SET 1
00081 # include <hash_set>
00082 #else
00083 # include <set>
00084 #endif
00085 
00086 #define WN_pragma_nest(wn) WN_pragma_arg1(wn)
00087 
00088 /*-------------------- Some general purpose macros --------------------*/
00089 /*---------------------------------------------------------------------*/
00090 
00091 
00092 /* This determines whether or not we need an explicit cast to convert
00093  * a value of type t1 to a value of type t2.
00094  */
00095 #define WN2C_assignment_compatible_types(lhs_ty, rhs_ty) \
00096    Stab_Assignment_Compatible_Types(lhs_ty, rhs_ty, \
00097                                     FALSE, /*check_quals*/ \
00098                                     FALSE, /*check_scalars*/ \
00099                                     FALSE) /*ptrs_as_scalars*/
00100 
00101 #define WN2C_compatible_lvalues(lhs_ty, rhs_ty) \
00102    Stab_Assignment_Compatible_Types(lhs_ty, rhs_ty, \
00103                                     FALSE, /*check_quals*/ \
00104                                     TRUE,  /*check_scalars*/ \
00105                                     FALSE) /*ptrs_as_scalars*/
00106 
00107 #define WN2C_arithmetic_compatible_types(t1, t2) \
00108    Stab_Identical_Types(t1, t2, \
00109                         FALSE, /*check_quals*/ \
00110                         TRUE,  /*check_scalars*/ \
00111                         FALSE) /*ptrs_as_scalars*/
00112 
00113 #define WN2C_compatible_qualified_types(t1, t2) \
00114    Stab_Identical_Types(t1, t2, \
00115                         TRUE,  /*check_quals*/ \
00116                         TRUE,  /*check_scalars*/ \
00117                         FALSE) /*ptrs_as_scalars*/
00118 
00119 #define WN2C_array_lvalue_as_ptr(ptr_to_array, ptr) \
00120    (TY_Is_Pointer(ptr)                    && \
00121     TY_Is_Pointer(ptr_to_array)           && \
00122     TY_Is_Array(TY_pointed(ptr_to_array)) && \
00123     WN2C_arithmetic_compatible_types(TY_AR_etype(TY_pointed(ptr_to_array)), \
00124                                      TY_pointed(ptr)))
00125 
00126 static BOOL
00127 WN2C_is_pointer_diff(OPCODE op, const WN *kid0, const WN *kid1)
00128 {
00129    TY_IDX ty0, ty1;
00130    BOOL  is_pointer_diff = FALSE;
00131 
00132    if (OPCODE_operator(op) == OPR_ASHR  &&
00133        WN_operator(kid0) == OPR_SUB &&
00134        WN_operator(kid1) == OPR_INTCONST)
00135    {
00136       ty0 = WN_Tree_Type(WN_kid0(kid0));
00137       ty1 = WN_Tree_Type(WN_kid1(kid0));
00138 
00139       if (TY_Is_Pointer(ty0) && TY_Is_Pointer(ty1) &&
00140           TY_size(TY_pointed(ty0)) == TY_size(TY_pointed(ty1)) &&
00141           TY_size(TY_pointed(ty0)) >> WN_const_val(kid1) == 1)
00142          is_pointer_diff = TRUE;
00143    }
00144    return is_pointer_diff;
00145 } /* WN2C_is_pointer_diff */
00146 
00147 
00148 /*---------------- General Purpose static variables -------------------*/
00149 /*---------------------------------------------------------------------*/
00150 
00151 /* The name of a temporary automatic variable used to hold function
00152  * return values.
00153  */
00154 static const char WN2C_Purple_Region_Name[] = "prp___region";
00155 static const char WN2C_Return_Value_Name[] = "_RetVal";
00156 static BOOL       WN2C_Used_Return_Value = FALSE;
00157 
00158 
00159 /*------------- Information about call/return sites -------------------*/
00160 /*---------------------------------------------------------------------*/
00161 
00162 /* Lists of return and call sites for the current PU,
00163  * initialized by means of "PUinfo.h" facilities.
00164  */
00165 static const RETURNSITE *WN2C_Next_ReturnSite = NULL;
00166 static const CALLSITE   *WN2C_Prev_CallSite = NULL;
00167 
00168 typedef struct SCALAR_C_NAME
00169 {
00170    const char *real_name;
00171    const char *pseudo_name;
00172 } SCALAR_C_NAME;
00173 
00174 
00175 /* This name is used to wrap a union around a block containing
00176  * equivalence fields.  Should only occur when translating
00177  * Fortran to C.
00178  */
00179 const char TY2C_Aligned_Block_Name[] = "__block";
00180 
00181 #define MTYPE_PREDEF MTYPE_F16
00182 
00183 static char Name_Unknown_Type[] = "__UNKNOWN_TYPE";
00184 static const SCALAR_C_NAME Scalar_C_Names[MTYPE_PREDEF+1] =
00185    {{"void",               Name_Unknown_Type},  /* MTYPE_UNKNOWN 0 */
00186     {"char",               "_BOOLEAN"},         /* MTYPE_B = 1 */
00187     {"signed char",        "_INT8"},            /* MTYPE_I1 = 2 */
00188     {"signed short",       "_INT16"},           /* MTYPE_I2 = 3 */
00189     {"signed int",         "_INT32"},           /* MTYPE_I4 = 4 */
00190     {"signed long long",   "_INT64"},           /* MTYPE_I8 = 5 */
00191     {"unsigned char",      "_UINT8"},           /* MTYPE_U1 = 6 */
00192     {"unsigned short",     "_UINT16"},          /* MTYPE_U2 = 7 */
00193     {"unsigned int",       "_UINT32"},          /* MTYPE_U4 = 8 */
00194     {"unsigned long long", "_UINT64"},          /* MTYPE_U8 = 9 */
00195     {"float",              "_IEEE32"},          /* MTYPE_F4 = 10 */
00196     {"double",             "_IEEE64"},          /* MTYPE_F8 = 11 */
00197     {Name_Unknown_Type,    "_IEEE80"},          /* MTYPE_F10 = 12 */
00198     {Name_Unknown_Type,    "_IEEE128"}  /* MTYPE_F16 = 13 = MTYPE_PREDEF */
00199    }; /* Scalar_C_Names */
00200 
00201 
00202 static BOOL 
00203 WN2C_Skip_Stmt(const WN *stmt)
00204 {
00205    return ((W2C_No_Pragmas && \
00206             (WN_operator(stmt) == OPR_PRAGMA || 
00207              WN_operator(stmt) == OPR_XPRAGMA) &&
00208             WN_pragma(stmt) != WN_PRAGMA_PREAMBLE_END) || /* For purple */\
00209 
00210            WN2C_Skip_Pragma_Stmt(stmt) ||
00211 
00212            (!W2C_Emit_Prefetch &&
00213             (WN_operator(stmt) == OPR_PREFETCH ||
00214              WN_operator(stmt) == OPR_PREFETCHX)) ||
00215 
00216            (WN2C_Next_ReturnSite != NULL &&
00217             (stmt == RETURNSITE_store1(WN2C_Next_ReturnSite) ||
00218              stmt == RETURNSITE_store2(WN2C_Next_ReturnSite))) ||
00219 
00220            (WN2C_Prev_CallSite != NULL &&
00221             (stmt == CALLSITE_store1(WN2C_Prev_CallSite) ||
00222              stmt == CALLSITE_store2(WN2C_Prev_CallSite))) ||
00223 
00224            (WN_operator(stmt) == OPR_COMMENT && /* special comment */
00225             strcmp(Index_To_Str(WN_GetComment(stmt)), "ENDLOOP") == 0)
00226            );
00227 } /* WN2C_Skip_Stmt */
00228 
00229 
00230 /*-------------------- Function handle for each OPR -------------------*/
00231 /*---------------------------------------------------------------------*/
00232 
00233 /* Forward declaration of functions to translate WHIRL to C.
00234 */
00235 static STATUS WN2C_ignore(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00236 static STATUS WN2C_unsupported(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00237 static STATUS WN2C_binaryop(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00238 static STATUS WN2C_unaryop(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00239 static STATUS WN2C_func_entry(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00240 static STATUS WN2C_block(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00241 static STATUS WN2C_region(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00242 static STATUS WN2C_switch(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00243 static STATUS WN2C_compgoto(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00244 static STATUS WN2C_do_loop(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00245 static STATUS WN2C_do_while(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00246 static STATUS WN2C_while_do(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00247 static STATUS WN2C_if(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00248 static STATUS WN2C_goto(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00249 static STATUS WN2C_condbr(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00250 static STATUS WN2C_return(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00251 static STATUS WN2C_return_val(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00252 static STATUS WN2C_label(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00253 static STATUS WN2C_exc_scope_end(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00254 static STATUS WN2C_exc_scope_begin(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00255 static STATUS WN2C_istore(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00256 static STATUS WN2C_istorex(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00257 static STATUS WN2C_mstore(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00258 static STATUS WN2C_stid(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00259 static STATUS WN2C_call(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00260 static STATUS WN2C_eval(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00261 static STATUS WN2C_prefetch(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00262 static STATUS WN2C_comment(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00263 static STATUS WN2C_iload(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00264 static STATUS WN2C_iloadx(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00265 static STATUS WN2C_mload(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00266 static STATUS WN2C_array(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00267 static STATUS WN2C_intrinsic_op(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00268 static STATUS WN2C_tas(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00269 static STATUS WN2C_select(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00270 static STATUS WN2C_cvt(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00271 static STATUS WN2C_cvtl(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00272 static STATUS WN2C_realpart(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00273 static STATUS WN2C_imagpart(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00274 static STATUS WN2C_paren(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00275 static STATUS WN2C_complex(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00276 static STATUS WN2C_bnor(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00277 static STATUS WN2C_madd(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00278 static STATUS WN2C_msub(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00279 static STATUS WN2C_nmadd(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00280 static STATUS WN2C_nmsub(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00281 static STATUS WN2C_ldid(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00282 static STATUS WN2C_lda(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00283 static STATUS WN2C_const(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00284 static STATUS WN2C_intconst(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00285 static STATUS WN2C_parm(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00286 static STATUS WN2C_comma(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00287 static STATUS WN2C_rcomma(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00288 static STATUS WN2C_alloca(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00289 static STATUS WN2C_dealloca(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00290 static STATUS WN2C_extract_bits(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00291 static STATUS WN2C_compose_bits(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context);
00292 
00293 typedef STATUS (*WN2C_HANDLER_FUNC)(TOKEN_BUFFER, const WN*, CONTEXT);
00294 
00295 /* WN2C_Opr_Handle[] maps an OPR (../common/com/opcode_gen_core.h)
00296  * to the function that translates it to C.  It is dynamically 
00297  * initialized in WN2C_initialize(), by means of the table:
00298  * WN2C_Opr_Handler_Map[].  Operators we cannot handle in whirl2c are
00299  * handled by WN2C_unsupported().
00300  */
00301 #define NUMBER_OF_OPERATORS (OPERATOR_LAST + 1)
00302 static WN2C_HANDLER_FUNC WN2C_Opr_Handler[NUMBER_OF_OPERATORS];
00303 
00304 typedef struct Opr2handler
00305 {
00306    OPERATOR           opr;
00307    WN2C_HANDLER_FUNC  handler;
00308 } OPR2HANDLER;
00309 
00310 #define NUMBER_OF_OPR2HANDLER_MAPS \
00311    (sizeof(WN2C_Opr_Handler_Map) / sizeof(OPR2HANDLER))
00312 
00313 static const OPR2HANDLER WN2C_Opr_Handler_Map[] =
00314 {
00315    {OPR_FUNC_ENTRY, &WN2C_func_entry},
00316    {OPR_BLOCK, &WN2C_block},
00317    {OPR_REGION, &WN2C_region},
00318    {OPR_REGION_EXIT, &WN2C_goto},
00319    {OPR_COMPGOTO, &WN2C_compgoto},
00320    {OPR_SWITCH, &WN2C_switch},
00321    {OPR_DO_LOOP, &WN2C_do_loop},
00322    {OPR_DO_WHILE, &WN2C_do_while},
00323    {OPR_WHILE_DO, &WN2C_while_do},
00324    {OPR_IF, &WN2C_if},
00325    {OPR_GOTO, &WN2C_goto},
00326    {OPR_CASEGOTO, &WN2C_goto},
00327    {OPR_FALSEBR, &WN2C_condbr},
00328    {OPR_TRUEBR, &WN2C_condbr},
00329    {OPR_RETURN, &WN2C_return},
00330    {OPR_RETURN_VAL, &WN2C_return_val},
00331    {OPR_LABEL, &WN2C_label},
00332    {OPR_EXC_SCOPE_BEGIN, &WN2C_exc_scope_begin},
00333    {OPR_EXC_SCOPE_END, &WN2C_exc_scope_end},
00334    {OPR_ISTORE, &WN2C_istore},
00335    {OPR_ISTOREX, &WN2C_istorex},
00336    {OPR_MSTORE, &WN2C_mstore},
00337    {OPR_STID, &WN2C_stid},
00338    {OPR_CALL, &WN2C_call},
00339    {OPR_INTRINSIC_CALL, &WN2C_call},
00340    {OPR_ICALL, &WN2C_call},
00341    {OPR_PICCALL, &WN2C_call},
00342    {OPR_EVAL, &WN2C_eval},
00343    {OPR_PRAGMA, &WN2C_pragma},
00344    {OPR_XPRAGMA, &WN2C_pragma},
00345    {OPR_PREFETCH, &WN2C_prefetch},
00346    {OPR_PREFETCHX, &WN2C_prefetch},
00347    {OPR_COMMENT, &WN2C_comment},
00348    {OPR_ILOAD, &WN2C_iload},
00349    {OPR_ILOADX, &WN2C_iloadx},
00350    {OPR_MLOAD, &WN2C_mload},
00351    {OPR_ARRAY, &WN2C_array},
00352    {OPR_INTRINSIC_OP, &WN2C_intrinsic_op},
00353    {OPR_TAS, &WN2C_tas},
00354    {OPR_SELECT, &WN2C_select},
00355    {OPR_CSELECT, &WN2C_select},
00356    {OPR_CVT, &WN2C_cvt},
00357    {OPR_CVTL, &WN2C_cvtl},
00358    {OPR_NEG, &WN2C_unaryop},
00359    {OPR_ABS, &WN2C_unaryop},
00360    {OPR_SQRT, &WN2C_unaryop},
00361    {OPR_REALPART, &WN2C_realpart},
00362    {OPR_IMAGPART, &WN2C_imagpart},
00363    {OPR_PAREN, &WN2C_paren},
00364    {OPR_RND, &WN2C_unaryop},
00365    {OPR_TRUNC, &WN2C_unaryop},
00366    {OPR_CEIL, &WN2C_unaryop},
00367    {OPR_FLOOR, &WN2C_unaryop},
00368    {OPR_BNOT, &WN2C_unaryop},
00369    {OPR_LNOT, &WN2C_unaryop},
00370    {OPR_ADD, &WN2C_binaryop},
00371    {OPR_SUB, &WN2C_binaryop},
00372    {OPR_MPY, &WN2C_binaryop},
00373    {OPR_DIV, &WN2C_binaryop},
00374    {OPR_MOD, &WN2C_binaryop},
00375    {OPR_REM, &WN2C_binaryop},
00376    {OPR_MAX, &WN2C_binaryop},
00377    {OPR_MIN, &WN2C_binaryop},
00378    {OPR_BAND, &WN2C_binaryop},
00379    {OPR_BIOR, &WN2C_binaryop},
00380    {OPR_BNOR, &WN2C_bnor},
00381    {OPR_BXOR, &WN2C_binaryop},
00382    {OPR_LAND, &WN2C_binaryop},
00383    {OPR_LIOR, &WN2C_binaryop},
00384    {OPR_CAND, &WN2C_binaryop},
00385    {OPR_CIOR, &WN2C_binaryop},
00386    {OPR_SHL, &WN2C_binaryop},
00387    {OPR_ASHR, &WN2C_binaryop},
00388    {OPR_LSHR, &WN2C_binaryop},
00389    {OPR_COMPLEX, &WN2C_complex},
00390    {OPR_RECIP, &WN2C_unaryop},
00391    {OPR_RSQRT, &WN2C_unaryop},
00392    {OPR_MADD, &WN2C_madd},
00393    {OPR_MSUB, &WN2C_msub},
00394    {OPR_NMADD, &WN2C_nmadd},
00395    {OPR_NMSUB, &WN2C_nmsub},
00396    {OPR_EQ, &WN2C_binaryop},
00397    {OPR_NE, &WN2C_binaryop},
00398    {OPR_GT, &WN2C_binaryop},
00399    {OPR_GE, &WN2C_binaryop},
00400    {OPR_LT, &WN2C_binaryop},
00401    {OPR_LE, &WN2C_binaryop},
00402    {OPR_LDID, &WN2C_ldid},
00403    {OPR_LDA, &WN2C_lda},
00404    {OPR_CONST, &WN2C_const},
00405    {OPR_INTCONST, &WN2C_intconst},
00406    {OPR_PARM, &WN2C_parm},
00407    {OPR_TRAP, &WN2C_ignore},
00408    {OPR_ASSERT, &WN2C_ignore},
00409    {OPR_FORWARD_BARRIER, &WN2C_ignore},
00410    {OPR_BACKWARD_BARRIER, &WN2C_ignore},
00411    {OPR_COMMA, &WN2C_comma},
00412    {OPR_RCOMMA, &WN2C_rcomma},
00413    {OPR_ALLOCA, &WN2C_alloca},
00414    {OPR_DEALLOCA, &WN2C_dealloca},
00415    {OPR_EXTRACT_BITS, &WN2C_extract_bits},
00416    {OPR_COMPOSE_BITS,&WN2C_compose_bits}
00417 }; /* WN2C_Opr_Handler_Map */
00418 
00419 
00420 /*------- C names for binary and unary arithmetic operations ----------*/
00421 /*---------------------------------------------------------------------*/
00422 
00423 
00424 /* Assume the C name for a WHIRL arithmetic/logical operation
00425  * begins with an underscore ('_') when it is implemented as
00426  * a function;  otherwise assume we have a builtin infix C
00427  * operator for the operation.
00428  */
00429 #define WN2C_IS_INFIX_OP(opc) \
00430    ((WN2C_Opc2cname[opc]!=NULL)? (WN2C_Opc2cname[opc][0]!='_') : FALSE)
00431 
00432 #define WN2C_IS_FUNCALL_OP(opc) \
00433    ((WN2C_Opc2cname[opc]!=NULL)? (WN2C_Opc2cname[opc][0]=='_') : FALSE)
00434 
00435 
00436 /* Mapping from opcodes to C names for arithmetic/logical operations.
00437  * An empty (NULL) C name will occur for non-arithmetic/-logical 
00438  * opcodes, which must be handled by special handler-functions.
00439  * This mapping is dynamically initialized, based on 
00440  * WN2C_Opc2cname_Map[], in WN2C_initialize().
00441  */
00442 #define NUMBER_OF_OPCODES (OPCODE_LAST+1)
00443 static const char *WN2C_Opc2cname[NUMBER_OF_OPCODES];
00444    
00445 
00446 typedef struct Opc2Cname_Map
00447 {
00448    OPCODE      opc;
00449    const char *cname;
00450 } OPC2CNAME_MAP;
00451 
00452 #define NUMBER_OF_OPC2CNAME_MAPS \
00453    sizeof(WN2C_Opc2cname_Map) / sizeof(OPC2CNAME_MAP)
00454 static const OPC2CNAME_MAP WN2C_Opc2cname_Map[] =
00455 {
00456   {OPC_U8NEG, "-"},
00457   {OPC_FQNEG, "-"},
00458   {OPC_I8NEG, "-"},
00459   {OPC_U4NEG, "-"},
00460   {OPC_CQNEG, "_CQNEG"},
00461   {OPC_F8NEG, "-"},
00462   {OPC_C8NEG, "_C8NEG"},
00463   {OPC_I4NEG, "-"},
00464   {OPC_F4NEG, "-"},
00465   {OPC_C4NEG, "_C4NEG"},
00466   {OPC_I4ABS, "_I4ABS"},
00467   {OPC_F4ABS, "_F4ABS"},
00468   {OPC_FQABS, "_FQABS"},
00469   {OPC_I8ABS, "_I8ABS"},
00470   {OPC_F8ABS, "_F8ABS"},
00471   {OPC_F4SQRT, "_F4SQRT"},
00472   {OPC_C4SQRT, "_C4SQRT"},
00473   {OPC_FQSQRT, "_FQSQRT"},
00474   {OPC_CQSQRT, "_CQSQRT"},
00475   {OPC_F8SQRT, "_F8SQRT"},
00476   {OPC_C8SQRT, "_C8SQRT"},
00477   {OPC_I4F4RND, "_I4F4RND"},
00478   {OPC_I4FQRND, "_I4FQRND"},
00479   {OPC_I4F8RND, "_I4F8RND"},
00480   {OPC_U4F4RND, "_U4F4RND"},
00481   {OPC_U4FQRND, "_U4FQRND"},
00482   {OPC_U4F8RND, "_U4F8RND"},
00483   {OPC_I8F4RND, "_I8F4RND"},
00484   {OPC_I8FQRND, "_I8FQRND"},
00485   {OPC_I8F8RND, "_I8F8RND"},
00486   {OPC_U8F4RND, "_U8F4RND"},
00487   {OPC_U8FQRND, "_U8FQRND"},
00488   {OPC_U8F8RND, "_U8F8RND"},
00489   {OPC_I4F4TRUNC, "_I4F4TRUNC"},
00490   {OPC_I4FQTRUNC, "_I4FQTRUNC"},
00491   {OPC_I4F8TRUNC, "_I4F8TRUNC"},
00492   {OPC_U4F4TRUNC, "_U4F8TRUNC"},
00493   {OPC_U4FQTRUNC, "_U4F8TRUNC"},
00494   {OPC_U4F8TRUNC, "_U4F8TRUNC"},
00495   {OPC_I8F4TRUNC, "_I8F4TRUNC"},
00496   {OPC_I8FQTRUNC, "_I8FQTRUNC"},
00497   {OPC_I8F8TRUNC, "_I8F8TRUNC"},
00498   {OPC_U8F4TRUNC, "_U8F8TRUNC"},
00499   {OPC_U8FQTRUNC, "_U8F8TRUNC"},
00500   {OPC_U8F8TRUNC, "_U8F8TRUNC"},
00501   {OPC_I4F4CEIL, "_I4F4CEIL"},
00502   {OPC_I4FQCEIL, "_I4FQCEIL"},
00503   {OPC_I4F8CEIL, "_I4F8CEIL"},
00504   {OPC_U4F4CEIL, "_U4F8CEIL"},
00505   {OPC_U4FQCEIL, "_U4F8CEIL"},
00506   {OPC_U4F8CEIL, "_U4F8CEIL"},
00507   {OPC_I8F4CEIL, "_I8F4CEIL"},
00508   {OPC_I8FQCEIL, "_I8FQCEIL"},
00509   {OPC_I8F8CEIL, "_I8F8CEIL"},
00510   {OPC_U8F4CEIL, "_U8F4CEIL"},
00511   {OPC_U8FQCEIL, "_U8FQCEIL"},
00512   {OPC_U8F8CEIL, "_U8F8CEIL"},
00513   {OPC_I4F4FLOOR, "_I4F4FLOOR"},
00514   {OPC_I4FQFLOOR, "_I4FQFLOOR"},
00515   {OPC_I4F8FLOOR, "_I4F8FLOOR"},
00516   {OPC_U4F4FLOOR, "_U4F4FLOOR"},
00517   {OPC_U4FQFLOOR, "_U4FQFLOOR"},
00518   {OPC_U4F8FLOOR, "_U4F8FLOOR"},
00519   {OPC_I8F4FLOOR, "_I8F4FLOOR"},
00520   {OPC_I8FQFLOOR, "_I8FQFLOOR"},
00521   {OPC_I8F8FLOOR, "_I8F8FLOOR"},
00522   {OPC_U8F4FLOOR, "_U8F4FLOOR"},
00523   {OPC_U8FQFLOOR, "_U8FQFLOOR"},
00524   {OPC_U8F8FLOOR, "_U8F8FLOOR"},
00525   {OPC_F8F8FLOOR,"_F8F8FLOOR"}, 
00526   {OPC_I4BNOT, "~"},
00527   {OPC_U8BNOT, "~"},
00528   {OPC_I8BNOT, "~"},
00529   {OPC_U4BNOT, "~"},
00530 // >> WHIRL 0.30: replaced OPC_LNOT by OPC_B and OP_I4 variants
00531 // TODO WHIRL 0.30: get rid of OPC_I4 variants
00532   {OPC_BLNOT, "!"},
00533   {OPC_I4LNOT, "!"},
00534 // << WHIRL 0.30: replaced OPC_LNOT by OPC_B and OP_I4 variants
00535   {OPC_U8ADD, "+"},
00536   {OPC_FQADD, "+"},
00537   {OPC_I8ADD, "+"},
00538   {OPC_U4ADD, "+"},
00539   {OPC_CQADD, "_CQADD"},
00540   {OPC_F8ADD, "+"},
00541   {OPC_C8ADD, "_C8ADD"},
00542   {OPC_I4ADD, "+"},
00543   {OPC_F4ADD, "+"},
00544   {OPC_C4ADD, "_C4ADD"},
00545   {OPC_U8SUB, "-"},
00546   {OPC_FQSUB, "-"},
00547   {OPC_I8SUB, "-"},
00548   {OPC_U4SUB, "-"},
00549   {OPC_CQSUB, "_CQSUB"},
00550   {OPC_F8SUB, "-"},
00551   {OPC_C8SUB, "_C8SUB"},
00552   {OPC_I4SUB, "-"},
00553   {OPC_F4SUB, "-"},
00554   {OPC_C4SUB, "_C4SUB"},
00555   {OPC_U8MPY, "*"},
00556   {OPC_FQMPY, "*"},
00557   {OPC_I8MPY, "*"},
00558   {OPC_U4MPY, "*"},
00559   {OPC_CQMPY, "_CQMPY"},
00560   {OPC_F8MPY, "*"},
00561   {OPC_C8MPY, "_C8MPY"},
00562   {OPC_I4MPY, "*"},
00563   {OPC_F4MPY, "*"},
00564   {OPC_C4MPY, "_C4MPY"},
00565   {OPC_U8DIV, "/"},
00566   {OPC_FQDIV, "/"},
00567   {OPC_I8DIV, "/"},
00568   {OPC_U4DIV, "/"},
00569   {OPC_CQDIV, "_CQDIV"},
00570   {OPC_F8DIV, "/"},
00571   {OPC_C8DIV, "_C8DIV"},
00572   {OPC_I4DIV, "/"},
00573   {OPC_F4DIV, "/"},
00574   {OPC_C4DIV, "_C4DIV"},
00575   {OPC_I4MOD, "_I4MOD"},
00576   {OPC_U8MOD, "%"},
00577   {OPC_I8MOD, "_I8MOD"},
00578   {OPC_U4MOD, "%"},
00579   {OPC_I4REM, "%"},
00580   {OPC_U8REM, "%"},
00581   {OPC_I8REM, "%"},
00582   {OPC_U4REM, "%"},
00583   {OPC_I4MAX, "_I4MAX"},
00584   {OPC_U8MAX, "_U8MAX"},
00585   {OPC_F4MAX, "_F4MAX"},
00586   {OPC_FQMAX, "_FQMAX"},
00587   {OPC_I8MAX, "_I8MAX"},
00588   {OPC_U4MAX, "_U4MAX"},
00589   {OPC_F8MAX, "_F8MAX"},
00590   {OPC_I4MIN, "_I4MIN"},
00591   {OPC_U8MIN, "_U8MIN"},
00592   {OPC_F4MIN, "_F4MIN"},
00593   {OPC_FQMIN, "_FQMIN"},
00594   {OPC_I8MIN, "_I8MIN"},
00595   {OPC_U4MIN, "_U4MIN"},
00596   {OPC_F8MIN, "_F8MIN"},
00597   {OPC_I4BAND, "&"},
00598   {OPC_U8BAND, "&"},
00599   {OPC_I8BAND, "&"},
00600   {OPC_U4BAND, "&"},
00601   {OPC_I4BIOR, "|"},
00602   {OPC_U8BIOR, "|"},
00603   {OPC_I8BIOR, "|"},
00604   {OPC_U4BIOR, "|"},
00605   {OPC_I4BXOR, "^"},
00606   {OPC_U8BXOR, "^"},
00607   {OPC_I8BXOR , "^"},
00608   {OPC_U4BXOR, "^"},
00609 // >> WHIRL 0.30: replaced OPC_LAND, OPC_LIOR, OPC_CAND, OPC_CIOR by OPC_B and OP_I4 variants
00610 // TODO WHIRL 0.30: get rid of OPC_I4 variants
00611   {OPC_BLAND, "&&"},
00612   {OPC_I4LAND, "&&"},
00613   {OPC_BLIOR, "||"},
00614   {OPC_I4LIOR, "||"},
00615   {OPC_BCAND, "&&"},
00616   {OPC_I4CAND, "&&"},
00617   {OPC_BCIOR, "||"},
00618   {OPC_I4CIOR, "||"},
00619 // << WHIRL 0.30: replaced OPC_LAND, OPC_LIOR, OPC_CAND, OPC_CIOR by OPC_B and OP_I4 variants
00620   {OPC_I4SHL, "_I4SHL"},
00621   {OPC_U8SHL, "_U8SHL"},
00622   {OPC_I8SHL, "_I8SHL"},
00623   {OPC_U4SHL, "_U4SHL"},
00624   {OPC_I4ASHR, "_I4ASHR"},
00625   {OPC_U8ASHR, "_U8ASHR"},
00626   {OPC_I8ASHR, "_I8ASHR"},
00627   {OPC_U4ASHR, "_U4ASHR"},
00628   {OPC_I4LSHR, "_I4LSHR"},
00629   {OPC_U8LSHR, "_U8LSHR"},
00630   {OPC_I8LSHR, "_I8LSHR"},
00631   {OPC_U4LSHR, "_U4LSHR"},
00632   {OPC_F4RECIP, "_F4RECIP"},
00633   {OPC_C4RECIP, "_C4RECIP"},
00634   {OPC_FQRECIP, "_FQRECIP"},
00635   {OPC_CQRECIP, "_CQRECIP"},
00636   {OPC_F8RECIP, "_F8RECIP"},
00637   {OPC_C8RECIP, "_C8RECIP"},
00638   {OPC_F4RSQRT, "_F4RSQRT"},
00639   {OPC_C4RSQRT, "_C4RSQRT"},
00640   {OPC_FQRSQRT, "_FQRSQRT"},
00641   {OPC_CQRSQRT, "_CQRSQRT"},
00642   {OPC_F8RSQRT, "_F8RSQRT"},
00643   {OPC_C8RSQRT, "_C8RSQRT"},
00644 // >> WHIRL 0.30: Replaced OPC_T1{EQ,NE,GT,GE,LT,LE} by OP_BT1 and OPC_I4T1 variants
00645 // TODO WHIRL 0.30: get rid of OPC_I4T1 variants
00646   {OPC_BU8EQ, "=="},
00647   {OPC_BFQEQ, "=="},
00648   {OPC_BI8EQ, "=="},
00649   {OPC_BU4EQ, "=="},
00650   {OPC_BCQEQ, "=="},
00651   {OPC_BF8EQ, "=="},
00652   {OPC_BC8EQ, "=="},
00653   {OPC_BI4EQ, "=="},
00654   {OPC_BF4EQ, "=="},
00655   {OPC_BC4EQ, "=="},
00656   {OPC_BU8NE, "!="},
00657   {OPC_BFQNE, "!="},
00658   {OPC_BI8NE, "!="},
00659   {OPC_BU4NE, "!="},
00660   {OPC_BCQNE, "!="},
00661   {OPC_BF8NE, "!="},
00662   {OPC_BC8NE, "!="},
00663   {OPC_BI4NE, "!="},
00664   {OPC_BF4NE, "!="},
00665   {OPC_BC4NE, "!="},
00666   {OPC_BI4GT, ">"},
00667   {OPC_BU8GT, ">"},
00668   {OPC_BF4GT, ">"},
00669   {OPC_BFQGT, ">"},
00670   {OPC_BI8GT, ">"},
00671   {OPC_BU4GT, ">"},
00672   {OPC_BF8GT, ">"},
00673   {OPC_BI4GE, ">="},
00674   {OPC_BU8GE, ">="},
00675   {OPC_BF4GE, ">="},
00676   {OPC_BFQGE, ">="},
00677   {OPC_BI8GE, ">="},
00678   {OPC_BU4GE, ">="},
00679   {OPC_BF8GE, ">="},
00680   {OPC_BI4LT, "<"},
00681   {OPC_BU8LT, "<"},
00682   {OPC_BF4LT, "<"},
00683   {OPC_BFQLT, "<"},
00684   {OPC_BI8LT, "<"},
00685   {OPC_BU4LT, "<"},
00686   {OPC_BF8LT, "<"},
00687   {OPC_BI4LE, "<="},
00688   {OPC_BU8LE, "<="},
00689   {OPC_BF4LE, "<="},
00690   {OPC_BFQLE, "<="},
00691   {OPC_BI8LE, "<="},
00692   {OPC_BU4LE, "<="},
00693   {OPC_BF8LE, "<="},
00694 
00695   {OPC_I4U8EQ, "=="},
00696   {OPC_I4FQEQ, "=="},
00697   {OPC_I4I8EQ, "=="},
00698   {OPC_I4U4EQ, "=="},
00699   {OPC_I4CQEQ, "=="},
00700   {OPC_I4F8EQ, "=="},
00701   {OPC_I4C8EQ, "=="},
00702   {OPC_I4I4EQ, "=="},
00703   {OPC_I4F4EQ, "=="},
00704   {OPC_I4C4EQ, "=="},
00705 
00706   {OPC_I8U8EQ, "=="},
00707   {OPC_I8FQEQ, "=="},
00708   {OPC_I8I8EQ, "=="},
00709   {OPC_I8U4EQ, "=="},
00710   {OPC_I8CQEQ, "=="},
00711   {OPC_I8F8EQ, "=="},
00712   {OPC_I8C8EQ, "=="},
00713   {OPC_I8I4EQ, "=="},
00714   {OPC_I8F4EQ, "=="},
00715   {OPC_I8C4EQ, "=="},
00716 
00717   {OPC_U4U8EQ, "=="},
00718   {OPC_U4FQEQ, "=="},
00719   {OPC_U4I8EQ, "=="},
00720   {OPC_U4U4EQ, "=="},
00721   {OPC_U4CQEQ, "=="},
00722   {OPC_U4F8EQ, "=="},
00723   {OPC_U4C8EQ, "=="},
00724   {OPC_U4I4EQ, "=="},
00725   {OPC_U4F4EQ, "=="},
00726   {OPC_U4C4EQ, "=="},
00727 
00728   {OPC_U8U8EQ, "=="},
00729   {OPC_U8FQEQ, "=="},
00730   {OPC_U8I8EQ, "=="},
00731   {OPC_U8U4EQ, "=="},
00732   {OPC_U8CQEQ, "=="},
00733   {OPC_U8F8EQ, "=="},
00734   {OPC_U8C8EQ, "=="},
00735   {OPC_U8I4EQ, "=="},
00736   {OPC_U8F4EQ, "=="},
00737   {OPC_U8C4EQ, "=="},
00738 
00739   {OPC_I4U8NE, "!="},
00740   {OPC_I4FQNE, "!="},
00741   {OPC_I4I8NE, "!="},
00742   {OPC_I4U4NE, "!="},
00743   {OPC_I4CQNE, "!="},
00744   {OPC_I4F8NE, "!="},
00745   {OPC_I4C8NE, "!="},
00746   {OPC_I4I4NE, "!="},
00747   {OPC_I4F4NE, "!="},
00748   {OPC_I4C4NE, "!="},
00749  
00750   {OPC_I8U8NE, "!="},
00751   {OPC_I8FQNE, "!="},
00752   {OPC_I8I8NE, "!="},
00753   {OPC_I8U4NE, "!="},
00754   {OPC_I8CQNE, "!="},
00755   {OPC_I8F8NE, "!="},
00756   {OPC_I8C8NE, "!="},
00757   {OPC_I8I4NE, "!="},
00758   {OPC_I8F4NE, "!="},
00759   {OPC_I8C4NE, "!="},
00760 
00761   {OPC_U4U8NE, "!="},
00762   {OPC_U4FQNE, "!="},
00763   {OPC_U4I8NE, "!="},
00764   {OPC_U4U4NE, "!="},
00765   {OPC_U4CQNE, "!="},
00766   {OPC_U4F8NE, "!="},
00767   {OPC_U4C8NE, "!="},
00768   {OPC_U4I4NE, "!="},
00769   {OPC_U4F4NE, "!="},
00770   {OPC_U4C4NE, "!="},
00771 
00772   {OPC_U8U8NE, "!="},
00773   {OPC_U8FQNE, "!="},
00774   {OPC_U8I8NE, "!="},
00775   {OPC_U8U4NE, "!="},
00776   {OPC_U8CQNE, "!="},
00777   {OPC_U8F8NE, "!="},
00778   {OPC_U8C8NE, "!="},
00779   {OPC_U8I4NE, "!="},
00780   {OPC_U8F4NE, "!="},
00781   {OPC_U8C4NE, "!="},
00782 
00783   {OPC_I4I4GT, ">"},
00784   {OPC_I4U8GT, ">"},
00785   {OPC_I4F4GT, ">"},
00786   {OPC_I4FQGT, ">"},
00787   {OPC_I4I8GT, ">"},
00788   {OPC_I4U4GT, ">"},
00789   {OPC_I4F8GT, ">"},
00790 
00791   {OPC_I8I4GT, ">"},
00792   {OPC_I8U8GT, ">"},
00793   {OPC_I8F4GT, ">"},
00794   {OPC_I8FQGT, ">"},
00795   {OPC_I8I8GT, ">"},
00796   {OPC_I8U4GT, ">"},
00797   {OPC_I8F8GT, ">"},
00798 
00799   {OPC_U4I4GT, ">"},
00800   {OPC_U4U8GT, ">"},
00801   {OPC_U4F4GT, ">"},
00802   {OPC_U4FQGT, ">"},
00803   {OPC_U4I8GT, ">"},
00804   {OPC_U4U4GT, ">"},
00805   {OPC_U4F8GT, ">"},
00806 
00807   {OPC_U8I4GT, ">"},
00808   {OPC_U8U8GT, ">"},
00809   {OPC_U8F4GT, ">"},
00810   {OPC_U8FQGT, ">"},
00811   {OPC_U8I8GT, ">"},
00812   {OPC_U8U4GT, ">"},
00813   {OPC_U8F8GT, ">"},
00814 
00815   {OPC_I4I4GE, ">="},
00816   {OPC_I4U8GE, ">="},
00817   {OPC_I4F4GE, ">="},
00818   {OPC_I4FQGE, ">="},
00819   {OPC_I4I8GE, ">="},
00820   {OPC_I4U4GE, ">="},
00821   {OPC_I4F8GE, ">="},
00822 
00823   {OPC_I8I4GE, ">="},
00824   {OPC_I8U8GE, ">="},
00825   {OPC_I8F4GE, ">="},
00826   {OPC_I8FQGE, ">="},
00827   {OPC_I8I8GE, ">="},
00828   {OPC_I8U4GE, ">="},
00829   {OPC_I8F8GE, ">="},
00830 
00831   {OPC_U4I4GE, ">="},
00832   {OPC_U4U8GE, ">="},
00833   {OPC_U4F4GE, ">="},
00834   {OPC_U4FQGE, ">="},
00835   {OPC_U4I8GE, ">="},
00836   {OPC_U4U4GE, ">="},
00837   {OPC_U4F8GE, ">="},
00838 
00839   {OPC_U8I4GE, ">="},
00840   {OPC_U8U8GE, ">="},
00841   {OPC_U8F4GE, ">="},
00842   {OPC_U8FQGE, ">="},
00843   {OPC_U8I8GE, ">="},
00844   {OPC_U8U4GE, ">="},
00845   {OPC_U8F8GE, ">="},
00846 
00847   {OPC_I4I4LT, "<"},
00848   {OPC_I4U8LT, "<"},
00849   {OPC_I4F4LT, "<"},
00850   {OPC_I4FQLT, "<"},
00851   {OPC_I4I8LT, "<"},
00852   {OPC_I4U4LT, "<"},
00853   {OPC_I4F8LT, "<"},
00854 
00855   {OPC_I8I4LT, "<"},
00856   {OPC_I8U8LT, "<"},
00857   {OPC_I8F4LT, "<"},
00858   {OPC_I8FQLT, "<"},
00859   {OPC_I8I8LT, "<"},
00860   {OPC_I8U4LT, "<"},
00861   {OPC_I8F8LT, "<"},
00862 
00863   {OPC_U4I4LT, "<"},
00864   {OPC_U4U8LT, "<"},
00865   {OPC_U4F4LT, "<"},
00866   {OPC_U4FQLT, "<"},
00867   {OPC_U4I8LT, "<"},
00868   {OPC_U4U4LT, "<"},
00869   {OPC_U4F8LT, "<"},
00870 
00871   {OPC_U8I4LT, "<"},
00872   {OPC_U8U8LT, "<"},
00873   {OPC_U8F4LT, "<"},
00874   {OPC_U8FQLT, "<"},
00875   {OPC_U8I8LT, "<"},
00876   {OPC_U8U4LT, "<"},
00877   {OPC_U8F8LT, "<"},
00878 
00879   {OPC_I4I4LE, "<="},
00880   {OPC_I4U8LE, "<="},
00881   {OPC_I4F4LE, "<="},
00882   {OPC_I4FQLE, "<="},
00883   {OPC_I4I8LE, "<="},
00884   {OPC_I4U4LE, "<="},
00885   {OPC_I4F8LE, "<="},
00886 
00887   {OPC_I8I4LE, "<="},
00888   {OPC_I8U8LE, "<="},
00889   {OPC_I8F4LE, "<="},
00890   {OPC_I8FQLE, "<="},
00891   {OPC_I8I8LE, "<="},
00892   {OPC_I8U4LE, "<="},
00893   {OPC_I8F8LE, "<="},
00894 
00895   {OPC_U4I4LE, "<="},
00896   {OPC_U4U8LE, "<="},
00897   {OPC_U4F4LE, "<="},
00898   {OPC_U4FQLE, "<="},
00899   {OPC_U4I8LE, "<="},
00900   {OPC_U4U4LE, "<="},
00901   {OPC_U4F8LE, "<="},
00902 
00903   {OPC_U8I4LE, "<="},
00904   {OPC_U8U8LE, "<="},
00905   {OPC_U8F4LE, "<="},
00906   {OPC_U8FQLE, "<="},
00907   {OPC_U8I8LE, "<="},
00908   {OPC_U8U4LE, "<="},
00909   {OPC_U8F8LE, "<="}
00910 
00911 
00912 // << WHIRL 0.30: Replaced OPC_T1{EQ,NE,GT,GE,LT,LE} by OP_BT1 and OPC_I4T1 variants
00913 }; /* WN2C_Opc2Cname_Map */
00914 
00915 /*------------------ Statement newline directives ----------------------*/
00916 /*----------------------------------------------------------------------*/
00917 
00918 static void 
00919 WN2C_Stmt_Newline(TOKEN_BUFFER tokens,
00920                   SRCPOS       srcpos)
00921 {
00922    if (W2C_Emit_Linedirs)
00923       Append_Srcpos_Directive(tokens, srcpos);
00924    Append_Indented_Newline(tokens, 1);
00925    if (W2C_File[W2C_LOC_FILE] != NULL)
00926       Append_Srcpos_Map(tokens, srcpos);
00927 } /* WN2C_Stmt_Newline */
00928 
00929 
00930 /*--------------------- hidden utility routines -----------------------*/
00931 /*---------------------------------------------------------------------*/
00932 
00933 static STATUS
00934 WN2C_lvalue_wn(TOKEN_BUFFER tokens,
00935                const WN    *wn,          /* Base address for lvalue */
00936                TY_IDX       addr_ty,     /* Type of base address */
00937                TY_IDX       object_ty,   /* Type of object to be loaded */
00938                STAB_OFFSET  addr_offset, /* Offset of object from base */
00939                CONTEXT      context);
00940 
00941 
00942 static void
00943 WN2C_incr_indentation_for_stmt_body(const WN *body)
00944 {
00945    /* The indentation of blocks as bodies of other statements or
00946     * functions is handled by the processing of the block in
00947     * WN2C_block(), so no increment needs be done here.
00948     */
00949    if (WN_operator(body) != OPR_BLOCK)
00950       Increment_Indentation();
00951 } /* WN2C_incr_indentation_for_stmt_body */
00952 
00953 
00954 static void 
00955 WN2C_decr_indentation_for_stmt_body(const WN *body)
00956 {
00957    /* The indentation of blocks as bodies of other statements or
00958     * functions is handled by the processing of the block in
00959     * WN2C_block(), so no decrement needs be done here.
00960     */
00961    if (WN_operator(body) != OPR_BLOCK)
00962       Decrement_Indentation();
00963 } /* WN2C_decr_indentation_for_stmt_body */
00964 
00965 
00966 static TOKEN_BUFFER
00967 WN2C_generate_cast(TY_IDX cast_to,         /* Cast expr to this ty */
00968                    BOOL   pointer_to_type) /* TYs are pointed to */
00969 {
00970    /* Generate a cast to preceede the existing tokens.  If 
00971     * pointer_to_type==TRUE, then we get:
00972     *
00973     *   (<cast_to> *)<tokens>
00974     *
00975     * Otherwise, we'll get:
00976     *
00977     *   (<cast_to>)<tokens>
00978     */
00979    TOKEN_BUFFER ty_buffer = New_Token_Buffer();
00980    
00981    if (pointer_to_type)
00982       Append_Token_Special(ty_buffer, '*');
00983    if (TY_Is_Array_Or_Function(cast_to))
00984       WHIRL2C_parenthesize(ty_buffer);
00985 
00986    TY2C_translate_unqualified(ty_buffer, cast_to);
00987    WHIRL2C_parenthesize(ty_buffer);
00988    return ty_buffer;
00989 } /* WN2C_generate_cast */
00990 
00991 
00992 static void
00993 WN2C_prepend_cast(TOKEN_BUFFER tokens,          /* Expression to be cast */
00994                   TY_IDX       cast_to,         /* Cast expr to this ty */
00995                   BOOL         pointer_to_type) /* TYs are pointed to */
00996 {
00997    TOKEN_BUFFER ty_buffer = WN2C_generate_cast(cast_to, pointer_to_type);
00998    Prepend_And_Reclaim_Token_List(tokens, &ty_buffer);
00999 } /* WN2C_prepend_cast */
01000 
01001 
01002 static void
01003 WN2C_append_cast(TOKEN_BUFFER tokens,          /* Expression to be cast */
01004                  TY_IDX       cast_to,         /* Cast expr to this ty */
01005                  BOOL         pointer_to_type) /* TYs are pointed to */
01006 {
01007    TOKEN_BUFFER ty_buffer = WN2C_generate_cast(cast_to, pointer_to_type);
01008    Append_And_Reclaim_Token_List(tokens, &ty_buffer);
01009 } /* WN2C_append_cast */
01010 
01011 
01012 static void
01013 WN2C_Assign_Complex_Const(TOKEN_BUFFER tokens,
01014                           const char  *lhs_name,
01015                           TCON         realpart,
01016                           TCON         imagpart)
01017 {
01018    /* Get real_part */
01019    Append_Token_Special(tokens, '('); /* getting real part */
01020    Append_Token_String(tokens, lhs_name);
01021    Append_Token_Special(tokens, '.');
01022    Append_Token_String(tokens, TY2C_Complex_Realpart_Name);
01023    Append_Token_Special(tokens, '=');
01024    TCON2C_translate(tokens, realpart);
01025    Append_Token_Special(tokens, ')'); /* gotten real part */
01026    Append_Token_Special(tokens, ',');
01027 
01028    /* Get imaginary_part */
01029    Append_Token_Special(tokens, '('); /* getting imaginary part */
01030    Append_Token_String(tokens, lhs_name);
01031    Append_Token_Special(tokens, '.');
01032    Append_Token_String(tokens, TY2C_Complex_Imagpart_Name);
01033    Append_Token_Special(tokens, '=');
01034    TCON2C_translate(tokens, imagpart);
01035    Append_Token_Special(tokens, ')'); /* gotten imaginary part */
01036    Append_Token_Special(tokens, ',');
01037 } /* WN2C_Assign_Complex_Const */
01038 
01039 
01040 static TOKEN_BUFFER
01041 WN2C_Translate_Arithmetic_Operand(const WN*wn, 
01042                                   TY_IDX   result_ty, 
01043                                   CONTEXT  context)
01044 {
01045    TOKEN_BUFFER opnd_tokens = New_Token_Buffer();
01046    TY_IDX       opnd_ty = WN_Tree_Type(wn);
01047 
01048    if (!WN2C_arithmetic_compatible_types(result_ty, opnd_ty))
01049    {
01050       CONTEXT_set_top_level_expr(context);
01051       (void)WN2C_translate(opnd_tokens, wn, context);
01052       WHIRL2C_parenthesize(opnd_tokens);
01053       WN2C_prepend_cast(opnd_tokens, result_ty, FALSE);
01054    }
01055    else
01056       (void)WN2C_translate(opnd_tokens, wn, context);
01057    
01058    return opnd_tokens;
01059 } /* WN2C_Translate_Arithmetic_Operand */
01060 
01061 
01062 static STATUS
01063 WN2C_address_add(TOKEN_BUFFER tokens, 
01064                  OPCODE       opcode,  
01065                  TY_IDX       expr_ty,
01066                  WN          *wn0,
01067                  WN          *wn1,
01068                  CONTEXT      context)
01069 {
01070    /* We make an attempt at retaining pointer types for ptr
01071     * arithmetics, where we expect ptr expressions to be of
01072     * one of the following forms:
01073     *
01074     *    1)  ptr + expr
01075     *    2)  ptr + expr*const
01076     *    1)  ptr + const
01077     *
01078     * and we modify the const whenever we can to account for the
01079     * element size.  First, see if we can find a suitable constant
01080     * expression.
01081     */
01082    TOKEN_BUFFER opnd_tokens;  /* Temporary buffer for translating operand */
01083    UINT64       old_intconst = 0;
01084    WN          *intconst = NULL;
01085    BOOL         top_level_expr = CONTEXT_top_level_expr(context);
01086    TY_IDX       wn0_ty = WN_Tree_Type(wn0);
01087    TY_IDX       wn1_ty = WN_Tree_Type(wn1);
01088    TY_IDX       given_lvalue_ty = (CONTEXT_lvalue_type(context)? 
01089                                    CONTEXT_given_lvalue_ty(context) : 0);
01090    
01091    Is_True(OPCODE_operator(opcode) == OPR_ADD, 
01092            ("Unexpected kind of pointer expression in WN2C_address_add()"));
01093 
01094    CONTEXT_reset_needs_lvalue(context);  /* Need actual value of subexprs */
01095 
01096    intconst = WN_Get_PtrAdd_Intconst(wn0, wn1, TY_pointed(expr_ty));
01097    if (intconst != NULL)
01098    {
01099       /* Normalize intconst, which may be an artbitrary expression 
01100        * if (TY_size(TY_pointed(expr_ty)) == 1).
01101        *
01102        * We already know that it must be divisable by the size of the
01103        * object pointed to by this expression.
01104        */
01105       if (TY_size(TY_pointed(expr_ty)) > 1)
01106       {
01107          Is_True(WN_operator(intconst) == OPR_INTCONST, 
01108                  ("Expected INTCONST in WN2C_address_add()"));
01109 
01110          old_intconst = WN_const_val(intconst);
01111          WN_const_val(intconst) = 
01112             WN_const_val(intconst) / TY_size(TY_pointed(expr_ty));
01113       }
01114       /* Fall through and handle the pointer addition below....
01115        */
01116    }
01117    else if (given_lvalue_ty == (TY_IDX) 0)
01118    {
01119       /* This may occur when the address expression is not dereferenced,
01120        * but occurs as an argument in a function call or in a pointer
01121        * assignment.  Do the offset using (char*), and cast the result
01122        * to a (void*).
01123        */
01124       top_level_expr = FALSE;
01125       WN2C_append_cast(tokens, 
01126                         Stab_Mtype_To_Ty(MTYPE_V), TRUE/*ptr_to_type*/);
01127 
01128       if (TY_Is_Pointer(wn0_ty))
01129          wn0_ty = Stab_Pointer_To(Stab_Mtype_To_Ty(MTYPE_U1));
01130       else
01131          wn1_ty = Stab_Pointer_To(Stab_Mtype_To_Ty(MTYPE_U1));
01132    }
01133    else
01134    {
01135       /* This is a special case.  The ADD represents array indexing,
01136        * a struct offset, or a combination thereof.  First, try to 
01137        * handle this as a struct offset.
01138        */
01139       if (WN_operator(wn0) == OPR_INTCONST && 
01140           TY_size(TY_pointed(expr_ty)) > WN_const_val(wn0) &&
01141           TY_Is_Structured(TY_pointed(expr_ty)))
01142       {
01143          /* Assume a struct offset or an array index */
01144          return WN2C_lvalue_wn(tokens,
01145                                wn1,               /* Base address */
01146                                expr_ty,           /* Type of base address */
01147                                given_lvalue_ty,   /* Type of object */
01148                                WN_const_val(wn0), /* Offset from base */
01149                                context);
01150       }
01151       else if (WN_operator(wn1) == OPR_INTCONST && 
01152                TY_size(TY_pointed(expr_ty)) > WN_const_val(wn1) &&
01153                TY_Is_Structured(TY_pointed(expr_ty)))
01154       {
01155          /* Assume a struct offset or an array index */
01156          return WN2C_lvalue_wn(tokens,
01157                                wn0,               /* Base address */
01158                                expr_ty,           /* Type of base address */
01159                                given_lvalue_ty,   /* Type of object */
01160                                WN_const_val(wn1), /* Offset from base */
01161                                context);
01162       }
01163       else
01164       {
01165          /* Do the pointer operation based on the given_lvalue_ty.
01166           * It may not be pretty, but it should work.
01167           */
01168          intconst = WN_Get_PtrAdd_Intconst(wn0, wn1, given_lvalue_ty);
01169          if (intconst != NULL)
01170          {
01171             /* Normalize the intconst.  We already know that it must be 
01172              * divisable by the size of the object pointed to by this 
01173              * expression.
01174              */
01175             if (TY_size(given_lvalue_ty) > 1)
01176             {
01177                Is_True(WN_operator(intconst) == OPR_INTCONST, 
01178                        ("Expected INTCONST in WN2C_address_add()"));
01179 
01180                old_intconst = WN_const_val(intconst);
01181                WN_const_val(intconst) = 
01182                   WN_const_val(intconst) / TY_size(given_lvalue_ty);
01183             }
01184 
01185             if (TY_Is_Pointer(wn0_ty))
01186                wn0_ty = Stab_Pointer_To(given_lvalue_ty);
01187             else
01188                wn1_ty = Stab_Pointer_To(given_lvalue_ty);
01189          }
01190          else
01191          {
01192             /* Last resort */
01193             top_level_expr = FALSE;
01194             WN2C_append_cast(tokens, given_lvalue_ty, TRUE/*ptr_to_type*/);
01195 
01196             if (TY_Is_Pointer(wn0_ty))
01197                wn0_ty = Stab_Pointer_To(Stab_Mtype_To_Ty(MTYPE_U1));
01198             else
01199                wn1_ty = Stab_Pointer_To(Stab_Mtype_To_Ty(MTYPE_U1));
01200          }
01201 
01202          /* Fall through and handle the pointer addition below....
01203           */
01204          
01205       } /* if struct or array offset */
01206    } /* a regular pointer addition */
01207 
01208    /* Append the expression to "tokens", parenthesized if nested within
01209     * another expression.
01210     */
01211    CONTEXT_reset_top_level_expr(context); /* Subexprs are not top-level */
01212    if (!top_level_expr)
01213       Append_Token_Special(tokens, '(');
01214 
01215    if (!TY_Is_Pointer(wn0_ty))
01216       CONTEXT_reset_lvalue_type(context);
01217    opnd_tokens = WN2C_Translate_Arithmetic_Operand(wn0, wn0_ty, context);
01218    Append_And_Reclaim_Token_List(tokens, &opnd_tokens);
01219 
01220    Append_Token_Special(tokens, '+');
01221 
01222    if (TY_Is_Pointer(wn0_ty) && given_lvalue_ty != (TY_IDX) 0)
01223       CONTEXT_set_lvalue_type(context);
01224    opnd_tokens = WN2C_Translate_Arithmetic_Operand(wn1, wn1_ty, context);
01225    Append_And_Reclaim_Token_List(tokens, &opnd_tokens);
01226 
01227    if (!top_level_expr)
01228       Append_Token_Special(tokens, ')');
01229 
01230    /* Restore the intconst value */
01231    if (old_intconst > 0 && intconst != NULL)
01232       WN_const_val(intconst) = old_intconst;
01233 
01234    return EMPTY_STATUS;
01235 } /* WN2C_address_add */
01236 
01237 
01238 static STATUS
01239 WN2C_infix_op(TOKEN_BUFFER tokens, 
01240               OPCODE       opcode, 
01241               TY_IDX       result_ty,
01242               WN          *wn0,
01243               WN          *wn1,
01244               CONTEXT      context)
01245 {
01246    /* This is assumed to be a binary operator, unless wn0==NULL,
01247     * in which case we treat it as a unary operator.  The operator
01248     * will be inserted infix and is assumed to consist of a sequence
01249     * of special character tokens.
01250     */
01251    const char  *op_char;
01252    const BOOL   binary_op = (wn0 != NULL);
01253    const BOOL   top_level_expr = CONTEXT_top_level_expr(context);
01254    const MTYPE  descriptor_mtype = OPCODE_desc(opcode);
01255    TY_IDX       wn0_ty;       /* Expected type of wn0 */
01256    TY_IDX       wn1_ty;       /* Expected type of wn1 */
01257    TOKEN_BUFFER opnd_tokens;  /* Temporary buffer for translating operand */
01258 
01259    /* Get the expected types for the two operands, dependent on whether
01260     * or not we have a descriptor type.
01261     */
01262    if (descriptor_mtype == MTYPE_V)
01263    {
01264       wn0_ty = wn1_ty = result_ty;
01265    }
01266    else
01267    {
01268       wn0_ty = wn1_ty = Stab_Mtype_To_Ty(descriptor_mtype);
01269    }
01270 
01271    /* Do the simplest forms of simplifications */
01272    if (OPCODE_operator(opcode) == OPR_NEG &&
01273        (WN_operator(wn1) == OPR_CONST || 
01274         WN_operator(wn1) == OPR_INTCONST))
01275    {
01276       TCON tcon, tcon1;
01277       BOOL folded;
01278       
01279       if (WN_operator(wn1) == OPR_CONST)
01280          tcon1 = STC_val(WN_st(wn1));
01281       else /* (WN_operator(wn1) == OPR_INTCONST) */
01282          tcon1 = Host_To_Targ(WN_opc_rtype(wn1), WN_const_val(wn1));
01283       tcon = Targ_WhirlOp(opcode, tcon1, tcon1, &folded);
01284 
01285       if (folded)
01286          TCON2C_translate(tokens, tcon);
01287       else
01288       {
01289          /* Explicitly do the operation */
01290          for (op_char = WN2C_Opc2cname[opcode]; *op_char != '\0'; op_char++)
01291             Append_Token_Special(tokens, *op_char);
01292          Append_Token_Special(tokens, '(');
01293          TCON2C_translate(tokens, tcon1);
01294          Append_Token_Special(tokens, ')');
01295       }
01296       return EMPTY_STATUS;
01297    }
01298    else if (OPCODE_operator(opcode) == OPR_MPY)
01299    {
01300       if (WN_operator(wn0) == OPR_INTCONST && 
01301           WN_const_val(wn0) == 1LL)
01302       {
01303          opnd_tokens = WN2C_Translate_Arithmetic_Operand(wn1, wn1_ty, context);
01304          Append_And_Reclaim_Token_List(tokens, &opnd_tokens);
01305          return EMPTY_STATUS;
01306       }
01307       else if (WN_operator(wn1) == OPR_INTCONST && 
01308                WN_const_val(wn1) == 1LL)
01309       {
01310          opnd_tokens = WN2C_Translate_Arithmetic_Operand(wn0, wn0_ty, context);
01311          Append_And_Reclaim_Token_List(tokens, &opnd_tokens);
01312          return EMPTY_STATUS;
01313       }
01314    }
01315 
01316    /* Handle special pointer operations */
01317    if (binary_op && WN2C_is_pointer_diff(opcode, wn0, wn1))
01318    {
01319       opcode = WN_opcode(wn0); /* OPC_SUB */
01320       wn1 = WN_kid1(wn0);      /* ptr0 */
01321       wn0 = WN_kid0(wn0);      /* ptr1 */
01322       wn0_ty = WN_Tree_Type(wn0);
01323       wn1_ty = WN_Tree_Type(wn1);
01324    }
01325    else if (binary_op && TY_Is_Pointer(result_ty))
01326    {
01327       return WN2C_address_add(tokens, 
01328                               opcode,  
01329                               result_ty,
01330                               wn0,
01331                               wn1,
01332                               context);
01333    }
01334 
01335    /* Append the expression to "tokens", parenthesized if nested within
01336     * another expression.
01337     */
01338    CONTEXT_reset_top_level_expr(context); /* Subexprs are not top-level */
01339    if (!top_level_expr)
01340       Append_Token_Special(tokens, '(');
01341 
01342    if (binary_op)
01343    {
01344       opnd_tokens = 
01345          WN2C_Translate_Arithmetic_Operand(wn0, wn0_ty, context);
01346       Append_And_Reclaim_Token_List(tokens, &opnd_tokens);
01347    }
01348        
01349    /* Operation */
01350    for (op_char = WN2C_Opc2cname[opcode]; *op_char != '\0'; op_char++)
01351       Append_Token_Special(tokens, *op_char);
01352 
01353    /* Second operand, or only operand for unary operation */
01354    opnd_tokens = WN2C_Translate_Arithmetic_Operand(wn1, wn1_ty, context);
01355    Append_And_Reclaim_Token_List(tokens, &opnd_tokens);
01356 
01357    if (!top_level_expr)
01358       Append_Token_Special(tokens, ')');
01359    
01360    return EMPTY_STATUS;
01361 } /* WN2C_infix_op */
01362 
01363 
01364 static STATUS
01365 WN2C_funcall_op(TOKEN_BUFFER tokens, 
01366                 OPCODE       opcode,
01367                 WN          *wn0, 
01368                 WN          *wn1, 
01369                 CONTEXT      context)
01370 {
01371    /* This is assumed to be a binary operator, unless wn0==NULL,
01372     * in which case we treat it as a unary operator.  The operator
01373     * will be applied as a function/macro call and is viewed as a
01374     * string token.
01375     */
01376    const TY_IDX result_ty = Stab_Mtype_To_Ty(OPCODE_rtype(opcode));
01377    TY_IDX       descriptor_ty = Stab_Mtype_To_Ty(OPCODE_desc(opcode));
01378    const BOOL   binary_op = (wn0 != NULL);
01379    TOKEN_BUFFER opnd_tokens;
01380 
01381    /* ASHR may appear here, and may part of a ptr-diff.  Treat
01382     * it specially here.
01383     */
01384    if (binary_op && WN2C_is_pointer_diff(opcode, wn0, wn1))
01385       return WN2C_infix_op(tokens, opcode, result_ty, wn0, wn1, context);
01386 
01387    CONTEXT_reset_needs_lvalue(context); /* Need actual value of subexprs */
01388 
01389    /* If there is no descriptor type, assume the operands should be
01390     * of the same type as the result.
01391     */
01392    if (TY_kind(descriptor_ty) == KIND_VOID)
01393       descriptor_ty = result_ty;
01394    
01395    /* Operator */
01396    Append_Token_String(tokens, WN2C_Opc2cname[opcode]);
01397 
01398    CONTEXT_set_top_level_expr(context);
01399    Append_Token_Special(tokens, '(');
01400 
01401    /* First operand */
01402    if (binary_op)
01403    {
01404       opnd_tokens = 
01405          WN2C_Translate_Arithmetic_Operand(wn0, descriptor_ty, context);
01406       Append_And_Reclaim_Token_List(tokens, &opnd_tokens);
01407       Append_Token_Special(tokens, ',');
01408    }
01409 
01410    /* Second operand, or only operand for unary operation */
01411    opnd_tokens =
01412       WN2C_Translate_Arithmetic_Operand(wn1, descriptor_ty, context);
01413    Append_And_Reclaim_Token_List(tokens, &opnd_tokens);
01414 
01415    Append_Token_Special(tokens, ')');
01416    
01417    return EMPTY_STATUS;
01418 } /* WN2C_funcall_op */
01419 
01420 
01421 static TY_IDX
01422 WN2C_MemAccess_Type(TY_IDX      base_ty,
01423                     TY_IDX      load_ty,
01424                     MTYPE       load_mtype,
01425                     STAB_OFFSET offset)
01426 {
01427    /* Return the type of an object to be loaded/stored at the given
01428     * offset from a base object of type base_ty.  
01429     *
01430     * Should the load_ty be compatible with the base_ty, or should
01431     * the base_ty not be a struct, then just return the base_ty; otherwise,
01432     * if the base_ty is a struct, and a field is found at the given
01433     * offset of the load_ty or load_mtype, then return the FLD_type; 
01434     * Otherwise we have an unexpected case: If the base_ty has the
01435     * same size as the load_mtype, then return the base_ty; otherwise
01436     * otherwise return the load_ty.  
01437     *
01438     * This routine is made as general as possible, to handle all the
01439     * typing issues that may conceivably be encountered for loads and
01440     * stores.
01441     */
01442    TY2C_FLD_INFO fld_info;
01443 
01444    if (TY_Is_Array(base_ty))
01445    {
01446       /* Usually we do not access an array, but instead we access an element
01447        * of an array.  Use the load_ty, even if this also is an array (in
01448        * which case we are taking the address of an array?).
01449        */
01450       return load_ty;
01451    }
01452    else if (!TY_Is_Structured(base_ty) || 
01453             WN2C_compatible_lvalues(load_ty, base_ty))
01454    {
01455       return base_ty;
01456    }
01457    else
01458    {
01459       /* May be accessing an element in a struct */
01460       fld_info = TY2C_get_field_info(base_ty, 
01461                                      load_ty, 
01462                                      load_mtype,
01463                                      offset);
01464       if (!fld_info.found_fld.Is_Null ())
01465       {
01466          Reclaim_Token_Buffer(&fld_info.select_tokens);
01467          return FLD_type(fld_info.found_fld);
01468       }
01469       else if (Stab_Mtype_To_Ty(load_mtype) != (TY_IDX) 0 &&
01470                TY_size(Stab_Mtype_To_Ty(load_mtype)) == TY_size(base_ty))
01471       {
01472          return base_ty; 
01473       }
01474       else
01475       {
01476          return load_ty;
01477       }
01478    }
01479 } /* WN2C_MemAccess_Type */
01480 
01481 
01482 static void
01483 WN2C_SymAccess_Type(TY_IDX     *base_addr_ty,
01484                     TY_IDX     *object_ty,
01485                     TY_IDX      base_ty,
01486                     TY_IDX      load_ty,
01487                     MTYPE       load_mtype,
01488                     STAB_OFFSET offset)
01489 {
01490    /* Return the type of an object_ty to be loaded/stored at the given
01491     * offset from a base object of type base_ty.  Since this is a
01492     * symbol access (LDID or STID) we do not have direct access to the
01493     * type of address at which to load/store, so we also derive that
01494     * here.  The address must observe the qualifiers (volatiles) of 
01495     * the load_ty.  When this routine returns:
01496     *
01497     *    !WN2C_compatible_lvalues(base_addr_ty, Stab_Pointer_To(base_ty))
01498     *
01499     * this implies that the lvalue of the symbol must be cast to a
01500     * different address-type (base_addr_ty) before the load can occur.
01501     * 
01502     * Otherwise, this routine is similar to the routine used for general
01503     * indirect loads and stores.
01504     */
01505    TY2C_FLD_INFO fld_info;
01506    TY_IDX        actual_loaded_ty = Stab_Mtype_To_Ty(load_mtype);
01507 
01508    if (TY_Is_Array(base_ty) &&
01509        WN2C_compatible_lvalues(load_ty, TY_AR_etype(base_ty)))
01510    {
01511       /* Accessing an element in an array */
01512       *object_ty = load_ty;
01513       if (TY_is_volatile(TY_AR_etype(base_ty)) == TY_is_volatile(load_ty))
01514          *base_addr_ty = Stab_Pointer_To(base_ty);
01515       else
01516          *base_addr_ty = Stab_Pointer_To(load_ty);
01517    } 
01518    else if (!TY_Is_Structured(base_ty) || 
01519             WN2C_compatible_lvalues(load_ty, base_ty))
01520    {
01521       /* Seemingly interchangable types */
01522       if (actual_loaded_ty != (TY_IDX) 0                      &&
01523           !WN2C_compatible_lvalues(actual_loaded_ty, load_ty) &&
01524           WN2C_compatible_lvalues(actual_loaded_ty, base_ty))
01525       {
01526          /* This should never really happen, but to ensure graceful recovery
01527           * with continued code-generation we just emit what seems most
01528           * sensible. This is a WHIRL BUG?
01529           */
01530          *object_ty = base_ty;
01531          *base_addr_ty = Stab_Pointer_To(base_ty);
01532       }
01533       else // Normal case
01534       {
01535          *object_ty = load_ty;
01536          if (TY_is_volatile(base_ty) == TY_is_volatile(load_ty))
01537             *base_addr_ty = Stab_Pointer_To(base_ty);
01538          else
01539             *base_addr_ty = Stab_Pointer_To(load_ty);
01540       }
01541    }
01542    else
01543    {
01544       /* May be accessing an element in a struct */
01545       fld_info = TY2C_get_field_info(base_ty, 
01546                                      load_ty, 
01547                                      load_mtype,
01548                                      offset);
01549       if (!fld_info.found_fld.Is_Null ())
01550       {
01551          const TY_IDX ftype = FLD_type(fld_info.found_fld);
01552 
01553          Reclaim_Token_Buffer(&fld_info.select_tokens);
01554          if (WN2C_compatible_lvalues(load_ty, ftype) &&
01555              TY_is_volatile(ftype) == TY_is_volatile(load_ty))
01556          {
01557             *object_ty = ftype;
01558             *base_addr_ty = Stab_Pointer_To(base_ty);
01559          }
01560          else
01561          {
01562             *object_ty = load_ty;
01563             *base_addr_ty = Stab_Pointer_To(load_ty);
01564          }
01565       }
01566       else if (actual_loaded_ty != (TY_IDX) 0                &&
01567                TY_size(actual_loaded_ty) == TY_size(base_ty) &&
01568                TY_is_volatile(base_ty) == TY_is_volatile(load_ty))
01569       {
01570          /* This should never really happen, but to ensure graceful recovery
01571           * with continued code-generation we just emit what seems most
01572           * sensible.
01573           */
01574          *object_ty = base_ty;
01575          *base_addr_ty = Stab_Pointer_To(base_ty);
01576       }
01577       else
01578       {
01579          /* This should never really happen, but to ensure graceful recovery
01580           * with continued code-generation we just emit what seems most
01581           * sensible.
01582           */
01583          *object_ty = load_ty;
01584          *base_addr_ty = Stab_Pointer_To(load_ty);
01585       }
01586    }
01587 } /* WN2C_SymAccess_Type */
01588 
01589 
01590 
01591 static void
01592 WN2C_append_addr_plus_const(TOKEN_BUFFER tokens, /* Base address expression */
01593                             INT64        element_size,
01594                             STAB_OFFSET  byte_offset)
01595 {
01596    /* Generate an address expression as follows:
01597     *
01598     *   <tokens> + byte_offset/element_size
01599     *
01600     * We assume the byte_offset is non-zero and an exact multiple of the 
01601     * element_size.
01602     */
01603     if (element_size == 0) {
01604       /* this is a KLUDGE, please fix this right.
01605          for now, with void *, the size of void is null so
01606          we fake it with element_size
01607        */
01608       element_size = 1;
01609    }
01610    Is_True(element_size!=0 && byte_offset!=0 && byte_offset%element_size==0,
01611            ("Illegal address increment in WN2C_addr_plus()"));
01612    
01613    Append_Token_Special(tokens, '+');
01614    TCON2C_translate(tokens, 
01615                     Host_To_Targ(MTYPE_I8, byte_offset/element_size));
01616    WHIRL2C_parenthesize(tokens);
01617 } /* WN2C_append_addr_plus_const */
01618 
01619 
01620 static void
01621 WN2C_append_addr_plus_expr(TOKEN_BUFFER tokens, /* Base address expression */
01622                            INT64        element_size,
01623                            TOKEN_BUFFER *byte_offset)
01624 {
01625    /* Generate an address expression as follows:
01626     *
01627     *   <tokens> + byte_offset/element_size
01628     *
01629     * We assume the byte_offset is an exact multiple of the 
01630     * element_size.
01631     */
01632    Is_True(element_size!=0,
01633            ("Illegal element size in WN2C_addr_plus()"));
01634    
01635    Append_Token_Special(tokens, '+');
01636    Append_And_Reclaim_Token_List(tokens, byte_offset);
01637    if (element_size != 1)
01638    {
01639       Append_Token_Special(tokens, '/');
01640       TCON2C_translate(tokens, Host_To_Targ(MTYPE_I8, element_size));
01641    }
01642    WHIRL2C_parenthesize(tokens);
01643 } /* WN2C_append_addr_plus_expr */
01644 
01645 
01646 static STATUS
01647 WN2C_based_lvalue(TOKEN_BUFFER expr_tokens,    /* lvalue or addr expr */
01648                   BOOL         expr_is_lvalue, /* an lvalue expr? */
01649                   TY_IDX       expr_ty,        /* type of expr */
01650                   TY_IDX       addr_ty,        /* type of base of object */
01651                   TY_IDX       object_ty,      /* type of object */
01652                   STAB_OFFSET  addr_offset)    /* offset of object from base */
01653 {
01654    /* This function takes an address (or lvalue) expression, and
01655     * adds in a given offset doing type conversions as is necessary
01656     * based on mismatches between the three types passed in.  We use
01657     * field-selection ('.' or '->') instead of casting and/or offset 
01658     * calculations whenever possible.  The resultant value in 
01659     * expr_tokens should either be an lvalue of type object_ty, or
01660     * an address value of type (object_ty *).
01661     *
01662     * At the various stages of this function, we update the local
01663     * state to reflect what is currently represented in expr_tokens.
01664     * This implementation detail makes it easier to assert about
01665     * what is the current state, and aids both the readability and
01666     * debuggability of this function.
01667     *
01668     * The returned status information indicates whether the resultant
01669     * expression denotes an (addressable) lvalue or not.
01670     */
01671    STATUS        status = EMPTY_STATUS;
01672    BOOL          incompat_addr_tys; /* expr_ty   vs addr_ty */
01673    BOOL          incompat_obj_tys;  /* object_ty vs TY_pointed(addr_ty) */
01674    TY_IDX        base_obj_ty;
01675    TY2C_FLD_INFO field_info;
01676    field_info.select_tokens = NULL;
01677    field_info.found_fld = FLD_HANDLE();
01678 
01679    /* PRECONDITION: */
01680    Is_True(expr_ty   != (TY_IDX) 0 &&
01681            addr_ty   != (TY_IDX) 0 && TY_Is_Pointer(addr_ty) &&
01682            object_ty != (TY_IDX) 0,
01683            ("Expected non-null types in WN2C_based_lvalue()"));
01684 
01685    /* Determine type compatibility between the expression type (expr_ty),
01686     * its expected type (addr_ty), and the type of object being accessed
01687     * object_ty.  While the addr_ty must be a pointer type, the expr_ty
01688     * may be any value that may be casted to a pointer type.
01689     */
01690    base_obj_ty = TY_pointed(addr_ty);
01691    incompat_addr_tys = !WN2C_assignment_compatible_types(addr_ty, expr_ty);
01692    incompat_obj_tys = !WN2C_compatible_lvalues(object_ty, base_obj_ty);
01693 
01694    /* Correct the address of the base object, if necessary.  Note that
01695     * we permit any kind of expr_ty, while the addr_ty must always be
01696     * a pointer type.
01697     */
01698    if (incompat_addr_tys)
01699    {
01700       if (WN2C_array_lvalue_as_ptr(expr_ty,  /* ptr to array */
01701                                    addr_ty)) /* ptr to etype */
01702       {
01703          /* Note that an lvalue of an array is interpreted in C as a
01704           * pointer to the array element type, so no cast is necessary
01705           * once these types are compatible.  We no longer consider
01706           * this an lvalue, since the caller of this routine should not
01707           * take the address of the result to get the address value.
01708           */
01709       }
01710       else
01711       {
01712          /* Cast the address value to the appropriate pointer type */
01713          if (expr_is_lvalue)
01714          {
01715             Prepend_Token_Special(expr_tokens, '&');
01716          }
01717          WN2C_prepend_cast(expr_tokens, addr_ty, FALSE/*ptr_to_type*/);
01718          WHIRL2C_parenthesize(expr_tokens);
01719       } /* if (treat-array-as-pointer) */
01720 
01721       /* Update status */
01722       expr_is_lvalue = FALSE;
01723       expr_ty = addr_ty;
01724       incompat_addr_tys = FALSE;
01725    }
01726    else if (WN2C_array_lvalue_as_ptr(addr_ty,            /* ptr to array */
01727                                      Stab_Pointer_To(object_ty))) /* ptr */
01728    {
01729       /* An array lvalue is to be interpreted in C as a pointer to 
01730        * the array element type, so no cast is necessary
01731        * once these types are compatible.  We no longer consider
01732        * this an lvalue, since the caller of this routine should not
01733        * take the address of the result to get the address value.
01734        */
01735       expr_is_lvalue = FALSE;
01736       expr_ty = addr_ty = Stab_Pointer_To(object_ty);
01737       base_obj_ty = object_ty;
01738       incompat_obj_tys = FALSE;
01739    } /* if (incompat_addr_tys) */
01740 
01741    /* Update status */
01742    expr_ty = addr_ty;
01743    incompat_addr_tys = FALSE;
01744 
01745    /* Determine whether or not the object type is a field in a 
01746     * struct/class/union at the given offset, in which case we
01747     * should use field-selection instead of an offset calculation.
01748     */
01749    if (incompat_obj_tys && TY_Is_Structured(base_obj_ty))
01750    {
01751       field_info =
01752          TY2C_get_field_info(base_obj_ty, 
01753                              object_ty, 
01754                              TY_mtype(object_ty), 
01755                              addr_offset);
01756    }
01757 
01758    /* Finally, get the address or lvalue corresponding to the object_ty
01759     * and addr_offset.
01760     */
01761    if (!field_info.found_fld.Is_Null ())
01762    {
01763       WHIRL2C_parenthesize(expr_tokens);
01764       if (expr_is_lvalue)
01765          Append_Token_Special(expr_tokens, '.');
01766       else
01767          Append_Token_String(expr_tokens, "->");
01768       Append_And_Reclaim_Token_List(expr_tokens, &field_info.select_tokens);
01769       expr_is_lvalue = TRUE;
01770    }
01771    else if (addr_offset != (STAB_OFFSET) 0 || incompat_obj_tys)
01772    {
01773       if (expr_is_lvalue)
01774          Prepend_Token_Special(expr_tokens, '&');
01775 
01776       if (addr_offset != 0 && TY_size(object_ty) != 0 && addr_offset%TY_size(object_ty) != 0)
01777       {
01778          /* Use cast and pointer arithmetics to give us:
01779           *
01780           *   (object_ty *)((char *)&<expr_tokens> + addr_offset)
01781           */
01782          WN2C_prepend_cast(expr_tokens, 
01783                            Stab_Mtype_To_Ty(MTYPE_I1), 
01784                            TRUE/*ptr_to_type*/);
01785          WHIRL2C_parenthesize(expr_tokens);
01786          WN2C_append_addr_plus_const(expr_tokens, 
01787                                      TY_size(Stab_Mtype_To_Ty(MTYPE_I1)),
01788                                      addr_offset);
01789          WN2C_prepend_cast(expr_tokens, object_ty, TRUE/*ptr_to_type*/);
01790       }
01791       else
01792       {
01793          /* Use cast and pointer arithmetics to give us:
01794           *
01795           *   (object_ty *)&<expr_tokens> + addr_offset/sizeof(object_ty)
01796           */
01797         //if (incompat_obj_tys && !expr_is_lvalue)
01798         if (incompat_obj_tys)
01799          {
01800             WHIRL2C_parenthesize(expr_tokens);
01801 
01802             WN2C_prepend_cast(expr_tokens, object_ty, TRUE/*ptr_to_type*/);
01803          }
01804 
01805          if (addr_offset != 0)
01806             WN2C_append_addr_plus_const(expr_tokens, 
01807                                         TY_size(object_ty), 
01808                                         addr_offset);
01809       }
01810       expr_is_lvalue = FALSE;
01811    } /* if (use-cast-and-ptr-arithmetics) */
01812 
01813    if (expr_is_lvalue)
01814       STATUS_set_lvalue(status);
01815    return status;
01816 } /* WN2C_based_lvalue */
01817 
01818 
01819 static STATUS
01820 WN2C_lvalue_st(TOKEN_BUFFER tokens,
01821                const ST    *st,          /* Base symbol for lvalue */
01822                TY_IDX       addr_ty,     /* Type of base object */
01823                TY_IDX       object_ty,   /* Type of object */
01824                STAB_OFFSET  addr_offset, /* Offset of object from base */
01825                CONTEXT      context)
01826 {
01827    /* PRECONDITION: tokens is an empty initialized buffer.
01828     *
01829     * Translate an object reference based at the given ST into
01830     * a C lvalue or an address expression, putting tokens into "tokens".
01831     * Return with STATUS_is_lvalue when the resultant expression is a 
01832     * true addressable lvalue, rather than an address calculation.
01833     *
01834     * When we return with STATUS_is_lvalue, the caller must prepend
01835     * the '&' operator to get the address of the value.  When we
01836     * return with !STATUS_is_lvalue, the caller must prepend the
01837     * '*' operator to access the value of the address.
01838     */
01839    STATUS status;
01840    TY_IDX base_ptr_ty;
01841 
01842    Is_True(ST_sym_class(st) != CLASS_PREG, 
01843            ("Did not expect a preg in WN2C_lvalue_st()"));
01844 
01845    if (ST_sym_class(st) == CLASS_CONST)
01846    {
01847       TCON2C_translate(tokens, STC_val(st));
01848       status = EMPTY_STATUS; /* not an lvalue */
01849    } else if (Compile_Upc && strcmp(ST_name(st), "MYTHREAD") == 0) {
01850      //WEI: treat them specially since they can be used either with U4 or I4
01851      Append_Token_String(tokens, WN_intrinsic_name(INTRN_MYTHREAD));
01852      Append_Token_String(tokens, "()");
01853      STATUS_set_lvalue(status);
01854    } else if (Compile_Upc && strcmp(ST_name(st), "THREADS") == 0) {
01855      Append_Token_String(tokens, WN_intrinsic_name(INTRN_THREADS));
01856      Append_Token_String(tokens, "()");
01857      STATUS_set_lvalue(status);
01858    } else
01859      {
01860       /* Get the variable name */
01861       if (Stab_Is_Based_At_Common_Or_Equivalence(st))
01862       {
01863          addr_offset += ST_ofst(st);
01864          st = ST_base(st);
01865          addr_ty = Stab_Pointer_To(ST_type(st));
01866       }
01867 
01868       if (ST_is_split_common(st))
01869       {
01870          addr_offset += Stab_Full_Split_Offset(st);
01871          st = ST_full(st);
01872          addr_ty = Stab_Pointer_To(ST_type(st));
01873       }
01874 
01875       ST2C_use_translate(tokens, st, context);
01876       base_ptr_ty = Stab_Pointer_To(ST_sym_class(st) == CLASS_FUNC ?
01877                                                  ST_pu_type(st) : ST_type(st));
01878 
01879       /* Get the object as an lvalue or as an address expression.
01880        */
01881       status = WN2C_based_lvalue(tokens,      /* base variable name */
01882                                  TRUE,        /* tokens represent an lvalue */
01883                                  base_ptr_ty, /* type of base variable addr */
01884                                  addr_ty,     /* expected type of base addr */
01885                                  object_ty,   /* expected type of object */
01886                                  addr_offset);/* offset of object from base */
01887    }
01888    return status;
01889 } /* WN2C_lvalue_st */
01890 
01891 
01892 static STATUS
01893 WN2C_lvalue_wn(TOKEN_BUFFER tokens,
01894                const WN    *wn,          /* Base address for lvalue */
01895                TY_IDX       addr_ty,     /* Type of base address */
01896                TY_IDX       object_ty,   /* Type of object to be loaded */
01897                STAB_OFFSET  addr_offset, /* Offset of object from base */
01898                CONTEXT      context)
01899 {
01900    /* PRECONDITION: tokens is an empty initialized buffer.
01901     *
01902     * Translate an object reference based at the given WN tree into
01903     * a C lvalue or an address expression, putting tokens into "tokens".
01904     * Return with STATUS_is_lvalue when the resultant expression is a 
01905     * true addressable lvalue, rather than an address calculation.
01906     *
01907     * When we return with STATUS_is_lvalue, the caller must prepend
01908     * the '&' operator to get the address of the value.  When we
01909     * return with !STATUS_is_lvalue, the caller must prepend the
01910     * '*' operator to access the value of the address.
01911     */
01912    STATUS status;
01913    TY_IDX tree_type = WN_Tree_Type(wn);
01914 
01915    /* Always try to get an lvalue representation for the address 
01916     * expression.
01917     */
01918    CONTEXT_set_needs_lvalue(context);
01919    CONTEXT_reset_top_level_expr(context);
01920    if (WN_operator(wn) == OPR_ARRAY)
01921    {
01922       TY_IDX array_base_ty = WN_Tree_Type(WN_kid0(wn));
01923 
01924       if (!TY_Is_Pointer(array_base_ty))
01925       {
01926          /* A special case, which we handle but perhaps it should 
01927           * be considered an error:  The array base is not a pointer
01928           * type.
01929           */
01930          CONTEXT_set_array_basetype(context);
01931          CONTEXT_set_given_base_ty(context, addr_ty);
01932          tree_type = addr_ty;
01933       }
01934    }
01935    else if (WN_operator(wn) == OPR_ADD &&
01936             TY_Is_Pointer(tree_type)       &&
01937             WN_Get_PtrAdd_Intconst(WN_kid0(wn), 
01938                                    WN_kid1(wn), 
01939                                    TY_pointed(tree_type)) == NULL)
01940    {
01941       /* An add representing a struct field selection or an array 
01942        * element indexing operation.  Go straight for the object type
01943        * (with potentially ugly code).  See WN2C_address_add() for
01944        * details.
01945        */
01946       CONTEXT_set_lvalue_type(context);
01947       CONTEXT_set_given_lvalue_ty(context, object_ty);
01948       addr_ty = tree_type = Stab_Pointer_To(object_ty);
01949    }
01950 
01951    status = WN2C_translate(tokens, wn, context);
01952 
01953    /* Get the object as an lvalue or as an address expression.
01954     */
01955    status = WN2C_based_lvalue(tokens,       /* base expression */
01956                               STATUS_is_lvalue(status),
01957                                             /* tokens represent an lvalue */
01958                               tree_type,    /* type of base expression */
01959                               addr_ty,      /* expected type of base address */
01960                               object_ty,    /* expected type of object */
01961                               addr_offset); /* offset of object from base */
01962 
01963    return status;
01964 } /* WN2C_lvalue_wn */
01965 
01966 
01967 static void 
01968 WN2C_create_ref_param_lda(WN *lda, const WN *ldid)
01969 {
01970    const TY_IDX lhs_addr_ty = Stab_Pointer_To(WN_ty(ldid));
01971 
01972    bzero(lda, sizeof(WN));
01973    WN_set_opcode(lda, OPCODE_make_op(OPR_LDA, TY_mtype(lhs_addr_ty), MTYPE_V));
01974    WN_set_kid_count(lda, 0);
01975    WN_map_id(lda)      = (WN_MAP_ID) (-1);
01976    WN_load_offset(lda) = 0;
01977    WN_st_idx(lda)      = WN_st_idx(ldid);
01978    WN_set_ty(lda, lhs_addr_ty);
01979 } /* WN2C_create_ref_param_lda */
01980 
01981 
01982 static void 
01983 WN2C_Append_Preg(TOKEN_BUFFER tokens, 
01984                  const ST    *st,       /* preg */
01985                  PREG_IDX     preg_idx, /* preg index */
01986                  TY_IDX       ty,       /* desired type */
01987                  CONTEXT      context)
01988 {
01989    /* Given a preg (st, idx), append an expression referencing the preg
01990     * as the desired type to the token list.
01991     */
01992    TY_IDX       preg_ty;
01993    TOKEN_BUFFER preg_tokens;
01994    
01995    Is_True(ST_sym_class(st) == CLASS_PREG, 
01996            ("Expected preg in WN2C_Append_Preg()"));
01997    
01998    /* Put the name of the preg into the preg_tokens */
01999    preg_tokens = New_Token_Buffer();
02000    preg_ty = PUinfo_Preg_Type(ST_type(st), preg_idx);
02001    ST2C_Use_Preg(preg_tokens, preg_ty, preg_idx, context);
02002    
02003    /* If the preg is declared with a btype different from that of
02004     * a pointer type, then cast it to an integral type with the
02005     * pointer btype, before casting it to the pointer type.
02006     */
02007    if (TY_Is_Pointer(ty) && TY_mtype(ty) != TY_mtype(preg_ty))
02008    {
02009       WN2C_prepend_cast(preg_tokens, 
02010                         Stab_Mtype_To_Ty(TY_mtype(ty)), 
02011                         FALSE/*ptr_to_type*/);
02012    }
02013    
02014    /* Now cast the preg to the appropriate type, unless the preg
02015     * is already arithmetically compatible with the desired type.
02016     */
02017    if (!WN2C_arithmetic_compatible_types(preg_ty, ty))
02018       WN2C_prepend_cast(preg_tokens, ty, FALSE/*ptr_to_type*/);
02019 
02020    Append_And_Reclaim_Token_List(tokens, &preg_tokens);
02021 } /* WN2C_Append_Preg */
02022 
02023 
02024 static void
02025 WN2C_Load_From_PregIdx(TOKEN_BUFFER tokens,
02026                        const ST    *preg1,     /* Base address preg */
02027                        PREG_IDX     preg_idx1, 
02028                        const ST    *preg2,     /* Byte offset preg */
02029                        PREG_IDX     preg_idx2,
02030                        TY_IDX       object_ty,
02031                        CONTEXT      context)
02032 {
02033    /* Load the contents of the pregs, add them together, cast the 
02034     * resultant address to a pointer to object_ty, and dereference.
02035     */
02036    TOKEN_BUFFER base_buffer, offset_buffer;
02037 
02038    /* Get the base address into which we are storing, as a pointer,
02039     * and cast it to a pointer to a character.
02040     */
02041    base_buffer = New_Token_Buffer();
02042    WN2C_Append_Preg(base_buffer, 
02043                     preg1, 
02044                     preg_idx1, 
02045                     Stab_Pointer_To(Stab_Mtype_To_Ty(MTYPE_U1)),
02046                     context);
02047    
02048    /* Get the offset value */
02049    offset_buffer = New_Token_Buffer();
02050    WN2C_Append_Preg(offset_buffer, 
02051                     preg2, 
02052                     preg_idx2, 
02053                     ST_type(preg2),
02054                     context);
02055 
02056    /* Add in the offset, giving us a parenthesized address expression. */
02057    WN2C_append_addr_plus_expr(base_buffer, 1/*byte size*/, &offset_buffer);
02058 
02059    /* Cast the resultant address to a pointer to the expected result
02060     * type, and dereference.
02061     */
02062    WN2C_prepend_cast(base_buffer, object_ty, TRUE/*pointer_to_type*/);
02063    Prepend_Token_Special(base_buffer, '*'); /* Dereference */
02064 
02065    Append_And_Reclaim_Token_List(tokens, &base_buffer);
02066 } /* WN2C_Load_From_PregIdx */
02067 
02068 
02069 static void
02070 WN2C_Append_Assignment(TOKEN_BUFFER  tokens, 
02071                        TOKEN_BUFFER *lhs_tokens, 
02072                        const WN     *rhs,
02073                        TY_IDX        assign_ty,
02074                        CONTEXT       context)
02075 {
02076    TOKEN_BUFFER rhs_buffer = New_Token_Buffer();
02077    TY_IDX       rhs_ty = WN_Tree_Type(rhs);
02078 
02079    if (WN_operator(rhs) == OPR_LDID || WN_operator(rhs) == OPR_ILOAD) {
02080      if (WN_field_id(rhs) != 0 && TY_kind(rhs_ty) == KIND_STRUCT) {
02081        rhs_ty = Get_Field_Type(rhs_ty, WN_field_id(rhs));
02082      }
02083    }
02084    //cout << "TYPE ASSIGNED TO: " << assign_ty << endl;
02085    /* Get the rhs expression */
02086    if (!WN2C_assignment_compatible_types(assign_ty, rhs_ty))
02087    {
02088       if (!TY_Is_Structured(assign_ty) && !TY_Is_Structured(rhs_ty))
02089       {
02090          (void)WN2C_translate(rhs_buffer, rhs, context);
02091          WHIRL2C_parenthesize(rhs_buffer);
02092          WN2C_prepend_cast(rhs_buffer,
02093                            assign_ty,
02094                            FALSE/*pointer_to_type*/);
02095       }
02096       else
02097       {
02098          /* Assign the rhs to a temporary, cast the address of the
02099           * temporary to the assign_ty, then dereference.
02100           */
02101          const UINT  tmp_idx = Stab_Lock_Tmpvar(rhs_ty, 
02102                                                 ST2C_Declare_Tempvar);
02103          const char *tmpvar_name = W2CF_Symtab_Nameof_Tempvar(tmp_idx);
02104          
02105          /* Assign rhs to temporary */
02106          Append_Token_String(tokens, tmpvar_name);
02107          Append_Token_Special(tokens, '=');
02108          (void)WN2C_translate(tokens, rhs, context);
02109          Append_Token_Special(tokens, ';');
02110          WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
02111 
02112          /* Rhs is the dereferenced casted temporary */
02113          Append_Token_Special(rhs_buffer, '&');
02114          Append_Token_String(rhs_buffer, tmpvar_name);
02115          WN2C_prepend_cast(rhs_buffer,
02116                            assign_ty,
02117                            TRUE/*pointer_to_type*/);
02118          Prepend_Token_Special(rhs_buffer, '*');
02119          Stab_Unlock_Tmpvar(tmp_idx);
02120       }
02121    }
02122    else
02123    {
02124       (void)WN2C_translate(rhs_buffer, rhs, context);
02125    }
02126    
02127    /* Wrap it up by assigning the rhs to the lhs */
02128    Append_And_Reclaim_Token_List(tokens, lhs_tokens);
02129    Append_Token_Special(tokens, '=');
02130    Append_And_Reclaim_Token_List(tokens, &rhs_buffer);
02131 } /* WN2C_Append_Assignment */
02132 
02133 
02134 static void
02135 WN2C_Normalize_Idx_To_Onedim(TOKEN_BUFFER tokens, 
02136                              const WN    *wn,
02137                              CONTEXT      context)
02138 {
02139    /* Express a multidimensional array index as a one-dimensional
02140     * array index.  The resulting expression denotes the offset into
02141     * an array in terms of number of elements.
02142     */
02143    static char  dim_string[128];
02144    char        *dim_stringp = &dim_string[0];
02145    INT32        dim1, dim2;
02146  
02147    for (dim1 = 0; dim1 < WN_num_dim(wn); dim1++)
02148    {
02149       if (dim1 > 0)
02150          Append_Token_Special(tokens, '+');
02151 
02152       /* Multiply the index expression with the product of the sizes
02153        * of subordinate dimensions, where a higher dimension-number
02154        * means a more subordinate dimension.  Do not parenthesize the
02155        * least significant index expression.
02156        */   
02157       if (dim1+1 == WN_num_dim(wn))
02158          CONTEXT_set_top_level_expr(context);
02159       (void)WN2C_translate(tokens, WN_array_index(wn, dim1), context);
02160       for (dim2 = dim1+1; dim2 < WN_num_dim(wn); dim2++)
02161       {
02162          Append_Token_Special(tokens, '*');
02163          (void)WN2C_translate(tokens, WN_array_dim(wn, dim2), context);
02164       } /*for*/
02165 
02166       if (W2C_Emit_Adims)
02167       {
02168          /* Indicate in the output which dimension this is */
02169          sprintf(dim_stringp, "/*Dim%d*/", WN_num_dim(wn)-dim1);
02170          Append_Token_String(tokens, dim_stringp);
02171       }
02172    } /*for*/
02173 
02174 } /* WN2C_Normalize_Idx_To_Onedim */
02175 
02176 
02177 static void
02178 WN2C_append_label_name(TOKEN_BUFFER tokens, const WN *wn)
02179 {
02180    /* There is no way to restore user-defined label names, so just use
02181     * the compiler generated numbers, prefixed by an underscore.
02182     */
02183    Append_Token_String(tokens, WHIRL2C_number_as_c_name(WN_label_number(wn)));
02184 } /* WN2C_append_label_name */
02185 
02186 
02187 
02188 
02189 static void
02190 WN2C_Append_Symtab_Types(TOKEN_BUFFER tokens, UINT lines_between_decls)
02191 {
02192    /* When "tokens" is NULL, we append the type declarations directly 
02193     * to the W2C_File[W2C_DOTH_FILE] (at file-level); otherwise, append them
02194     * them to the given token-list.
02195     */
02196    TY_IDX       ty,ty_idx;
02197    TOKEN_BUFFER tmp_tokens;
02198 
02199    //WEI: This code is obviously broken, but should we fix it?
02200    //FMZ: we fix the bug--June 30,2004
02201 
02202    /* Declare structure types. --*/
02203    for (ty = 1; ty < TY_Table_Size(); ty++)
02204    {
02205      ty_idx = ty<<8;
02206      if (TY_Is_Structured(ty_idx)       &&
02207          !TY_split(Ty_Table[ty_idx])    &&
02208          !TY_is_translated_to_c(ty_idx)  &&
02209           !Stab_Reserved_Ty(ty_idx))
02210       {
02211          tmp_tokens = New_Token_Buffer();
02212 
02213          Set_TY_is_written(ty_idx); 
02214          //this should  be done in frontend,will fix later--FMZ
02215 
02216 //       TY2C_translate_unqualified(tmp_tokens, ty);
02217          //misuse this ty as TY_IDX--FMZ
02218 
02219          TY2C_translate_unqualified(tmp_tokens, ty_idx);
02220 
02221 #if 0 //not correct code---FMZ
02222          Append_Token_Special(tmp_tokens, ';');
02223          Append_Indented_Newline(tmp_tokens, lines_between_decls);
02224          if (tokens != NULL)
02225             Append_And_Reclaim_Token_List(tokens, &tmp_tokens);
02226          else {
02227             Write_And_Reclaim_Tokens(W2C_File[W2C_DOTH_FILE], 
02228                                      NULL, /* No srcpos map */
02229                                      &tmp_tokens);
02230          }
02231 #endif
02232 
02233       }
02234    }
02235 }  /* WN2C_Append_Symtab_Types */
02236 
02237 
02238 static void
02239 WN2C_Append_Symtab_Consts(TOKEN_BUFFER tokens, 
02240                           BOOL         use_const_tab,
02241                           UINT         lines_between_decls,
02242                           CONTEXT      context)
02243 {
02244    /* When "tokens" is NULL, we append the consts directly to the
02245     * W2C_File[W2C_DOTH_FILE] (at file-level); otherwise, append
02246     * them to the given token-list.
02247     */
02248    const ST    *st;
02249    TOKEN_BUFFER tmp_tokens;
02250 
02251    /* Declare any STFL_IS_CONST_VAR variables */
02252    ST_IDX st_idx;
02253    FOREACH_SYMBOL(CURRENT_SYMTAB, st, st_idx)
02254    {
02255 //      if ((ST_sym_class(st) == CLASS_VAR && ST_is_const_var(st)) || 
02256 //        (ST_sym_class(st) == CLASS_CONST))
02257 // Only " ST_IS_CONST_VAR" need to be dumpout.
02258 // if "ST_sym_class(st) == CLASS_CONST",we never need to have explicit 
02259 // declaration for the symbol in unparsed code----fzhao
02260 
02261      if (ST_sym_class(st) == CLASS_VAR && ST_is_const_var(st)) 
02262      
02263       {
02264          tmp_tokens = New_Token_Buffer();
02265          ST2C_decl_translate(tmp_tokens, st, context);
02266          Append_Token_Special(tmp_tokens, ';');
02267          Append_Indented_Newline(tmp_tokens, lines_between_decls);
02268          if (tokens != NULL)
02269             Append_And_Reclaim_Token_List(tokens, &tmp_tokens);
02270          else {
02271            Write_And_Reclaim_Tokens(W2C_File[W2C_DOTH_FILE], 
02272                                     NULL, /* No srcpos map */
02273                                     &tmp_tokens);
02274          }
02275       }
02276    }
02277 } /* WN2C_Append_Symtab_Consts */
02278 
02279 struct eqstr
02280 {
02281   bool operator()(const char* s1, const char* s2) const
02282   {
02283     return strcmp(s1, s2) == 0;
02284   }
02285 };
02286 
02287 static hash_set<const char*, hash<const char*>, eqstr> upcr_internal;
02288 static bool init = false;
02289 
02290 static bool lookup(const char* s) {
02291   return upcr_internal.find(s) != upcr_internal.end(); 
02292 }
02293 
02294 static void init_map() {
02295   
02296   if (init) {
02297     return;
02298   }
02299 
02300   upcr_internal.clear();
02301 
02302   //initialize the table
02303   upcr_internal.insert("UPCR_LOCAL_ALLOC");
02304   upcr_internal.insert("UPCR_GLOBAL_ALLOC");
02305   upcr_internal.insert("UPCR_ALL_ALLOC");
02306   upcr_internal.insert("UPCR_FREE");
02307   upcr_internal.insert("UPCR_GLOBAL_LOCK_ALLOC");
02308   upcr_internal.insert("UPCR_ALL_LOCK_ALLOC");
02309   upcr_internal.insert("UPCR_LOCK");
02310   upcr_internal.insert("UPCR_LOCK_ATTEMPT");
02311   upcr_internal.insert("UPCR_UNLOCK");
02312   upcr_internal.insert("UPCR_LOCK_FREE");
02313   upcr_internal.insert("UPCR_PUT_SHARED");
02314   upcr_internal.insert("UPCR_PUT_PSHARED");
02315   upcr_internal.insert("UPCR_PUT_NB_SHARED");
02316   upcr_internal.insert("UPCR_PUT_NB_PSHARED");
02317   upcr_internal.insert("UPCR_GET_SHARED");
02318   upcr_internal.insert("UPCR_GET_NB_SHARED");
02319   upcr_internal.insert("UPCR_GET_PSHARED");
02320   upcr_internal.insert("UPCR_GET_NB_PSHARED");
02321   upcr_internal.insert("UPCR_WAIT_SYNCNB");
02322   upcr_internal.insert("UPCR_TRY_SYNCNB");
02323   upcr_internal.insert("UPCR_PUT_SHARED_VAL");
02324   upcr_internal.insert("UPCR_PUT_NB_SHARED_VAL");
02325   upcr_internal.insert("UPCR_PUT_PSHARED_VAL");
02326   upcr_internal.insert("UPCR_PUT_NB_PSHARED_VAL");
02327   upcr_internal.insert("UPCR_GET_SHARED_VAL");
02328   upcr_internal.insert("UPCR_GET_NB_SHARED_VAL");
02329   upcr_internal.insert("UPCR_GET_PSHARED_VAL");
02330   upcr_internal.insert("UPCR_GET_NB_PSHARED_VAL");
02331   upcr_internal.insert("UPCR_WAIT_SYNCNB_VALGET");
02332   upcr_internal.insert("UPCR_PUT_SHARED_FLOATVAL");
02333   upcr_internal.insert("UPCR_PUT_PSHARED_FLOATVAL");
02334   upcr_internal.insert("UPCR_PUT_SHARED_DOUBLEVAL");
02335   upcr_internal.insert("UPCR_PUT_PSHARED_DOUBLEVAL");
02336   upcr_internal.insert("UPCR_GET_SHARED_FLOATVAL");
02337   upcr_internal.insert("UPCR_GET_PSHARED_FLOATVAL");
02338   upcr_internal.insert("UPCR_GET_SHARED_DOUBLEVAL");
02339   upcr_internal.insert("UPCR_GET_PSHARED_DOUBLEVAL");
02340   upcr_internal.insert("UPCR_MEMGET");
02341   upcr_internal.insert("UPCR_MEMPUT");
02342   upcr_internal.insert("UPCR_MEMSET");
02343   upcr_internal.insert("UPCR_NB_MEMGET");
02344   upcr_internal.insert("UPCR_NB_MEMPUT");
02345   upcr_internal.insert("UPCR_NB_MEMSET");
02346   upcr_internal.insert("UPCR_MEMCPY");
02347   upcr_internal.insert("UPCR_NB_MEMCPY");
02348   upcr_internal.insert("UPCR_ISNULL_SHARED");
02349   upcr_internal.insert("UPCR_ISNULL_PSHARED");
02350   upcr_internal.insert("UPCR_SHARED_TO_LOCAL");
02351   upcr_internal.insert("UPCR_PSHARED_TO_LOCAL");
02352   upcr_internal.insert("UPCR_SHARED_TO_PSHARED");
02353   upcr_internal.insert("UPCR_PSHARED_TO_SHARED");
02354   upcr_internal.insert("UPCR_SHARED_RESETPHASE");
02355   upcr_internal.insert("UPCR_THREADOF_SHARED");
02356   upcr_internal.insert("UPCR_THREADOF_PSHARED");
02357   upcr_internal.insert("UPCR_PHASEOF_SHARED");
02358   upcr_internal.insert("UPCR_PHASEOF_PSHARED");
02359   upcr_internal.insert("UPCR_ADDRFIELD_SHARED");
02360   upcr_internal.insert("UPCR_ADDRFIELD_PSHARED");
02361   upcr_internal.insert("UPCR_ADD_SHARED");
02362   upcr_internal.insert("UPCR_ADD_PSHAREDI");
02363   upcr_internal.insert("UPCR_ADD_PSHARED1");
02364   upcr_internal.insert("UPCR_ISEQUAL_SHARED_SHARED");
02365   upcr_internal.insert("UPCR_ISEQUAL_SHARED_PSHARED");
02366   upcr_internal.insert("UPCR_ISEQUAL_PSHARED_PSHARED");
02367   upcr_internal.insert("UPCR_SUB_SHARED");
02368   upcr_internal.insert("UPCR_SUB_PSHAREDI");
02369   upcr_internal.insert("UPCR_SUB_PSHARED1");
02370   upcr_internal.insert("upcr_hasAffinity");
02371   upcr_internal.insert("upcr_barrier");
02372   
02373 
02374   init = true;
02375 }
02376 
02377 static void
02378 WN2C_Append_Symtab_Vars(TOKEN_BUFFER tokens, 
02379                         INT          lines_between_decls,
02380                         CONTEXT      context)
02381 {
02382    /* When "tokens" is NULL, we append the vars directly to the
02383     * W2C_File[W2C_DOTH_FILE] (at file-level); otherwise, append
02384     * them to the given token-list.
02385     */
02386    const ST    *st;
02387    TOKEN_BUFFER var_tokens;
02388    TOKEN_BUFFER func_tokens;
02389    TOKEN_BUFFER tmp_tokens;
02390    ST_IDX       st_idx;
02391 
02392    init_map();
02393    
02394    var_tokens = New_Token_Buffer();
02395    func_tokens = New_Token_Buffer();
02396 
02397    /* Declare identifiers from the new symbol table, provided they
02398     * represent functions or variables that are either defining
02399     * global definition or that have been referenced in this 
02400     * compilation unit.
02401     */
02402    FOREACH_SYMBOL(CURRENT_SYMTAB, st, st_idx)
02403    {
02404      //WEI: ignore static or global variables, since they're handled specially by the initialization script
02405      //For SCLASS_PSTATIC, we additionally check that the symbol name does not include ".init" (such name is 
02406      //reserved for temp symbols representing array initializers, and need to be outputed)
02407      bool global = ST_sym_class(st) == CLASS_VAR && 
02408        ((ST_sclass(st) == SCLASS_PSTATIC && strstr(ST_name(st), ".init") == NULL) ||
02409         ST_sclass(st) == SCLASS_FSTATIC || 
02410        ST_sclass(st) == SCLASS_UGLOBAL || ST_sclass(st) == SCLASS_DGLOBAL || 
02411        ST_sclass(st) == SCLASS_EXTERN || ST_sclass(st) == SCLASS_COMMON);
02412      //WEI: for testing, block all extern functions that returns void for now
02413      bool extern_void_fun = (ST_sym_class(st) == CLASS_FUNC && ST_sclass(st) == SCLASS_EXTERN); 
02414      extern_void_fun = extern_void_fun && (TY_mtype(TY_ret_type(ST_pu_type(st))) != MTYPE_F8);
02415      global = global || extern_void_fun;
02416 
02417      TY_IDX st_ty  = ST_class(st) == CLASS_VAR ? ST_type(st) :
02418        ST_class(st) == CLASS_FUNC ? ST_pu_type(st) : ST_type(st);
02419 //     cout << "For ST: " << ST_name(st) << " " << st_ty << " " << TY_name(st_ty) << endl;      
02420      if (!ST_is_not_used(st)                         &&
02421          ST_sclass(st) != SCLASS_FORMAL              && 
02422          ST_sclass(st) != SCLASS_FORMAL_REF          &&
02423          ((ST_sym_class(st) == CLASS_VAR && !ST_is_const_var(st)) || 
02424           ST_sym_class(st) == CLASS_FUNC)            &&
02425          !Stab_Reserved_St(st)                       &&
02426          !Stab_Is_Based_At_Common_Or_Equivalence(st) &&
02427          !Stab_Is_Common_Block(st)                   &&
02428          !Stab_Is_Equivalence_Block(st)              &&
02429          !global &&
02430          !(ST_sym_class(st) == CLASS_FUNC && lookup(ST_name(st))) &&
02431          (Stab_External_Def_Linkage(st)                        || 
02432           (ST_sym_class(st) == CLASS_VAR && ST_sclass(st) == SCLASS_CPLINIT) ||
02433           BE_ST_w2fc_referenced(st)) || 
02434           global )
02435        {
02436          tmp_tokens = New_Token_Buffer();
02437          if (ST_is_weak_symbol(st))
02438          {
02439             ST2C_weakext_translate(tmp_tokens, st, context);
02440          }
02441          else
02442          {
02443             ST2C_decl_translate(tmp_tokens, st, context);
02444             Append_Token_Special(tmp_tokens, ';');
02445          }
02446 
02447          Append_Indented_Newline(tmp_tokens, lines_between_decls);
02448 
02449          if (ST_sym_class(st) == CLASS_FUNC)
02450                Append_And_Reclaim_Token_List(func_tokens, &tmp_tokens);
02451          else
02452                Append_And_Reclaim_Token_List(var_tokens, &tmp_tokens);
02453 #if 0
02454          if (tokens != NULL)
02455              Append_And_Reclaim_Token_List(tokens, &tmp_tokens);
02456          else 
02457              Write_And_Reclaim_Tokens(W2C_File[W2C_DOTH_FILE], 
02458                                           NULL, /* No srcpos map */
02459                                           &tmp_tokens);
02460 #endif
02461          }
02462        
02463        }  /*FOREACH */
02464 
02465         if (tokens != NULL){
02466             if (func_tokens != NULL)
02467                   Append_And_Reclaim_Token_List(tokens, &func_tokens);
02468             if (var_tokens != NULL)
02469                   Append_And_Reclaim_Token_List(tokens, &var_tokens);
02470           }
02471          else {
02472             if (func_tokens != NULL)
02473                 Write_And_Reclaim_Tokens(W2C_File[W2C_DOTH_FILE],
02474                                           NULL, /* No srcpos map */
02475                                           &func_tokens);
02476              if (var_tokens != NULL)
02477                  Write_And_Reclaim_Tokens(W2C_File[W2C_DOTH_FILE],
02478                                           NULL, /* No srcpos map */
02479                                           &var_tokens);
02480             }
02481 
02482 } /* WN2C_Append_Symtab_Vars */
02483 
02484 
02485 static void
02486 WN2C_Declare_Return_Variable(TOKEN_BUFFER tokens)
02487 {
02488    /* Declare the return variable; i.e. a temporary variable to hold
02489     * the function return value.  This is necessary to unify a return
02490     * value split up between two return pseudo-registers.
02491     */
02492    TOKEN_BUFFER tmp_tokens;
02493 
02494    /* Declare a variable to hold the function return value */
02495    tmp_tokens = New_Token_Buffer();
02496    Append_Token_String(tmp_tokens, WN2C_Return_Value_Name);
02497    TY2C_translate_unqualified(tmp_tokens, PUINFO_RETURN_TY);
02498    Append_Token_Special(tmp_tokens, ';');
02499    Append_And_Reclaim_Token_List(tokens, &tmp_tokens);
02500 } /* WN2C_Declare_Return_Variable */
02501 
02502 
02503 static void
02504 WN2C_Declare_Return_Parameter(TOKEN_BUFFER tokens, CONTEXT context)
02505 {
02506    /* We are in the scope of a function that returns its value into
02507     * the location pointed to by its first (implicit) parameter.  We
02508     * do not want the parameter to be part of the function declaration,
02509     * and instead declare a local variable to represent the return value.
02510     * The declaration is local to the current_func in the given context.
02511     */
02512    
02513    /* First, declare a variable to hold the function return value */
02514    WN2C_Declare_Return_Variable(tokens);
02515    Append_Indented_Newline(tokens, 1);
02516 
02517    /* Next, declare the return parameter as a local variable, initialized
02518     * to point to the return value.
02519     */
02520    ST2C_decl_translate(tokens, PUINFO_RETURN_PARAM, context);
02521    Append_Token_Special(tokens, '=');
02522    Append_Token_Special(tokens, '&');
02523    Append_Token_String(tokens, WN2C_Return_Value_Name);
02524    Append_Token_Special(tokens, ';');
02525    Append_Indented_Newline(tokens, 1);
02526 } /* WN2C_Declare_Return_Parameter */
02527 
02528 
02529 static void
02530 WN2C_Store_Return_Reg(TOKEN_BUFFER tokens,
02531                       const char  *var_name,
02532                       STAB_OFFSET  var_offset,
02533                       MTYPE        preg_mtype,
02534                       PREG_IDX     preg_offset,
02535                       CONTEXT      context)
02536 {
02537    /* Store the preg value into the given variable at the given
02538     * offset.
02539     */
02540    const TY_IDX preg_ty = Stab_Mtype_To_Ty(preg_mtype);
02541    TOKEN_BUFFER tmp_tokens = New_Token_Buffer();
02542    STATUS       status = EMPTY_STATUS;
02543    
02544    /* Cast the lhs to the type of the preg, and dereference the
02545     * resultant address.
02546     */
02547    Append_Token_String(tmp_tokens, var_name);
02548    status = WN2C_based_lvalue(tmp_tokens,   /* base variable name */
02549                               TRUE,         /* tokens represent an lvalue */
02550                               Stab_Pointer_To(PUINFO_RETURN_TY),
02551                                             /* type of base address */
02552                               Stab_Pointer_To(PUINFO_RETURN_TY),
02553                                             /* expected type of base address */
02554                               preg_ty,      /* expected type of object */
02555                               var_offset);  /* offset of object from base */
02556 
02557    if (!STATUS_is_lvalue(status))
02558       Prepend_Token_Special(tmp_tokens, '*');
02559    Append_And_Reclaim_Token_List(tokens, &tmp_tokens);
02560    
02561    /* Assign the preg to the lhs */
02562    Append_Token_Special(tokens, '=');
02563    ST2C_Use_Preg(tokens, preg_ty, preg_offset, context);
02564    Append_Token_Special(tokens, ';');
02565    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
02566 } /* WN2C_Store_Return_Reg */
02567 
02568 
02569 static void
02570 WN2C_Load_Return_Reg(TOKEN_BUFFER tokens,
02571                      TY_IDX       return_ty,
02572                      const char  *var_name,
02573                      STAB_OFFSET  var_offset,
02574                      MTYPE        preg_mtype,
02575                      PREG_IDX     preg_offset,
02576                      CONTEXT      context)
02577 {
02578    /* Load a preg value from the given variable at the given offset
02579     * from the base-address of the variable.
02580     */
02581    const TY_IDX preg_ty = Stab_Mtype_To_Ty(preg_mtype);
02582    TOKEN_BUFFER tmp_tokens = New_Token_Buffer();
02583    STATUS       status = EMPTY_STATUS;
02584 
02585    /* Cast the rhs to the type of the preg, and dereference the
02586     * resultant address.
02587     */
02588    Append_Token_String(tmp_tokens, var_name);
02589    status = WN2C_based_lvalue(tmp_tokens,   /* base variable name */
02590                               TRUE,         /* tokens represent an lvalue */
02591                               Stab_Pointer_To(return_ty),
02592                                             /* type of base address */
02593                               Stab_Pointer_To(return_ty),
02594                                             /* expected type of base address */
02595                               preg_ty,      /* expected type of object */
02596                               var_offset);  /* offset of object from base */
02597 
02598    if (!STATUS_is_lvalue(status))
02599       Prepend_Token_Special(tmp_tokens, '*');
02600    
02601    /* Assign the variable to the preg */
02602    ST2C_Use_Preg(tokens, preg_ty, preg_offset, context);
02603    Append_Token_Special(tokens, '=');
02604    Append_And_Reclaim_Token_List(tokens, &tmp_tokens);
02605 
02606 } /* WN2C_Load_Return_Reg */
02607 
02608 
02609 static void
02610 WN2C_Function_Call_Lhs(TOKEN_BUFFER rhs_tokens,  /* The function call */
02611                        BOOL         parm_return, /* Return through parameter */
02612                        TY_IDX       return_ty,   /* The function return type */
02613                        const WN    *first_arg,   /* First arg to function */
02614                        CONTEXT      context)
02615 {
02616    /* PRECONDITION: return_ty != Void_Type.
02617     * Append to the rhs_tokens any assignments necessary to retrieve
02618     * the function-call return value into a temporary variable or 
02619     * into return registers, unless no use of a return register
02620     * fitting the return_ty is found.
02621     */
02622    TOKEN_BUFFER             lhs_tokens = New_Token_Buffer();
02623    STAB_OFFSET              value_offset;
02624    STATUS                   status;
02625    BOOL                     return_value_is_used = TRUE;
02626    RETURN_PREG              return_info = PUinfo_Get_ReturnPreg(return_ty);
02627    const RETURN_PREG *const return_info_ptr = &return_info;
02628    
02629    if (parm_return)
02630    {
02631       /* Return through a parameter:  Assign the call-value to
02632        * the dereferenced implicit argument expression (first_arg).
02633        */
02634       status = WN2C_lvalue_wn(lhs_tokens, 
02635                               first_arg,
02636                               WN_Tree_Type(first_arg),
02637                               return_ty,
02638                               0,    /* no offset */
02639                               context);
02640       if (!STATUS_is_lvalue(status))
02641          Prepend_Token_Special(lhs_tokens, '*');
02642    }
02643    else /* Return through a preg; the usual case */
02644    {
02645       const ST *result_var   = CALLSITE_return_var(WN2C_Prev_CallSite);
02646       const WN *result_store = CALLSITE_store1(WN2C_Prev_CallSite);
02647       MTYPE     preg_mtype   = RETURN_PREG_mtype(return_info_ptr, 0);
02648       PREG_IDX  preg_offset  = RETURN_PREG_offset(return_info_ptr, 0);
02649 
02650       /* preg_mtype and preg_offset holds information about the first
02651        * return register.  Now generate code for the location into which
02652        * the call-value should be put.
02653        */
02654       if (preg_mtype == MTYPE_V)
02655       {
02656          /* The resultant value from the call is not used anywhere! */
02657          return_value_is_used = FALSE;
02658       }
02659       else if (result_var != NULL)
02660       {
02661         //WEI: if result of function call is void*, it's presented as UINT64,
02662         //and we need to cast it to the appropriate pointer type on lhs
02663         if (TY_kind(return_ty) == KIND_SCALAR && TY_mtype(return_ty) == Pointer_Mtype &&
02664             TY_kind(ST_type(result_var)) == KIND_POINTER) {
02665           WN2C_prepend_cast(rhs_tokens, ST_type(result_var), false);
02666         }
02667 
02668          STAB_OFFSET var_offset = CALLSITE_var_offset(WN2C_Prev_CallSite);
02669          TY_IDX      var_ty = ST_type(result_var);
02670 
02671          Is_True(!CALLSITE_in_regs(WN2C_Prev_CallSite),
02672                  ("Encountered unexpected reference to a return register"));
02673          
02674          /* Return to a variable or to a preg, as was determined by
02675           * the analysis (pattern matching) in PUinfo_init_pu().  We
02676           * assign the value directly to the variable/register, without
02677           * referencing the return registers.
02678           */
02679          if (ST_sym_class(result_var) == CLASS_PREG)
02680          {
02681             Is_True(RETURN_PREG_num_pregs(return_info_ptr) == 1,
02682                     ("Unexpected number of call-value save registers"));
02683 
02684             var_ty = PUinfo_Preg_Type(var_ty, var_offset);
02685             ST2C_Use_Preg(lhs_tokens, 
02686                           var_ty,
02687                           var_offset,
02688                           context);
02689             if (!WN2C_assignment_compatible_types(var_ty, return_ty))
02690             {
02691                WN2C_prepend_cast(rhs_tokens, 
02692                                  var_ty,  /* cast rhs to type of var */
02693                                  FALSE/*pointer_to_type*/);
02694             }
02695          }
02696          else
02697          {
02698             status = WN2C_lvalue_st(lhs_tokens,
02699                                     result_var,              /* base address */
02700                                     Stab_Pointer_To(var_ty), /* base type */
02701                                     ST_type(result_var),
02702                                     //return_ty, /* type object to be loaded */
02703                                     var_offset,
02704                                     context);
02705             if (!STATUS_is_lvalue(status))
02706                Prepend_Token_Special(lhs_tokens, '*');
02707          }
02708       }
02709       else if (result_store != NULL)
02710       {
02711          TY_IDX base_ty;
02712          TY_IDX stored_ty;
02713          
02714          /* We have a store into an lvalue that is not a variable, so
02715           * it must be an OPR_ISTORE node with the rhs being an LDID
02716           * of the return register.  Do the exact same thing as would
02717           * be done in translating the ISTORE, but substitute the rhs
02718           * with the call expression.
02719           */
02720          Is_True(WN_operator(result_store) == OPR_ISTORE &&
02721                  WN_operator(WN_kid0(result_store)) == OPR_LDID, 
02722                  ("Unexpected store1 in WN2C_Function_Call_Lhs()"));
02723 
02724          Is_True(!CALLSITE_in_regs(WN2C_Prev_CallSite),
02725                  ("Encountered unexpected reference to a return register"));
02726          
02727          /* Get the type of object being stored */
02728          base_ty = WN_Tree_Type(WN_kid1(result_store));
02729          if (!TY_Is_Pointer(base_ty))
02730             base_ty = WN_ty(result_store);
02731          stored_ty = TY_pointed(WN_ty(result_store));
02732          stored_ty =
02733             WN2C_MemAccess_Type(TY_pointed(base_ty),         /* base ty */
02734                                 stored_ty,                   /* preferred ty */
02735                                 WN_opc_dtype(result_store),  /* required mty */
02736                                 WN_store_offset(result_store)); /* base offs */
02737    
02738          status = WN2C_lvalue_wn(lhs_tokens,
02739                                  WN_kid1(result_store), /* lhs of ISTORE */
02740                                  base_ty,               /* type of lhs */
02741                                  stored_ty,             /* type to be stored */
02742                                  WN_store_offset(result_store), /* lhs offs */
02743                                  context);
02744          if (!STATUS_is_lvalue(status))
02745             Prepend_Token_Special(lhs_tokens, '*');
02746 
02747          if (!WN2C_assignment_compatible_types(stored_ty, return_ty))
02748             WN2C_prepend_cast(rhs_tokens, stored_ty, FALSE/*ptr_to_type*/);
02749       }
02750       else if (!CALLSITE_in_regs(WN2C_Prev_CallSite))
02751       {
02752          /* The return registers are not referenced, so do not bother
02753           * assigning the return value to the return registers.
02754           */
02755          return_value_is_used = FALSE;
02756       }
02757       else if (RETURN_PREG_num_pregs(return_info_ptr) == 1 && 
02758                TY_Is_Preg_Type(return_ty))
02759       {
02760          TY_IDX preg_ty = 
02761             PUinfo_Preg_Type(Stab_Mtype_To_Ty(preg_mtype), preg_offset);
02762 
02763          /* There is a single return register holding the return value,
02764           * so return the rhs into this register, after casting the rhs
02765           * to the appropriate type.
02766           */
02767          ST2C_Use_Preg(lhs_tokens, preg_ty, preg_offset, context);
02768          if (!WN2C_assignment_compatible_types(preg_ty, return_ty))
02769          {
02770             WN2C_prepend_cast(rhs_tokens,
02771                               preg_ty,
02772                               FALSE/*pointer_to_type*/);
02773          }
02774       }
02775       else /* Our most difficult case */
02776       {
02777          /* We need to store the call-result into a temporary variable,
02778           * then save the temporary variable into the return registers.
02779           */
02780          const UINT  tmp_idx = Stab_Lock_Tmpvar(return_ty, 
02781                                                 ST2C_Declare_Tempvar);
02782          const char *tmpvar_name = W2CF_Symtab_Nameof_Tempvar(tmp_idx);
02783          
02784          /* The lhs is simply the tmpvar */
02785          Append_Token_String(lhs_tokens, tmpvar_name);
02786 
02787          /* Load the first register off the tmpvar_name after assigning the
02788           * rhs to the lhs.
02789           */
02790          Append_Token_Special(rhs_tokens, ';');
02791          WN2C_Stmt_Newline(rhs_tokens, CONTEXT_srcpos(context));
02792          WN2C_Load_Return_Reg(rhs_tokens,
02793                               return_ty, /* Type of tmpvar_name */
02794                               tmpvar_name, 
02795                               0,         /* Offset in tmpvar_name */
02796                               preg_mtype,
02797                               preg_offset,
02798                               context);
02799             
02800          if (RETURN_PREG_num_pregs(return_info_ptr) > 1)
02801          {
02802             /* Get the offset into the value from which the second preg
02803              * needs to be loaded.
02804              */
02805             value_offset = TY_size(Stab_Mtype_To_Ty(preg_mtype));
02806 
02807             /* Load the second register */
02808             Append_Token_Special(rhs_tokens, ';');
02809             WN2C_Stmt_Newline(rhs_tokens, CONTEXT_srcpos(context));
02810             preg_offset = RETURN_PREG_offset(return_info_ptr, 1);
02811             preg_mtype = RETURN_PREG_mtype(return_info_ptr, 1);
02812             WN2C_Load_Return_Reg(rhs_tokens,
02813                                  return_ty,   /* Type of tmpvar_name */
02814                                  tmpvar_name, 
02815                                  value_offset, /* Offset in tmpvar_name */
02816                                  preg_mtype, 
02817                                  preg_offset, 
02818                                  context);
02819          } /* if save call-value into both return pregs */
02820 
02821          Stab_Unlock_Tmpvar(tmp_idx);
02822 
02823       } /* if return into registers */
02824    } /* if return into parameter */
02825       
02826    /* Assign the lhs to the rhs */
02827    if (return_value_is_used)
02828    {
02829       Prepend_Token_Special(rhs_tokens, '=');
02830       Prepend_And_Reclaim_Token_List(rhs_tokens, &lhs_tokens);
02831    }
02832    else
02833    {
02834       Reclaim_Token_Buffer(&lhs_tokens);
02835    }   
02836 } /* WN2C_Function_Call_Lhs */
02837 
02838 
02839 static void
02840 WN2C_Function_Return_Value(TOKEN_BUFFER tokens, /* Statements before return */
02841                            CONTEXT context)
02842 {
02843    /* PRECONDITION: return_ty != Void_Type.
02844     * Append any necessary assignments and a return statement for the
02845     * return value to the given token-list.
02846     */
02847    TOKEN_BUFFER value_tokens;
02848    STAB_OFFSET  value_offset;
02849    STATUS       status;
02850 
02851    value_tokens = New_Token_Buffer();
02852    if (PUINFO_RETURN_TO_PARAM)
02853    {
02854       /* Return through a parameter.  This paremeter will be
02855        * declared as a local variable in WN2C_block().
02856        */
02857       Append_Token_String(value_tokens, WN2C_Return_Value_Name);
02858       WN2C_Used_Return_Value = TRUE;
02859    }
02860    else /* Return through a preg; the usual case */
02861    {
02862       MTYPE     preg_mtype;
02863       PREG_IDX  preg_offset;
02864       const ST *result_var = RETURNSITE_return_var(WN2C_Next_ReturnSite);
02865       const WN *result_store = RETURNSITE_store1(WN2C_Next_ReturnSite);
02866 
02867       /* Get the offset and mtype of the first return register */
02868       preg_offset = RETURN_PREG_offset(PUinfo_return_preg, 0);
02869       preg_mtype = RETURN_PREG_mtype(PUinfo_return_preg, 0);
02870 
02871       /* Now that we have information about the distribution of the
02872        * return values in registers and how these registers are set
02873        * by means of STIDs (possibly from a variable), generate
02874        * code for the return value.
02875        */
02876       if (result_var != NULL)
02877       {
02878          STAB_OFFSET var_offset = RETURNSITE_var_offset(WN2C_Next_ReturnSite);
02879          TY_IDX      var_ty = ST_type(result_var);
02880 
02881          /* Pattern matching in PUinfo_init_pu() revealed that the
02882           * return value is present in a variable/non-return-register.
02883           * Just return the value of this variable/register.
02884           */
02885          if (ST_sym_class(result_var) == CLASS_PREG)
02886          {
02887             Is_True(RETURN_PREG_num_pregs(PUinfo_return_preg) == 1,
02888                     ("Unexpected number of return-value save registers"));
02889 
02890             var_ty = PUinfo_Preg_Type(var_ty, var_offset);
02891             ST2C_Use_Preg(value_tokens, 
02892                           var_ty,
02893                           var_offset,
02894                           context);
02895             if (!WN2C_assignment_compatible_types(PUINFO_RETURN_TY, var_ty))
02896             {
02897                WN2C_prepend_cast(value_tokens, 
02898                                  PUINFO_RETURN_TY,
02899                                  FALSE/*pointer_to_type*/);
02900             }
02901          }
02902          else
02903          {
02904             status = WN2C_lvalue_st(value_tokens,
02905                                     result_var,             /* base variable */
02906                                     Stab_Pointer_To(var_ty),/* base addr ty */
02907                                     PUINFO_RETURN_TY, /* type object loaded */
02908                                     var_offset,
02909                                     context);
02910             if (!STATUS_is_lvalue(status))
02911                Prepend_Token_Special(value_tokens, '*');
02912          }
02913       }
02914       else if (result_store != NULL)
02915       {
02916          /* We have a store into the return register, so just return
02917           * the rhs of the store (should be an STID).
02918           */
02919          Is_True(WN_operator(result_store) == OPR_STID, 
02920                  ("Unexpected store1 in WN2C_Function_Return_Value()"));
02921          
02922          /* Get the type of object being stored */
02923          CONTEXT_reset_needs_lvalue(context);
02924          CONTEXT_set_top_level_expr(context);
02925          status = WN2C_translate(value_tokens, WN_kid0(result_store), context);
02926          if (!WN2C_assignment_compatible_types(PUINFO_RETURN_TY,
02927                                       WN_Tree_Type(WN_kid0(result_store))))
02928          {
02929             WN2C_prepend_cast(value_tokens,
02930                               PUINFO_RETURN_TY,
02931                               FALSE/*ptr_to_type*/);
02932          }
02933       }
02934       else if (RETURN_PREG_num_pregs(PUinfo_return_preg) == 1 &&
02935                TY_Is_Preg_Type(PUINFO_RETURN_TY))
02936       {
02937          TY_IDX preg_ty =
02938             PUinfo_Preg_Type(Stab_Mtype_To_Ty(preg_mtype), preg_offset);
02939 
02940          /* There is a single return register holding the return value,
02941           * so return a reference to this register casted to the 
02942           * appropriate type.
02943           */
02944          ST2C_Use_Preg(value_tokens, preg_ty, preg_offset, context);
02945          if (!WN2C_assignment_compatible_types(PUINFO_RETURN_TY, preg_ty))
02946          {
02947             WN2C_prepend_cast(value_tokens,
02948                               PUINFO_RETURN_TY, 
02949                               FALSE/*pointer_to_type*/);
02950          }
02951       }
02952       else /* Our most difficult case */
02953       {
02954          /* We need to store the return registers into a temporary 
02955           * variable, then return the value of this variable.
02956           */
02957             
02958          /* Store the first register */
02959          WN2C_Store_Return_Reg(tokens,
02960                                WN2C_Return_Value_Name, 
02961                                0, /* offset in return value */
02962                                preg_mtype,
02963                                preg_offset, 
02964                                context);
02965             
02966          if (RETURN_PREG_num_pregs(PUinfo_return_preg) > 1)
02967          {
02968             /* Get the offset into the value where the second preg
02969              * needs to be stored.
02970              */
02971             value_offset = TY_size(Stab_Mtype_To_Ty(preg_mtype));
02972 
02973             /* Store the second register */
02974             preg_offset = RETURN_PREG_offset(PUinfo_return_preg, 1);
02975             preg_mtype = RETURN_PREG_mtype(PUinfo_return_preg, 1);
02976             WN2C_Store_Return_Reg(tokens,
02977                                   WN2C_Return_Value_Name, 
02978                                   value_offset, /* offset in return value */
02979                                   preg_mtype, 
02980                                   preg_offset,
02981                                   context);
02982          } /* if return two pregs */
02983          Append_Token_String(value_tokens, WN2C_Return_Value_Name);
02984          WN2C_Used_Return_Value = TRUE;
02985       } /* if return through existing variable */
02986    } /* if return through parameter */
02987 
02988    Append_Token_String(tokens, "return");
02989    Append_And_Reclaim_Token_List(tokens, &value_tokens);
02990 
02991 } /* WN2C_Function_Return_Value */
02992 
02993 
02994 static void
02995 WN2C_Append_Pragma_Newline(TOKEN_BUFFER tokens, SRCPOS srcpos)
02996 {
02997    UINT current_indent = Current_Indentation();
02998 
02999    Set_Current_Indentation(0);
03000    WN2C_Stmt_Newline(tokens, srcpos);
03001    Set_Current_Indentation(current_indent);
03002 } /* WN2C_Append_Pragma_Newline */
03003 
03004 
03005 static void
03006 WN2C_Callsite_Directives(TOKEN_BUFFER tokens, 
03007                          const WN    *call_wn,
03008                          const ST    *func_st,
03009                          CONTEXT      context)
03010 {
03011    if (WN_Call_Inline(call_wn))
03012    {
03013       WN2C_Append_Pragma_Newline(tokens, CONTEXT_srcpos(context));
03014       Append_Token_String(tokens, "#pragma");
03015       Append_Token_String(tokens, "inline");
03016       Append_Token_Special(tokens, '(');
03017       ST2C_use_translate(tokens, func_st, context);
03018       Append_Token_Special(tokens, ')');
03019    }
03020    else if (WN_Call_Dont_Inline(call_wn))
03021    {
03022       WN2C_Append_Pragma_Newline(tokens, CONTEXT_srcpos(context));
03023       Append_Token_String(tokens, "#pragma");
03024       Append_Token_String(tokens, "noinline");
03025       Append_Token_Special(tokens, '(');
03026       ST2C_use_translate(tokens, func_st, context);
03027       Append_Token_Special(tokens, ')');
03028    }
03029    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
03030 } /* WN2C_Callsite_Directives */
03031 
03032 
03033 static void
03034 WN2C_Translate_Stmt_Sequence(TOKEN_BUFFER  tokens, 
03035                              const WN     *first,
03036                              BOOL          first_on_newline,
03037                              CONTEXT       context)
03038 {
03039    /* Translate the sequence of statements listed at "first",
03040     * separating the statements with newline characters.
03041     */
03042    const WN *stmt;
03043    STATUS    status;
03044 
03045    for (stmt = first; stmt != NULL; stmt = WN_next(stmt))
03046    {
03047       if (!WN2C_Skip_Stmt(stmt))
03048       {
03049          /* Seperate stmts by newlines */
03050          CONTEXT_set_srcpos(context, WN_Get_Linenum(stmt));
03051          if (first_on_newline || stmt != first)
03052          {
03053              if (WN_operator(stmt) == OPR_DO_LOOP ||
03054                  WN_operator(stmt) == OPR_WHILE_DO ||
03055                  WN_operator(stmt) == OPR_DO_WHILE ||
03056                  WN_operator(stmt) == OPR_CALL ||
03057                  WN_operator(stmt) == OPR_PICCALL ||
03058                  WN_operator(stmt) == OPR_REGION ||
03059                  WN_operator(stmt) == OPR_PRAGMA ||
03060                  WN_operator(stmt) == OPR_XPRAGMA && 
03061                  WN_operator(stmt) == OPR_TRAP ||
03062                  WN_operator(stmt) == OPR_ASSERT ||
03063                  WN_operator(stmt) == OPR_FORWARD_BARRIER ||
03064                  WN_operator(stmt) == OPR_BACKWARD_BARRIER)
03065              {
03066                 /* Special newlines are added by handler routines.
03067                  */
03068              }
03069              else
03070                 WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
03071          }
03072          status = WN2C_translate(tokens, stmt, context);
03073          if (!STATUS_is_block(status)      && 
03074              WN_operator(stmt) != OPR_REGION &&
03075              WN_operator(stmt) != OPR_PRAGMA &&
03076              WN_operator(stmt) != OPR_XPRAGMA &&
03077              WN_operator(stmt) != OPR_TRAP &&
03078              WN_operator(stmt) != OPR_ASSERT &&
03079              WN_operator(stmt) != OPR_FORWARD_BARRIER &&
03080              WN_operator(stmt) != OPR_BACKWARD_BARRIER)
03081             Append_Token_Special(tokens, ';');
03082 
03083          /* Append frequency feedback info in a comment
03084           */
03085          if (W2C_Emit_Frequency                         && 
03086              W2C_Frequency_Map != WN_MAP_UNDEFINED      &&
03087              WN_MAP32_Get(W2C_Frequency_Map, stmt) >= 0 &&
03088              WN_operator(stmt) != OPR_REGION              &&
03089              WN_operator(stmt) != OPR_PRAGMA              &&
03090              WN_operator(stmt) != OPR_XPRAGMA             &&
03091              WN_operator(stmt) != OPR_TRAP                &&
03092              WN_operator(stmt) != OPR_ASSERT              &&
03093              WN_operator(stmt) != OPR_FORWARD_BARRIER     &&
03094              WN_operator(stmt) != OPR_BACKWARD_BARRIER)
03095          {
03096             INT32 freq = WN_MAP32_Get(W2C_Frequency_Map, stmt);
03097             Append_Token_String(tokens, "  /*FREQ=");
03098             Append_Token_String(tokens, Number_as_String(freq,"%lld"));
03099             Append_Token_String(tokens, "*/");
03100          }
03101       }
03102    } /*for*/
03103 } /* WN2C_Translate_Stmt_Sequence */
03104 
03105 
03106 static void
03107 WN2C_Translate_Comma_Sequence(TOKEN_BUFFER  tokens, 
03108                               const WN     *first,
03109                               CONTEXT       context)
03110 {
03111    /* Translate the sequence of statements listed at "first",
03112     * separating the statements with comma characters.
03113     */
03114    const WN *stmt;
03115 
03116    for (stmt = first; stmt != NULL; stmt = WN_next(stmt))
03117    {
03118       if (!WN2C_Skip_Stmt(stmt))
03119       {
03120          /* Seperate stmts by commas */
03121          CONTEXT_set_srcpos(context, WN_Get_Linenum(stmt));
03122          if (stmt != first)
03123          {
03124             Append_Token_Special(tokens, ',');
03125          }
03126          WN2C_translate(tokens, stmt, context);
03127       }
03128    } /*for*/
03129 } /* WN2C_Translate_Comma_Sequence */
03130 
03131 
03132 void
03133 WN2C_Append_Purple_Funcinfo(TOKEN_BUFFER tokens)
03134 {
03135    const char *name   = W2C_Object_Name(PUINFO_FUNC_ST);
03136    ST_IDX      id     = PUINFO_FUNC_ST_IDX;
03137    ST_SCLASS   sclass = ST_sclass(PUINFO_FUNC_ST);
03138    ST_EXPORT   export_class = (ST_EXPORT)ST_export(PUINFO_FUNC_ST);
03139 
03140    Append_Token_String(tokens, name);
03141    Append_Token_Special(tokens, ',');
03142    if (strcmp(name, WN2C_Purple_Region_Name) == 0)
03143    {
03144       /* This must match the setting in PRP_TRACE_READER::_Read_Next()
03145        * when a region is entered.
03146        */
03147       id = 0xffffffff;
03148       sclass = SCLASS_TEXT;
03149       export_class = EXPORT_INTERNAL;
03150    }
03151    Append_Token_String(tokens, Number_as_String(id, "%llu"));
03152    Append_Token_Special(tokens, ',');
03153    Append_Token_String(tokens, Number_as_String(sclass, "%lld"));
03154    Append_Token_Special(tokens, ',');
03155    Append_Token_String(tokens, Number_as_String(export_class, "%lld"));
03156    Append_Token_Special(tokens, ',');
03157    Append_Token_String(tokens, "0"); /* Flags */
03158 } /* WN2C_Append_Purple_Funcinfo */
03159 
03160 
03161 static void
03162 Append_Cplus_Initialization(TOKEN_BUFFER tokens, CONTEXT context)
03163 {
03164    Append_Token_String(tokens, "/* C++ specific initialization */");
03165    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
03166    Append_Token_String(tokens,
03167                        "if (__cplinit.ctor != NULL) __cplinit.ctor();");
03168    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
03169 } /* Append_Cplus_Initialization */
03170 
03171 
03172 /*---------------------- Prefetching Comments ------------------------*/
03173 /*--------------------------------------------------------------------*/
03174 
03175 static void
03176 WN2C_Prefetch_Map(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
03177 {
03178    PF_POINTER* pfptr;
03179    const char *info_str;
03180 
03181    pfptr = (PF_POINTER*)WN_MAP_Get(WN_MAP_PREFETCH, wn);
03182    info_str = "/* prefetch (ptr, lrnum): ";
03183    if (pfptr->wn_pref_1L)
03184    {
03185       info_str = 
03186          Concat2_Strings(    info_str,
03187           Concat2_Strings(   "1st <", 
03188            Concat2_Strings(  Ptr_as_String(pfptr->wn_pref_1L),
03189             Concat2_Strings( ", ",
03190              Concat2_Strings(Number_as_String(pfptr->lrnum_1L,"%lld"),
03191                              "> ")))));
03192    }
03193    if (pfptr->wn_pref_2L)
03194    {
03195       info_str = 
03196          Concat2_Strings(    info_str,
03197           Concat2_Strings(   "2nd <", 
03198            Concat2_Strings(  Ptr_as_String(pfptr->wn_pref_2L),
03199             Concat2_Strings( ", ",
03200              Concat2_Strings(Number_as_String(pfptr->lrnum_2L,"%lld"),
03201                              "> ")))));
03202    }
03203    info_str = Concat2_Strings(info_str, "*/");
03204    Append_Indented_Newline(tokens, 1);
03205    Append_Token_String (tokens, info_str);
03206    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
03207 } /* WN2C_Prefetch_Map */
03208 
03209 
03210 /*--------------------- prompf processing utilities -------------------*/
03211 /*---------------------------------------------------------------------*/
03212 
03213 static void
03214 WN2C_Append_Prompf_Flag_Newline(TOKEN_BUFFER tokens)
03215 {
03216    UINT current_indent = Current_Indentation();
03217 
03218    Set_Current_Indentation(0);
03219    Append_Indented_Newline(tokens, 1);
03220    Set_Current_Indentation(current_indent);
03221 } /* WN2C_Append_Prompf_Flag_Newline */
03222 
03223 
03224 static BOOL
03225 WN2C_Is_Loop_Region(const WN *region, CONTEXT context)
03226 {
03227    /* Return TRUE if the given region is either a DOACROSS,
03228     * PARALLEL_DO, or a PDO region; otherwise, return FALSE.
03229     */
03230    BOOL predicate = (WN_operator(region) == OPR_REGION);
03231 
03232    if (predicate)
03233    {
03234       const WN *pragma = WN_first(WN_region_pragmas(region));
03235 
03236       predicate = (pragma != NULL &&
03237                    (WN_pragma(pragma) == WN_PRAGMA_DOACROSS    ||
03238                     WN_pragma(pragma) == WN_PRAGMA_PARALLEL_DO ||
03239                     WN_pragma(pragma) == WN_PRAGMA_PDO_BEGIN) &&
03240                    WN_pragma_nest(pragma) <= 0 &&
03241                    !Ignore_Synchronized_Construct(pragma, context));
03242    }
03243    return predicate;
03244 } /* WN2C_Is_Loop_Region */
03245 
03246 
03247 static BOOL
03248 WN2C_Is_Parallel_Region(const WN *region, CONTEXT context)
03249 {
03250    BOOL predicate = (region != NULL && WN_operator(region) == OPR_REGION);
03251 
03252    if (predicate)
03253    {
03254       const WN *pragma = WN_first(WN_region_pragmas(region));
03255 
03256       predicate = (pragma != NULL && 
03257                    (WN_pragma(pragma) == WN_PRAGMA_PARALLEL_BEGIN || 
03258                     WN_pragma(pragma) == WN_PRAGMA_MASTER_BEGIN || 
03259                     WN_pragma(pragma) == WN_PRAGMA_SINGLE_PROCESS_BEGIN ||
03260                     WN_pragma(pragma) == WN_PRAGMA_PSECTION_BEGIN ||
03261                     WN_pragma(pragma) == WN_PRAGMA_PARALLEL_SECTIONS) &&
03262                    !Ignore_Synchronized_Construct(pragma, context));
03263    }   
03264    return predicate;
03265 } /* WN2C_Is_Parallel_Region */
03266 
03267 
03268 static void
03269 WN2C_Prompf_Construct_Start(TOKEN_BUFFER tokens, const WN *construct)
03270 {
03271    INT32 construct_id = WN_MAP32_Get(*W2C_Construct_Map, construct);
03272 
03273    if (construct_id != 0)
03274    {
03275       WN2C_Append_Prompf_Flag_Newline(tokens);
03276       Append_Token_String(tokens, "/*$SGI");
03277       Append_Token_String(tokens, "start");
03278       Append_Token_String(tokens, Number_as_String(construct_id, "%llu"));
03279       Append_Token_String(tokens, "*/");
03280    }
03281 } /* WN2C_Prompf_Construct_Start */
03282 
03283 
03284 static void
03285 WN2C_Prompf_Construct_End(TOKEN_BUFFER tokens, const WN *construct)
03286 {
03287    INT32 construct_id = WN_MAP32_Get(*W2C_Construct_Map, construct);
03288 
03289    if (construct_id != 0)
03290    {
03291       WN2C_Append_Prompf_Flag_Newline(tokens);
03292       Append_Token_String(tokens, "/*$SGI");
03293       Append_Token_String(tokens, "end");
03294       Append_Token_String(tokens, Number_as_String(construct_id, "%llu"));
03295       Append_Token_String(tokens, "*/");
03296    }
03297 } /* WN2C_Prompf_Construct_End */
03298 
03299 
03300 static void
03301 WN2C_Start_Prompf_Transformed_Loop(TOKEN_BUFFER tokens,
03302                                    const WN    *loop,
03303                                    CONTEXT      context)
03304 {
03305    /* We if this is a DOACROSS, PDO or PARALLEL DO loop, then it will
03306     * already have been handled by the sourrounding region, so we need
03307     * not emit anything here.  Otherwise, emit the prompf flags.
03308     */
03309    if (!WN2C_Is_Loop_Region(W2CF_Get_Parent(W2CF_Get_Parent(loop)), context))
03310       WN2C_Prompf_Construct_Start(tokens, loop);
03311 } /* WN2C_Start_Prompf_Transformed_Loop */
03312 
03313 
03314 static void
03315 WN2C_End_Prompf_Transformed_Loop(TOKEN_BUFFER tokens,
03316                                  const WN    *loop,
03317                                  CONTEXT      context)
03318 {
03319    /* We if this is a DOACROSS, PDO or PARALLEL DO loop, then it will
03320     * already have been handled by the sourrounding region, so we need
03321     * not emit anything here.  Otherwise, emit the prompf flags.
03322     */
03323    if (!WN2C_Is_Loop_Region(W2CF_Get_Parent(W2CF_Get_Parent(loop)), context))
03324       WN2C_Prompf_Construct_End(tokens, loop);
03325 } /* WN2C_End_Prompf_Transformed_Loop */
03326 
03327 
03328 static void
03329 WN2C_Start_Prompf_Transformed_Region(TOKEN_BUFFER tokens, 
03330                                      const WN    *region,
03331                                      CONTEXT      context)
03332 {
03333    /* Handle a PARALLEL region, or a DOACROSS, PDO or PARALLEL DO 
03334     * loop enclosed in a region.
03335     */
03336    if (WN2C_Is_Loop_Region(region, context) || 
03337        WN2C_Is_Parallel_Region(region, context))
03338       WN2C_Prompf_Construct_Start(tokens, region);
03339 } /* WN2C_Start_Prompf_Transformed_Region */
03340 
03341 
03342 static void
03343 WN2C_End_Prompf_Transformed_Region(TOKEN_BUFFER tokens, 
03344                                    const WN    *region,
03345                                    CONTEXT      context)
03346 {
03347    /* Handle a PARALLEL region, or a DOACROSS, PDO or PARALLEL DO 
03348     * loop enclosed in a region.
03349     */
03350    if (WN2C_Is_Loop_Region(region, context) ||
03351        WN2C_Is_Parallel_Region(region, context))
03352       WN2C_Prompf_Construct_End(tokens, region);
03353 } /* WN2C_End_Prompf_Transformed_Region */
03354 
03355 
03356 /*--------- hidden routines to handle each kind of operator -----------*/
03357 /*---------------------------------------------------------------------*/
03358 
03359 static STATUS
03360 WN2C_ignore(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
03361 {
03362    return EMPTY_STATUS;
03363 } /* WN2C_ignore */
03364 
03365 
03366 static STATUS
03367 WN2C_unsupported(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
03368 {
03369    fprintf(stderr, 
03370            "==> wn2c cannot handle operator <%s> (%d): construct ignored!\n",
03371            WN_opc_name(wn), WN_operator(wn));
03372 
03373    Append_Token_String(tokens, Concat3_Strings("<", WN_opc_name(wn), ">"));
03374    
03375    return EMPTY_STATUS;
03376 } /* WN2C_unsupported */
03377 
03378 
03379 static STATUS
03380 WN2C_binaryop(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
03381 {
03382    STATUS status;
03383    
03384    Is_True(WN_kid_count(wn) == 2, 
03385      ("Expected 2 kids in WN2C_binaryop for op %s",WN_opc_name(wn)));
03386 
03387    if (WN2C_IS_INFIX_OP(WN_opcode(wn)))
03388       status = WN2C_infix_op(tokens,
03389                              WN_opcode(wn),
03390                              WN_Tree_Type(wn),
03391                              WN_kid0(wn), 
03392                              WN_kid1(wn), 
03393                              context);
03394    else if (WN2C_IS_FUNCALL_OP(WN_opcode(wn)))
03395       status = WN2C_funcall_op(tokens, 
03396                                WN_opcode(wn), 
03397                                WN_kid0(wn), 
03398                                WN_kid1(wn), 
03399                                context);
03400    else 
03401       Is_True(FALSE, ("Illegal operator (%s=%d) in WN2C_binaryop()",
03402                       WN_opc_name(wn), WN_opcode(wn)));
03403 
03404    return status;
03405 } /* WN2C_binaryop */
03406 
03407 
03408 static STATUS
03409 WN2C_unaryop(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
03410 {
03411    Is_True(WN_kid_count(wn) == 1, ("Expected 1 kid in WN2C_unaryop()"));
03412 
03413    if (WN2C_IS_INFIX_OP(WN_opcode(wn)))
03414       WN2C_infix_op(tokens,
03415                     WN_opcode(wn), 
03416                     WN_Tree_Type(wn),
03417                     NULL, /* No first operand */
03418                     WN_kid0(wn), 
03419                     context);
03420    else if (WN2C_IS_FUNCALL_OP(WN_opcode(wn)))
03421       WN2C_funcall_op(tokens, WN_opcode(wn), NULL, WN_kid0(wn), context);
03422    else
03423       Is_True(FALSE, ("Illegal operator (%s=%d) in WN2C_unaryop()",
03424                       WN_opc_name(wn), WN_opcode(wn)));
03425 
03426    return EMPTY_STATUS;
03427 } /* WN2C_unaryop */
03428 
03429 
03430 static STATUS
03431 WN2C_func_entry(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
03432 {
03433    /* Add tokens for the function header and body to "tokens".  Note
03434     * that all the tokens will be added to the buffer, while the task
03435     * of writing the tokens to file and freeing up the buffer is left
03436     * to the caller.
03437     *
03438     * Assume that Current_Symtab has been updated (see bedriver.c).
03439     * Note that Current_PU is not maintained, but we instead get to
03440     * it through PUinfo_current_func.
03441     *
03442     */
03443    ST **param_st;
03444    INT  param;
03445    
03446    Is_True(WN_operator(wn) == OPR_FUNC_ENTRY, 
03447            ("Invalid opcode for WN2C_func_entry()"));
03448 
03449    /* Set the state to reflect the current PU, assuming PUinfo
03450     * already is up to date.
03451     */
03452    CONTEXT_set_new_func_scope(context);
03453    WN2C_Used_Return_Value = FALSE;
03454    WN2C_Next_ReturnSite = PUinfo_Get_ReturnSites();
03455    WN2C_Prev_CallSite = NULL;
03456    
03457    /* Emit the function pragmas before local variables */
03458    if (!W2C_No_Pragmas)
03459       WN2C_pragma_list_begin(PUinfo_pragmas, 
03460                              WN_first(WN_region_pragmas(wn)),
03461                              context);
03462 
03463    /* Accumulate the parameters and their ST/TY entries in the 
03464     * "param_st"/"param_ty" array.
03465     */
03466    param_st = (ST **)alloca((WN_num_formals(wn) + 1)*sizeof(ST *));
03467    for (param = 0; param < WN_num_formals(wn); param++)
03468    {
03469       Is_True(WN_operator(WN_formal(wn, param)) == OPR_IDNAME, 
03470               ("Invalid opcode for parameter of OPR_FUNC_ENTRY"));
03471       param_st[param] = WN_st(WN_formal(wn, param));
03472    }
03473    param_st[WN_num_formals(wn)] = NULL; /* Terminates list of param STs */
03474 
03475    /* Write prompf information */
03476    if (W2C_Prompf_Emission)
03477       WN2C_Prompf_Construct_Start(tokens, wn);
03478 
03479    /* Write function header, and begin the body on a new line */
03480    CONTEXT_set_srcpos(context, WN_Get_Linenum(wn));
03481    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
03482 
03483    //WEI: don't output the complete type declaration at the function header
03484    if (Compile_Upc) {
03485      CONTEXT_set_incomplete_ty2c(context);
03486    }
03487    ST2C_func_header(tokens, WN_st(wn), param_st, context);
03488    
03489    /* Write out the function body */
03490    CONTEXT_set_srcpos(context, WN_Get_Linenum(WN_func_body(wn)));
03491    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
03492    Append_Token_Special(tokens, '{');
03493    Increment_Indentation();
03494 
03495    //WEI: write the BEGIN_FUNCTION
03496    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
03497    if (Compile_Upc) {
03498      Append_Token_String(tokens, "UPCR_BEGIN_FUNCTION();");
03499    }
03500 
03501    (void)WN2C_translate(tokens, WN_func_body(wn), context);
03502    if (!W2C_No_Pragmas)
03503       WN2C_pragma_list_end(tokens, 
03504                            WN_first(WN_region_pragmas(wn)),
03505                            context);
03506    Decrement_Indentation();
03507    Append_Indented_Newline(tokens, 1);
03508    Append_Token_Special(tokens, '}');
03509 
03510    /* Emit the function name inb a comment */
03511    Append_Token_String(tokens, "/*");
03512    ST2C_use_translate(tokens, &St_Table[WN_entry_name(wn)], context);
03513    Append_Token_String(tokens, "*/");
03514 
03515    if (W2C_Prompf_Emission)
03516       WN2C_Prompf_Construct_End(tokens, wn);
03517 
03518    /* Separate functions by two empty lines */
03519    Append_Indented_Newline(tokens, 2);
03520 
03521    /* Reset the state to reflect an exit from this PU context */
03522    WN2C_Prev_CallSite = NULL;
03523    WN2C_Next_ReturnSite = NULL;
03524    WN2C_Used_Return_Value = FALSE;
03525 
03526    return EMPTY_STATUS;
03527 } /* WN2C_func_entry */
03528 
03529 
03530 static STATUS
03531 WN2C_block(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
03532 {
03533    /* Do the local declarations (if we have a new symtab) and the
03534     * list of statements.
03535     */
03536    const ST    *st;
03537    TOKEN_BUFFER stmt_tokens;
03538    const BOOL   new_func_scope = CONTEXT_new_func_scope(context);
03539    const BOOL   new_symtab = WN2C_new_symtab();
03540    UINT         current_indent;
03541    STATUS       status;
03542    ST_IDX       st_idx;
03543    
03544    Is_True(WN_operator(wn) == OPR_BLOCK,
03545            ("Invalid operator for WN2C_block()"));
03546    
03547    /* Register Fortran common blocks in st2c, marking the 
03548     * associated types as having been declared.
03549     */
03550    if (new_symtab)
03551    {
03552       FOREACH_SYMBOL(CURRENT_SYMTAB, st, st_idx)
03553       {
03554          if (ST_sym_class(st) == CLASS_VAR && 
03555              Stab_Is_Common_Block(st)      &&
03556              !ST_is_split_common(st))
03557          {
03558             ST2C_New_Common_Block(st);
03559          }
03560       }
03561    }
03562 
03563    /* Reset the context so we do not interpret nested scopes as 
03564     * function-scopes, and save off the proper indentation for local
03565     * declarations in this scope.
03566     */
03567    if (new_func_scope)
03568    {
03569       /* The '{' has already been added and the indentation has been changed
03570        */
03571       CONTEXT_reset_new_func_scope(context);
03572       PUinfo_local_decls_indent = Current_Indentation();
03573    }
03574    else
03575    {
03576       /* Statements and local declarations for this block should be 
03577        * indented from the surrounding text, but the '{' character
03578        * should be level with the surrounding text.
03579        */
03580       Append_Token_Special(tokens, '{');
03581       Increment_Indentation();
03582    }
03583 
03584    /* Emit code for the statements in the block, indented and 
03585     * separated by a newline character.
03586     */
03587    stmt_tokens = New_Token_Buffer();
03588    if (new_func_scope        &&
03589        W2C_Cplus_Initializer && 
03590        (PU_is_mainpu(Pu_Table[ST_pu(PUINFO_FUNC_ST)]) || 
03591         strcmp(ST_name(PUINFO_FUNC_ST), "main") == 0))
03592    {
03593       Append_Cplus_Initialization(stmt_tokens, context);
03594    }
03595    CONTEXT_set_top_level_expr(context);
03596    if (WN_first(wn) != NULL)
03597       WN2C_Translate_Stmt_Sequence(
03598          stmt_tokens, WN_first(wn), TRUE/*first_on_newline*/, context);
03599 
03600    /* Declare the identifiers local to this block, in the current
03601     * function scope context, when the Current_Symtab has changed.
03602     * We need to do this after traversing the statements to limit
03603     * the declarations to local variables that have been marked as
03604     * actually having been referenced.
03605     */
03606    if (new_symtab)
03607    {
03608       current_indent = Current_Indentation();
03609       Set_Current_Indentation(PUinfo_local_decls_indent);
03610       WN2C_Append_Symtab_Consts(NULL, /* token_buffer */ 
03611                                 FALSE, /*use const_tab*/
03612                                 1,    /* lines between decls */
03613                                 context);
03614       WN2C_Append_Symtab_Vars(PUinfo_local_decls, 1/*Newlines*/, context);
03615       Set_Current_Indentation(current_indent);
03616 
03617       /* Later compiler stages may use the ST_referenced flag,
03618        * expecting it to be FALSE by default, hence we reset
03619        * the flag after we have used it here.
03620        */
03621       Stab_Reset_Referenced_Flag(CURRENT_SYMTAB);
03622    }
03623 
03624    /* Append the declaration for the return variable and all the
03625     * local variables accumulated for this context, when this is 
03626     * a function body.
03627     */
03628    if (new_func_scope)
03629    {
03630       current_indent = Current_Indentation();
03631       Set_Current_Indentation(PUinfo_local_decls_indent);
03632       if (PUINFO_RETURN_TO_PARAM)
03633          WN2C_Declare_Return_Parameter(PUinfo_local_decls, context);
03634       else if (WN2C_Used_Return_Value)
03635          WN2C_Declare_Return_Variable(PUinfo_local_decls);
03636       Set_Current_Indentation(current_indent);
03637 
03638       /* Append local declarations to "tokens" */
03639       Append_Indented_Newline(tokens, 1);
03640       Append_And_Reclaim_Token_List(tokens, &PUinfo_local_decls);
03641 
03642       if (!Is_Empty_Token_Buffer(PUinfo_pragmas))
03643          Append_Indented_Newline(PUinfo_pragmas, 1);
03644       Append_And_Reclaim_Token_List(tokens, &PUinfo_pragmas);
03645       
03646       /* If this is a purple code-extraction, insert a placeholder
03647        * for purple-specific initialization.
03648        */
03649       if (W2C_Purple_Emission)
03650       {
03651          /* <#PRP_XSYM:INIT_DECL name, id, sclass, export#>
03652           */
03653          Append_Indented_Newline(tokens, 1);
03654          Append_Token_String(tokens, "<#PRP_XSYM:INIT_DECL");
03655          WN2C_Append_Purple_Funcinfo(tokens);
03656          Append_Token_String(tokens, "#>");
03657       }
03658    }
03659    
03660    /* Append the statements to the tokens */
03661    Append_And_Reclaim_Token_List(tokens, &stmt_tokens);
03662 
03663    if (new_func_scope && W2C_Purple_Emission &&
03664        strcmp(W2C_Object_Name(PUINFO_FUNC_ST), WN2C_Purple_Region_Name) == 0)
03665    {
03666       /* <#PRP_XSYM:TEST name, id, sclass, export#>
03667        */
03668       Append_Indented_Newline(tokens, 1);
03669       Append_Token_String(tokens, "<#PRP_XSYM:TEST");
03670       WN2C_Append_Purple_Funcinfo(tokens);
03671       Append_Token_String(tokens, "#>");
03672    }
03673 
03674    /* The curly brackets for a scope are not indented, so recover
03675     * the previous indentation before emitting the '}' token.
03676     */
03677    if (!new_func_scope)
03678    {
03679       Decrement_Indentation();
03680       Append_Indented_Newline(tokens, 1);
03681       Append_Token_Special(tokens, '}');
03682    }
03683 
03684    status = EMPTY_STATUS;
03685    STATUS_set_block(status);
03686    return status;
03687 } /* WN2C_block */
03688 
03689 
03690 static STATUS
03691 WN2C_region(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
03692 {
03693    /* Emit region #pragma, the WN_region_pragmas, and the 
03694     * WN_region_body.
03695     */
03696    RID *rid;
03697    BOOL good_rid; 
03698 
03699    Is_True(WN_operator(wn) == OPR_REGION, 
03700            ("Invalid operator for WN2C_region()"));
03701 
03702    Is_True(WN_operator(WN_region_body(wn)) == OPR_BLOCK, 
03703            ("Expected OPR_BLOCK as body of OPR_REGION in WN2C_region()"));
03704 
03705    if (W2C_Prompf_Emission)
03706       WN2C_Start_Prompf_Transformed_Region(tokens, wn, context);
03707 
03708    good_rid = RID_map >= 0; 
03709    if (good_rid) 
03710      rid = (RID *)WN_MAP_Get(RID_map, wn);
03711    if (W2C_Emit_All_Regions ||
03712        (!W2C_No_Pragmas && good_rid && 
03713         (rid == NULL          ||             /* == RID_TYPE_pragma */
03714          RID_type(rid) == RID_TYPE_pragma))) /* User defined region */
03715    {
03716       WN2C_Append_Pragma_Newline(tokens, CONTEXT_srcpos(context));
03717       Append_Token_String(tokens, "#pragma");
03718       Append_Token_String(tokens, "region_begin");
03719 
03720       /* Emit the pragmas that are associated with regions and that have
03721        * a corresponding pragma in the source language.
03722        */
03723       if (!W2C_No_Pragmas)
03724          WN2C_pragma_list_begin(tokens, 
03725                                 WN_first(WN_region_pragmas(wn)),
03726                                 context);
03727       
03728       if (WN_first(WN_region_body(wn)) != NULL)
03729          WN2C_Translate_Stmt_Sequence(tokens, 
03730                                       WN_first(WN_region_body(wn)), 
03731                                       TRUE/*first_on_newline*/,
03732                                       context);
03733 
03734       if (!W2C_No_Pragmas)
03735          WN2C_pragma_list_end(tokens, 
03736                               WN_first(WN_region_pragmas(wn)),
03737                               context);
03738    
03739       WN2C_Append_Pragma_Newline(tokens, WN_Get_Linenum(wn));
03740       Append_Token_String(tokens, "#pragma");
03741       Append_Token_String(tokens, "region_end");
03742    }
03743    else
03744    {
03745       if (!W2C_No_Pragmas)
03746          WN2C_pragma_list_begin(tokens, 
03747                                 WN_first(WN_region_pragmas(wn)),
03748                                 context);
03749 
03750       /* Emit the body of the region, making the actual region 
03751        * markings completely transparent.
03752        */
03753       if (WN_first(WN_region_body(wn)) != NULL)
03754          WN2C_Translate_Stmt_Sequence(tokens, 
03755                                       WN_first(WN_region_body(wn)), 
03756                                       TRUE/*first_on_newline*/,
03757                                       context);
03758 
03759       if (!W2C_No_Pragmas)
03760          WN2C_pragma_list_end(tokens, 
03761                               WN_first(WN_region_pragmas(wn)),
03762                               context);
03763    } /* if emit pragma */
03764 
03765    if (W2C_Prompf_Emission)
03766       WN2C_End_Prompf_Transformed_Region(tokens, wn, context);
03767 
03768    return EMPTY_STATUS;
03769 } /* WN2C_region */
03770 
03771 
03772 static STATUS
03773 WN2C_compgoto(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
03774 {
03775    /* The WN_compgoto_num_cases field gives the number of entries in 
03776     * the jump table.  Kid0 is the switch value, which is a zero-
03777     * based ordinal pointer into the switch cases represented by 
03778     * kid1.  Kid1 is a block statement with a goto statement per
03779     * case.  Kid2 is a lone OPR_GOTO node which gives the default 
03780     * jump target if the value lies outside the range of the jump
03781     * table.  If the kid_count is 2, then it is assumed that the 
03782     * jump target lies within the range of the jump-table, and we 
03783     * should not access kid2.
03784     *
03785     * We generate a switch statement controlled by kid0, with a case
03786     * for each entry in the switch table represented by kid1.  The
03787     * switch statement will have a default case corresponding to
03788     * kid2, unless the kid_count is 2.
03789     */
03790    const WN *goto_stmt;
03791    INT32     goto_entry;
03792    MTYPE     switch_mty;
03793    STATUS    status = EMPTY_STATUS;
03794    OPCODE    myopcode;
03795    const  WN *compgotoid;
03796    
03797    Is_True(WN_operator(wn) == OPR_COMPGOTO,
03798            ("Invalid operator for WN2C_compgoto()"));
03799 
03800    /* Emit the switch control */
03801    /* FMZ-fix bug for switch based on a field of structure-type variable*/ 
03802   //  switch_mty = TY_mtype(WN_Tree_Type(WN_compgoto_idx(wn)));
03803    compgotoid = WN_compgoto_idx(wn);
03804    myopcode   = WN_opcode(compgotoid); 
03805    if (OPCODE_has_field_id(myopcode) && WN_field_id(compgotoid)) 
03806          switch_mty = WN_rtype(compgotoid);
03807    else
03808          switch_mty = TY_mtype(WN_Tree_Type(compgotoid));
03809 
03810    Append_Token_String(tokens, "switch");
03811    Append_Token_Special(tokens, '(');
03812    (void)WN2C_translate(tokens, WN_compgoto_idx(wn), context);
03813    Append_Token_Special(tokens, ')');
03814    
03815    /* Emit the beginning of the switch body */
03816    Append_Indented_Newline(tokens, 1);
03817    Append_Token_Special(tokens, '{');
03818    Append_Indented_Newline(tokens, 1);
03819 
03820    /* Emit each of the cases, possibly followed by a default case */
03821    goto_stmt = WN_first(WN_compgoto_table(wn));
03822    for (goto_entry = 0; goto_entry < WN_compgoto_num_cases(wn); goto_entry++)
03823    {
03824       Is_True(WN_operator(goto_stmt) == OPR_GOTO,
03825               ("Expected each COMPGOTO case to be an OPR_GOTO"));
03826       Append_Token_String(tokens, "case");
03827       TCON2C_translate(tokens, Host_To_Targ(switch_mty, goto_entry));
03828       Append_Token_Special(tokens, ':');
03829       Increment_Indentation();
03830       Append_Indented_Newline(tokens, 1);
03831       (void)WN2C_translate(tokens, goto_stmt, context);
03832       Append_Token_Special(tokens, ';');
03833       Decrement_Indentation();
03834       Append_Indented_Newline(tokens, 1);
03835       goto_stmt = WN_next(goto_stmt);
03836    }
03837    if (WN_compgoto_has_default_case(wn))
03838    {
03839       goto_stmt = WN_kid(wn,2);
03840       Is_True(WN_operator(goto_stmt) == OPR_GOTO,
03841               ("Expected COMPGOTO default case to be an OPR_GOTO"));
03842 
03843       Append_Token_String(tokens, "default");
03844       Append_Token_Special(tokens, ':');
03845       Increment_Indentation();
03846       Append_Indented_Newline(tokens, 1);
03847       (void)WN2C_translate(tokens, goto_stmt, context);
03848       Append_Token_Special(tokens, ';');
03849       Decrement_Indentation();
03850       Append_Indented_Newline(tokens, 1);
03851    }
03852       
03853    /* Emit the end of the switch body */
03854    Append_Token_Special(tokens, '}');
03855 
03856    STATUS_set_block(status);
03857    return status;
03858 } /* WN2C_compgoto */
03859 
03860 
03861 static STATUS
03862 WN2C_switch(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
03863 {
03864    /* The WN_switch_num_cases field gives the number of entries in 
03865     * the case table.  Kid0 is the switch value, which is an
03866     * integral case-value for the switch cases in kid1.  Kid2 is 
03867     * a lone OPR_CASEGOTO node, which gives the default jump target
03868     * when the value lies outside the range of the case table.  If
03869     * the kid_count is 2, then it is assumed that the jump target
03870     * lies within the range of the jump-table, and we should not 
03871     * access kid2.
03872     *
03873     * We generate a switch statement controlled by kid0, with a case
03874     * for each entry in the switch table represented by kid1.  The
03875     * switch statement will have a default case corresponding to
03876     * kid2, unless the kid_count is 2.
03877     *
03878     * This is a little closer to a regular C switch-statement than
03879     * the compgoto statement, but only slightly more so.  We abandon
03880     * the idea of moving the code for each case in under "case" 
03881     * statements, since this seems a prohibitively difficult task in
03882     * the presence of nested switch-statements and possible code-
03883     * motion,inlining, etc. from optimizer phases.
03884     */
03885    const WN *goto_stmt;
03886    MTYPE     switch_mty;
03887    STATUS    status = EMPTY_STATUS;
03888    OPCODE    myopcode;
03889    const  WN *compgotoid;
03890 
03891    Is_True(WN_operator(wn) == OPR_SWITCH, 
03892            ("Invalid operator for WN2C_switch()"));
03893 
03894    compgotoid = WN_compgoto_idx(wn);
03895    myopcode   = WN_opcode(compgotoid);
03896 
03897    /* Emit the switch control */
03898    /* FMZ-fix bug for switch based on a field of structure-type variable*/ 
03899 //   switch_mty = TY_mtype(WN_Tree_Type(WN_compgoto_idx(wn)));
03900 
03901    if (OPCODE_has_field_id(myopcode) && WN_field_id(compgotoid))
03902          switch_mty = WN_rtype(compgotoid);
03903    else
03904          switch_mty = TY_mtype(WN_Tree_Type(compgotoid));
03905 
03906    Append_Token_String(tokens, "switch");
03907    Append_Token_Special(tokens, '(');
03908    (void)WN2C_translate(tokens, WN_switch_test(wn), context);
03909    Append_Token_Special(tokens, ')');
03910    
03911    /* Emit the beginning of the switch body */
03912    Append_Indented_Newline(tokens, 1);
03913    Append_Token_Special(tokens, '{');
03914    Append_Indented_Newline(tokens, 1);
03915 
03916    /* Emit each of the cases, possibly followed by a default case */
03917    for (goto_stmt = WN_first(WN_switch_table(wn));
03918         goto_stmt != NULL;
03919         goto_stmt = WN_next(goto_stmt))
03920    {
03921       Is_True(WN_operator(goto_stmt) == OPR_CASEGOTO,
03922               ("Expected each SWITCH case to be an OPR_CASEGOTO"));
03923       Append_Token_String(tokens, "case");
03924 
03925       TCON2C_translate(tokens, 
03926                        Host_To_Targ(switch_mty, WN_const_val(goto_stmt)));
03927 
03928       Append_Token_Special(tokens, ':');
03929       Increment_Indentation();
03930       Append_Indented_Newline(tokens, 1);
03931       (void)WN2C_translate(tokens, goto_stmt, context);
03932       Append_Token_Special(tokens, ';');
03933       Decrement_Indentation();
03934       Append_Indented_Newline(tokens, 1);
03935    }
03936    if (WN_switch_has_default_case(wn))
03937    {
03938       goto_stmt = WN_switch_default(wn);
03939       Is_True(WN_operator(goto_stmt) == OPR_GOTO,
03940               ("Expected SWITCH default case to be an OPR_GOTO"));
03941 
03942       Append_Token_String(tokens, "default");
03943       Append_Token_Special(tokens, ':');
03944       Increment_Indentation();
03945       Append_Indented_Newline(tokens, 1);
03946       (void)WN2C_translate(tokens, goto_stmt, context);
03947       Append_Token_Special(tokens, ';');
03948       Decrement_Indentation();
03949       Append_Indented_Newline(tokens, 1);
03950    }
03951       
03952    /* Emit the end of the switch body */
03953    Append_Token_Special(tokens, '}');
03954    STATUS_set_block(status);
03955    return status;
03956 } /* WN2C_switch */
03957 
03958 
03959 static STATUS
03960 WN2C_do_loop(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
03961 {
03962    /* Strictly speaking, the rhs of the termination test and the rhs of
03963     * the induction increment expression should be evaluated only once.
03964     * However, we assume any side-effect expressions have been removed
03965     * and assigned to temporaries, so we ignore this requirement for now.
03966     */
03967    STATUS    status;
03968    const WN *loop_info;
03969    
03970    Is_True(WN_operator(wn) == OPR_DO_LOOP,
03971            ("Invalid operator for WN2C_do_loop()"));
03972 
03973    if (W2C_Prompf_Emission)
03974    {
03975       WN2C_Start_Prompf_Transformed_Loop(tokens, wn, context);
03976    }
03977    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
03978    
03979    loop_info = WN_do_loop_info(wn);
03980    if (W2C_Emit_Cgtag && loop_info != NULL)
03981    {
03982       Append_Token_String(tokens, "/* LOOPINFO #");
03983       Append_Token_String(tokens, Number_as_String((UINT64)loop_info, "%ull"));
03984       Append_Token_String(tokens, "*/");
03985       Append_Indented_Newline(tokens, 1);
03986    }
03987 
03988    /* Emit the loop header as a for-loop */
03989    Append_Token_String(tokens, "for");
03990    Append_Token_Special(tokens, '(');
03991    (void)WN2C_translate(tokens, WN_start(wn), context);
03992    Append_Token_Special(tokens, ';');
03993    (void)WN2C_translate(tokens, WN_end(wn), context);
03994    Append_Token_Special(tokens, ';');
03995    (void)WN2C_translate(tokens, WN_step(wn), context);
03996    Append_Token_Special(tokens, ')');
03997 
03998    /* Emit the loop body on the next line */
03999    WN2C_incr_indentation_for_stmt_body(WN_do_body(wn));
04000    CONTEXT_set_srcpos(context, WN_Get_Linenum(WN_do_body(wn)));
04001    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
04002    status = WN2C_translate(tokens, WN_do_body(wn), context);
04003    WN2C_decr_indentation_for_stmt_body(WN_do_body(wn));
04004 
04005    if (W2C_Prompf_Emission)
04006       WN2C_End_Prompf_Transformed_Loop(tokens, wn, context);
04007 
04008    return status;
04009 } /* WN2C_do_loop */
04010 
04011 
04012 static STATUS
04013 WN2C_do_while(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04014 {
04015    /* A simple do-loop as in C */
04016    
04017    Is_True(WN_operator(wn) == OPR_DO_WHILE,
04018            ("Invalid operator for WN2C_do_while()"));
04019    
04020    if (W2C_Prompf_Emission)
04021       WN2C_Start_Prompf_Transformed_Loop(tokens, wn, context);
04022 
04023    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
04024 
04025    /* Emit the header of the do-loop */
04026    Append_Token_String(tokens, "do");
04027 
04028    /* Emit the loop body on the next line */
04029    WN2C_incr_indentation_for_stmt_body(WN_while_body(wn));
04030    CONTEXT_set_srcpos(context, WN_Get_Linenum(WN_while_body(wn)));
04031    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
04032    (void)WN2C_translate(tokens, WN_while_body(wn), context);
04033    WN2C_decr_indentation_for_stmt_body(WN_while_body(wn));
04034 
04035    /* Emit the tail of the do-loop on a new line */
04036    WN2C_Stmt_Newline(tokens, WN_Get_Linenum(wn));
04037    Append_Token_String(tokens, "while");
04038    Append_Token_Special(tokens, '(');
04039    (void)WN2C_translate(tokens, WN_while_test(wn), context);
04040    Append_Token_Special(tokens, ')');
04041 
04042    if (W2C_Prompf_Emission)
04043       WN2C_End_Prompf_Transformed_Loop(tokens, wn, context);
04044 
04045    return EMPTY_STATUS;
04046 } /* WN2C_do_while */
04047 
04048 
04049 static STATUS 
04050 WN2C_while_do(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04051 {
04052    /* A simple while-loop as in C */
04053    STATUS status;
04054    
04055    Is_True(WN_operator(wn) == OPR_WHILE_DO,
04056            ("Invalid operator for WN2C_while_do()"));
04057    
04058    if (W2C_Prompf_Emission)
04059    {
04060       WN2C_Start_Prompf_Transformed_Loop(tokens, wn, context);
04061    }
04062    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
04063 
04064    /* Emit the loop header as a while-loop */
04065    Append_Token_String(tokens, "while");
04066    Append_Token_Special(tokens, '(');
04067    (void)WN2C_translate(tokens, WN_while_test(wn), context);
04068    Append_Token_Special(tokens, ')');
04069 
04070    /* Emit the loop body on the next line */
04071    WN2C_incr_indentation_for_stmt_body(WN_while_body(wn));
04072    CONTEXT_set_srcpos(context, WN_Get_Linenum(WN_while_body(wn)));
04073    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
04074    status = WN2C_translate(tokens, WN_while_body(wn), context);
04075    WN2C_decr_indentation_for_stmt_body(WN_while_body(wn));
04076 
04077    if (W2C_Prompf_Emission)
04078       WN2C_End_Prompf_Transformed_Loop(tokens, wn, context);
04079 
04080    return status;
04081 } /* WN2C_while_do */
04082 
04083 
04084 static STATUS
04085 WN2C_if(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04086 {
04087    STATUS status;
04088    
04089    Is_True(WN_operator(wn) == OPR_IF, ("Invalid operator for WN2C_if()"));
04090 
04091    /* Ignore if-guards inserted by lno, since these are redundant
04092     * in High WHIRL.
04093     */
04094    if (WN_Is_If_Guard(wn))
04095    {
04096       /* Emit only the THEN body, provided it is non-empty */
04097       if (WN_operator(WN_then(wn)) != OPR_BLOCK)
04098       {
04099          CONTEXT_set_srcpos(context, WN_Get_Linenum(WN_then(wn)));
04100          status = WN2C_translate(tokens, WN_then(wn), context);
04101       }
04102       else
04103       {
04104          WN2C_Translate_Stmt_Sequence(
04105             tokens, WN_first(WN_then(wn)), FALSE/*on_newline*/, context);
04106       } /* if then-block */
04107    }
04108    else /* Not a redundant guard (from whirl2c perspective) */
04109    {
04110       /* Emit the "if" header */
04111       Append_Token_String(tokens, "if");
04112       Append_Token_Special(tokens, '(');
04113       (void)WN2C_translate(tokens, WN_if_test(wn), context);
04114       Append_Token_Special(tokens, ')');
04115 
04116       /* Emit the THEN body on a new line */
04117       WN2C_incr_indentation_for_stmt_body(WN_then(wn));
04118       CONTEXT_set_srcpos(context, WN_Get_Linenum(WN_then(wn)));
04119       WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
04120       status = WN2C_translate(tokens, WN_then(wn), context);
04121       WN2C_decr_indentation_for_stmt_body(WN_then(wn));
04122 
04123       /* See if there is anything but an empty else-part */
04124       if (!WN_else_is_empty(wn))
04125       {
04126          /* Emit the "else" keyword and the else-body on a new line */
04127          Append_Indented_Newline(tokens, 1);
04128          Append_Token_String(tokens, "else");
04129          WN2C_incr_indentation_for_stmt_body(WN_else(wn));
04130          CONTEXT_set_srcpos(context, WN_Get_Linenum(WN_else(wn)));
04131          WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
04132          status = WN2C_translate(tokens, WN_else(wn), context);
04133          WN2C_decr_indentation_for_stmt_body(WN_else(wn));
04134       }
04135    } /* if WN_Is_If_Guard */
04136    
04137    return status;
04138 } /* WN2C_if */
04139 
04140 
04141 static STATUS
04142 WN2C_goto(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04143 {
04144    Is_True(WN_operator(wn) == OPR_GOTO ||
04145            WN_operator(wn) == OPR_CASEGOTO ||
04146            WN_operator(wn) == OPR_REGION_EXIT,
04147            ("Invalid operator for WN2C_goto()"));
04148    Append_Token_String(tokens, "goto");
04149    WN2C_append_label_name(tokens, wn);
04150 
04151    return EMPTY_STATUS;
04152 } /* WN2C_goto */
04153 
04154 
04155 static STATUS
04156 WN2C_altentry(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04157 {
04158    /* TODO: Handle OPR_ALTENTRY in C?? */
04159    Is_True(WN_operator(wn) == OPR_ALTENTRY,
04160            ("Invalid operator for WN2C_altentry()"));
04161    Append_Token_String(tokens, "__OPR_ALTENTRY");
04162    Append_Token_Special(tokens, '(');
04163    Append_Token_String(tokens, ST_name(WN_st(wn)));
04164    Append_Token_Special(tokens, ')');
04165 
04166    return EMPTY_STATUS;
04167 } /* WN2C_altentry */
04168 
04169 
04170 static STATUS
04171 WN2C_condbr(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04172 {
04173    Is_True(WN_operator(wn) == OPR_TRUEBR || WN_operator(wn) == OPR_FALSEBR,
04174            ("Invalid operator for WN2C_condbr()"));
04175 
04176    /* Check the condition, which must be true to do the branch */
04177    Append_Token_String(tokens, "if");
04178    Append_Token_Special(tokens, '(');
04179    if (WN_operator(wn) == OPR_FALSEBR)
04180    {
04181       Append_Token_Special(tokens, '!');
04182       Append_Token_Special(tokens, '(');
04183       (void)WN2C_translate(tokens, WN_condbr_cond(wn), context);
04184       Append_Token_Special(tokens, ')');
04185    }
04186    else /* WN_operator(wn) == OPR_TRUEBR */
04187    {
04188       (void)WN2C_translate(tokens, WN_condbr_cond(wn), context);
04189    }
04190    Append_Token_Special(tokens, ')');
04191    
04192    /* Emit the branch part as a goto statement on a new line */
04193    Increment_Indentation();
04194    Append_Indented_Newline(tokens, 1);
04195    Append_Token_String(tokens, "goto");
04196    WN2C_append_label_name(tokens, wn);
04197    Decrement_Indentation();
04198 
04199    return EMPTY_STATUS;
04200 } /* WN2C_condbr */
04201 
04202 
04203 static STATUS
04204 WN2C_return(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04205 {
04206    /* Note that we either return through the first parameter, or
04207     * a preg.  This is given by the PUinfo.
04208     */
04209    Is_True(WN_operator(wn) == OPR_RETURN,
04210            ("Invalid operator for WN2C_return()"));
04211    Is_True(RETURNSITE_return(WN2C_Next_ReturnSite) == wn,
04212            ("RETURNSITE out of sequence in WN2C_return()"));
04213 
04214    if (PUINFO_RETURN_TY != (TY_IDX) 0 && 
04215        TY_kind(PUINFO_RETURN_TY) != KIND_VOID &&
04216        RETURN_PREG_mtype(PUinfo_return_preg, 0) != MTYPE_V)
04217    {
04218       WN2C_Function_Return_Value(tokens, context);
04219    }
04220    else /* nothing to return */
04221    {
04222       Append_Token_String(tokens, "return");
04223    }
04224 
04225    WN2C_Next_ReturnSite = RETURNSITE_next(WN2C_Next_ReturnSite);
04226    
04227    return EMPTY_STATUS;
04228 } /* WN2C_return */
04229 
04230 static STATUS
04231 WN2C_return_val(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04232 {
04233    char buf[64];
04234    Is_True(WN_operator(wn) == OPR_RETURN_VAL,
04235            ("Invalid operator for WN2C_return_val()"));
04236    Append_Token_String(tokens, "return ");
04237    Append_Token_Special(tokens, '(');
04238    (void) WN2C_translate(tokens, WN_kid0(wn), context);
04239    Append_Token_Special(tokens, ')');
04240    return EMPTY_STATUS;
04241 } /* WN2C_return_val */
04242 
04243 static STATUS
04244 WN2C_label(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04245 {
04246    Is_True(WN_operator(wn) == OPR_LABEL,
04247            ("Invalid operator for WN2C_label()"));
04248 
04249    WN2C_append_label_name(tokens, wn);
04250    Append_Token_Special(tokens, ':');
04251 
04252    return EMPTY_STATUS;
04253 } /* WN2C_label */
04254 
04255 
04256 static STATUS 
04257 WN2C_exc_scope_end(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04258 {
04259    UINT current_indent = Current_Indentation();
04260 
04261    Set_Current_Indentation(0);
04262    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
04263    Append_Token_String(tokens, "#pragma");
04264    Set_Current_Indentation(current_indent);
04265    Append_Token_String(tokens, "EXCEPTION_SCOPE_END");
04266    return EMPTY_STATUS;
04267 } /* WN2C_exc_scope_end */
04268 
04269 
04270 static STATUS 
04271 WN2C_exc_scope_begin(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04272 {
04273    UINT current_indent = Current_Indentation();
04274 
04275    Set_Current_Indentation(0);
04276    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
04277    Append_Token_String(tokens, "#pragma");
04278    Set_Current_Indentation(current_indent);
04279    Append_Token_String(tokens, "EXCEPTION_SCOPE_BEGIN");
04280    return EMPTY_STATUS;
04281 } /* WN2C_exc_scope_begin */
04282 
04283 
04284 static STATUS
04285 WN2C_istore(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04286 {
04287    /* Get the lvalue for the lhs (kid1), and the value of the rhs
04288     * (kid0), and assign the rhs to the lhs.
04289     */
04290    TY_IDX       stored_ty;
04291    TOKEN_BUFFER lhs_tokens;
04292    
04293    Is_True(WN_operator(wn) == OPR_ISTORE || 
04294            (WN_operator(wn) == OPR_STID && 
04295             ST_sclass(WN_st(wn)) == SCLASS_FORMAL_REF),
04296            ("Invalid operator for WN2C_istore()"));
04297    Is_True(WN_operator(wn) != OPR_ISTORE || TY_Is_Pointer(WN_ty(wn)),
04298            ("Expected WN_ty to be a pointer for WN2C_istore()"));
04299 
04300 
04301    /* See if there is any prefetch information with this store */
04302    /* Insert prefetch for stores BEFORE the store */
04303    if (W2C_Emit_Prefetch && WN_MAP_Get(WN_MAP_PREFETCH, wn))
04304      WN2C_Prefetch_Map(tokens, wn, context); /* between newlines */
04305 
04306    /* Get lhs of the indirect assignment
04307    */
04308    lhs_tokens = New_Token_Buffer();
04309    if (WN_operator(wn) == OPR_STID)
04310    {
04311       char lhs_address_area [sizeof (WN)];
04312       WN* lhs_address = (WN*) &lhs_address_area;;
04313 
04314       WN2C_create_ref_param_lda(lhs_address, wn);
04315       WN2C_memref_lhs(lhs_tokens, 
04316                       &stored_ty,
04317                       lhs_address,         /* lhs address */
04318                       WN_store_offset(wn), /* offset from this address */
04319                       WN_ty(lhs_address),  /* ref type for stored object */
04320                       WN_ty(wn),           /* type for stored object */
04321                       WN_opc_dtype(wn),    /* base-type for stored object */
04322                       context);
04323    }
04324    else
04325    {
04326      //WEI:  if lhs is a field access (e.g. f1->x), we want the type of the field 
04327      //instead of the struct
04328      TY_IDX base_ty = TY_pointed(WN_ty(wn));
04329      TY_IDX actual_ty = (WN_field_id(wn) > 0) ? Make_Pointer_Type(Get_Field_Type(base_ty, WN_field_id(wn))) : WN_ty(wn);
04330 
04331       WN2C_memref_lhs(lhs_tokens, 
04332                       &stored_ty,
04333                       WN_kid1(wn),         /* lhs address */
04334                       WN_store_offset(wn), /* offset from this address */
04335                       actual_ty,
04336                       //WN_ty(wn),           /* ref type for stored object */
04337                       TY_pointed(actual_ty),
04338                       //TY_pointed(WN_ty(wn)), /* type for stored object */
04339                       WN_opc_dtype(wn),    /* base-type for stored object */
04340                       context);
04341    }
04342 
04343    //
04344    
04345    /* Do the assignment */
04346    WN2C_Append_Assignment(tokens, 
04347                           &lhs_tokens, /* lhs */
04348                           WN_kid0(wn), /* rhs */
04349                           stored_ty,   /* expected type of rhs */
04350                           context);
04351 
04352    return EMPTY_STATUS;
04353 } /* WN2C_istore */
04354 
04355 
04356 static STATUS
04357 WN2C_istorex(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04358 {
04359    /* Both kid1 and kid2 must be LDID nodes representing pregs.
04360     * Load the contents of the pregs, add them together, and
04361     * store kid0 into the resultant address.  The assignment is
04362     * typed according to the WN_ty.
04363     */
04364    TY_IDX       object_ty;
04365    TOKEN_BUFFER lhs_tokens;
04366 
04367    Is_True((WN_operator(wn) == OPR_ISTOREX             &&
04368             WN_operator(WN_kid1(wn)) == OPR_LDID       &&
04369             WN_operator(WN_kid(wn,2)) == OPR_LDID      &&
04370             ST_sym_class(WN_st(WN_kid1(wn))) == CLASS_PREG &&
04371             ST_sym_class(WN_st(WN_kid(wn,2))) == CLASS_PREG),
04372            ("Invalid WN tree for WN2C_istorex()"));
04373    Is_True(TY_Is_Pointer(WN_ty(wn)),
04374            ("Expected WN_ty to be a pointer for WN2C_istorex()"));
04375 
04376    /* Get the type of object being stored */
04377    object_ty =
04378       WN2C_MemAccess_Type(TY_pointed(WN_ty(wn)),     /* base_type */
04379                           WN_Tree_Type(WN_kid0(wn)), /* preferred type */
04380                           WN_opc_dtype(wn),          /* required mtype */
04381                           WN_store_offset(wn));      /* offset from base */
04382 
04383    lhs_tokens = New_Token_Buffer();
04384    WN2C_Load_From_PregIdx(lhs_tokens, 
04385                           WN_st(WN_kid1(wn)),           /* preg1 */
04386                           WN_load_offset(WN_kid1(wn)),  /* preg_idx1 */
04387                           WN_st(WN_kid(wn,2)),          /* preg2 */
04388                           WN_load_offset(WN_kid(wn,2)), /* preg_idx2 */
04389                           object_ty,                    /* result type */
04390                           context);
04391    
04392    /* Do the assignment */
04393    WN2C_Append_Assignment(tokens, 
04394                           &lhs_tokens, /* lhs */
04395                           WN_kid0(wn), /* rhs */
04396                           object_ty,   /* expected type of rhs */
04397                           context);
04398 
04399    return EMPTY_STATUS;
04400 } /* WN2C_istorex */
04401 
04402 
04403 static STATUS
04404 WN2C_mstore(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04405 {
04406    /* We have (MSTORE (MLOAD ...) (...)), or, alternatively an MSTORE of
04407     * a scalar into successive locations.  For a store of a MLOAD,
04408     * translate into a call to the "__MSTORE" builtin function, unless 
04409     * we have a struct copy ... in which case we try to be more clever 
04410     * and just do a regular assignment.
04411     */
04412    TY_IDX       base_ty;
04413    TY_IDX       stored_ty;
04414    TOKEN_BUFFER lhs_tokens;
04415    STATUS       lhs_status;
04416    
04417    Is_True(WN_operator(wn) == OPR_MSTORE,
04418            ("Invalid operator for WN2C_mstore()"));
04419    Is_True(TY_Is_Pointer(WN_ty(wn)),
04420            ("Expected WN_ty to be a pointer for WN2C_mstore()"));
04421 
04422    /* Get the type of object being stored */
04423    base_ty = WN_Tree_Type(WN_kid1(wn));
04424    if (!TY_Is_Pointer(base_ty))
04425       base_ty = WN_ty(wn);
04426    stored_ty = TY_pointed(WN_ty(wn));
04427 
04428    if (WN_field_id(wn) != 0) {
04429      //use the field's type instead
04430      stored_ty = Get_Field_Type(stored_ty, WN_field_id(wn));
04431    } else {
04432      stored_ty = 
04433        WN2C_MemAccess_Type(TY_pointed(base_ty),  /* base_type */
04434                            stored_ty,            /* preferred type */
04435                            MTYPE_M,              /* required mtype */
04436                            WN_store_offset(wn)); /* offset from base */
04437    }
04438 
04439    //WEI: an ugly hack that should probably go in be, but I can't get it work there
04440    //without breaking other stuff(threadof, affinity, etc)...
04441    if (WN_operator(WN_kid0(wn)) == OPR_TAS) {
04442      WN_kid0((WN*) wn) = WN_kid0(WN_kid0(wn));
04443    }
04444 
04445    if (WN_operator(WN_kid0(wn)) == OPR_MLOAD)
04446    {
04447       /* Use a regular struct assignment, provided the object stored has
04448        * been found to be a struct and the size of the MLOAD is known.
04449        */
04450       if (TY_Is_Structured(stored_ty) && 
04451           WN_operator(WN_kid1(WN_kid0(wn))) == OPR_INTCONST)
04452       {
04453          /* Get the lhs, preferably as an lvalue, but possibly as an address.
04454           */
04455          lhs_tokens = New_Token_Buffer();
04456          lhs_status = WN2C_lvalue_wn(lhs_tokens,
04457                                      WN_kid1(wn), /* the base address */
04458                                      base_ty,   /* the base addr_ty */
04459                                      stored_ty, /* type of obj to be stored */
04460                                      WN_store_offset(wn),
04461                                      context);
04462 
04463          /* Dereference the address into which we are storing, if necessary.
04464           */
04465          if (!STATUS_is_lvalue(lhs_status))
04466             Prepend_Token_Special(lhs_tokens, '*');
04467    
04468          /* Do the assignment */
04469          WN2C_Append_Assignment(tokens, 
04470                                 &lhs_tokens, /* lhs */
04471                                 WN_kid0(wn), /* rhs */
04472                                 stored_ty,   /* expected type of rhs */
04473                                 context);
04474       }
04475       else
04476       {
04477          /* Need to copy byte by byte, from kid0 to kid1 */
04478          Append_Token_String(tokens, "__MSTORE");
04479          Append_Token_Special(tokens, '(');
04480          (void)WN2C_translate(tokens, WN_kid0(WN_kid0(wn)), context);
04481          Append_Token_Special(tokens, ',');
04482          TCON2C_translate(tokens, 
04483                           Host_To_Targ(MTYPE_I8, WN_load_offset(WN_kid0(wn))));
04484          Append_Token_Special(tokens, ',');
04485          (void)WN2C_translate(tokens, WN_kid1(wn), context);
04486          Append_Token_Special(tokens, ',');
04487          TCON2C_translate(tokens, Host_To_Targ(MTYPE_I8, WN_store_offset(wn)));
04488 
04489          Append_Token_Special(tokens, ',');
04490          (void)WN2C_translate(tokens, WN_kid(wn,2), context); /* bytes */
04491          Append_Token_Special(tokens, ')');
04492       } /*if*/
04493    }
04494    else
04495    {
04496       TY_IDX      rhs_ty = WN_Tree_Type(WN_kid0(wn));
04497       TY_IDX      rhs_ptr = Stab_Pointer_To(rhs_ty);
04498       const INT32 rhs_size = TY_size(rhs_ty);
04499       const UINT  tmp_idx1 = Stab_Lock_Tmpvar(rhs_ty, ST2C_Declare_Tempvar);
04500       const UINT  tmp_idx2 = Stab_Lock_Tmpvar(rhs_ptr, ST2C_Declare_Tempvar);
04501       const char *induction_var_name = W2CF_Symtab_Nameof_Tempvar(tmp_idx1);
04502       const char *ptr_var_name = W2CF_Symtab_Nameof_Tempvar(tmp_idx2);
04503 
04504       /* Assign the address we are to store into into the "ptr_var_name",
04505        * taking into account the store offset.
04506        */
04507       Append_Token_String(tokens, ptr_var_name);
04508       Append_Token_Special(tokens, '=');
04509       WN2C_append_cast(tokens, rhs_ty, TRUE/*ptr_to_type*/);
04510       (void)WN2C_translate(tokens, WN_kid1(wn), context);
04511       if (WN_store_offset(wn) > 0)
04512       {
04513          Append_Token_Special(tokens, '+');
04514          TCON2C_translate(tokens, 
04515                           Host_To_Targ(MTYPE_I8, 
04516                                        WN_store_offset(wn)/rhs_size));
04517       }
04518       Append_Token_Special(tokens, ';');
04519       Append_Indented_Newline(tokens, 1);
04520 
04521       /* Set up a loop header to initiate numbytes/elementsize slots.
04522        */
04523       Append_Token_String(tokens, "for");
04524       Append_Token_Special(tokens, '(');
04525       Append_Token_String(tokens, induction_var_name);
04526       Append_Token_Special(tokens, '=');
04527       TCON2C_translate(tokens, Host_To_Targ(MTYPE_I8, 0));
04528       Append_Token_Special(tokens, ';');
04529       Append_Token_String(tokens, induction_var_name);
04530       Append_Token_Special(tokens, '<');
04531       Append_Token_Special(tokens, '(');
04532       (void)WN2C_translate(tokens, WN_kid(wn,2), context); /* bytes */
04533       Append_Token_Special(tokens, '/');
04534       TCON2C_translate(tokens, Host_To_Targ(MTYPE_I8, rhs_size));
04535       Append_Token_Special(tokens, ')');
04536       Append_Token_Special(tokens, ';');
04537       Append_Token_String(tokens, Concat2_Strings(induction_var_name, "++"));
04538       Append_Token_Special(tokens, ')');
04539 
04540       /* Copy one value at a time */
04541       Increment_Indentation();
04542       Append_Indented_Newline(tokens, 1);
04543       Append_Token_String(tokens, ptr_var_name);
04544       Append_Token_Special(tokens, '[');
04545       Append_Token_String(tokens, induction_var_name);
04546       Append_Token_Special(tokens, ']');
04547       Append_Token_Special(tokens, '=');
04548       (void)WN2C_translate(tokens, WN_kid0(wn), context);
04549       Decrement_Indentation();
04550 
04551       Stab_Unlock_Tmpvar(tmp_idx1);
04552       Stab_Unlock_Tmpvar(tmp_idx2);
04553    }
04554 
04555    return EMPTY_STATUS;
04556 } /* WN2C_mstore */
04557 
04558 
04559 static STATUS
04560 WN2C_stid(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04561 {
04562    /* Get the lvalue for the lhs (kid1), and the value of the rhs
04563     * (kid0), and assign the rhs to the lhs.
04564     */
04565    TOKEN_BUFFER lhs_tokens;
04566    TY_IDX       stored_ty;    /* Type of assignment */
04567 
04568    Is_True(WN_operator(wn) == OPR_STID,
04569            ("Invalid operator for WN2C_stid()"));
04570 
04571    if (ST_sym_class(WN_st(wn))==CLASS_VAR && ST_is_not_used(WN_st(wn)))
04572    {
04573       /* This is a redundant assignment statement, so determined
04574        * by IPA, so only generate the rhs (in case of volatiles?).
04575        */
04576       (void)WN2C_translate(tokens, WN_kid0(wn), context); /* bytes */
04577    }
04578    else if (ST_sclass(WN_st(wn)) == SCLASS_FORMAL_REF)
04579    {
04580       (void)WN2C_istore(tokens, wn, context);
04581    }
04582    else
04583    {
04584      //FIX: for field accesses, change stored type to that of the field
04585      TY_IDX stored_ty = WN_ty(wn);
04586      if (WN_field_id(wn) != 0) {
04587        stored_ty = Get_Field_Type(stored_ty, WN_field_id(wn));
04588      }
04589      /* Get the lhs expression */
04590      lhs_tokens = New_Token_Buffer();
04591      WN2C_stid_lhs(lhs_tokens,
04592                    &stored_ty,          /* Corrected stored type */
04593                    WN_st(wn),           /* base symbol */
04594                    WN_store_offset(wn), /* offset from base */
04595                    stored_ty,           /* stored type */
04596                    WN_opc_dtype(wn),    /* stored mtype */
04597                    context);
04598 
04599       /* Do the assignment */
04600       WN2C_Append_Assignment(tokens, 
04601                              &lhs_tokens, /* lhs */
04602                              WN_kid0(wn), /* rhs */
04603                              stored_ty,   /* expected type of rhs */
04604                              context);    /* Get the rhs expression */
04605    }
04606    return EMPTY_STATUS;
04607 } /* WN2C_stid */
04608 
04609 
04610 static STATUS 
04611 WN2C_call(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04612 {
04613    /* A call statement.  Generate the call and assign the return
04614     * value to the return registers, a return variable, or a temporary
04615     * return variable ... dependent on the type of value returned
04616     * and whether or not a return-variable was found during the PUinfo
04617     * analysis.
04618     */
04619    INT          arg_idx, first_arg_idx, last_arg_idx;
04620    TY_IDX       func_ty, return_ty;
04621    TYLIST_IDX   param_tylist;
04622    TOKEN_BUFFER call_tokens, arg_tokens;
04623    BOOL         return_to_param;
04624 
04625    /* Emit any relevant call-site directives
04626     */
04627    if (WN_operator(wn) == OPR_CALL || WN_operator(wn) == OPR_PICCALL)
04628    {
04629       WN2C_Callsite_Directives(tokens, wn, &St_Table[WN_entry_name(wn)],
04630                                context);
04631    }
04632 
04633    /* A buffer to hold the tokens representing the function call */
04634    call_tokens = New_Token_Buffer();
04635    
04636    /* Tokenize the function reference, and get the function type and
04637     * return type, whether or not the return is through the first 
04638     * parameter.  Also, get the range of kids representing the
04639     * actual arguments.  A NULL func_ty indicates an unknown type.
04640     */
04641    CONTEXT_reset_top_level_expr(context); /* Parenthesize func addr expr */
04642    if (WN_operator(wn) == OPR_CALL)
04643    {
04644       ST2C_use_translate(call_tokens, &St_Table[WN_entry_name(wn)], context);
04645       func_ty = ST_pu_type(&St_Table[WN_entry_name(wn)]);
04646       return_to_param = W2X_Unparse_Target->Func_Return_To_Param(func_ty);
04647       return_ty = W2X_Unparse_Target->Func_Return_Type(func_ty);
04648       first_arg_idx = (return_to_param? 1 : 0);
04649       last_arg_idx = WN_kid_count(wn) - 1;
04650    }
04651    else if (WN_operator(wn) == OPR_ICALL)
04652    {
04653       Is_True(WN_ty(wn) != (TY_IDX) 0, 
04654               ("Expected non-null WN_ty for ICALL in WN_call()"));
04655      
04656       (void)WN2C_translate(call_tokens, 
04657                            WN_kid(wn, WN_kid_count(wn) - 1), 
04658                            context);
04659 
04660       //WEI: Need to paranthesize the address of the function
04661       WHIRL2C_parenthesize(call_tokens);
04662 
04663       /* The function type used be:
04664        *
04665        *    TY_pointed(WN_Tree_Type(WN_kid(wn,WN_kid_count(wn) - 1)));
04666        *
04667        * but is now directly available as the WN_ty attribute.
04668        */
04669       func_ty = WN_ty(wn);
04670       return_to_param = W2X_Unparse_Target->Func_Return_To_Param(func_ty);
04671       return_ty = W2X_Unparse_Target->Func_Return_Type(func_ty);
04672       first_arg_idx = (return_to_param? 1 : 0);
04673       last_arg_idx = WN_kid_count(wn) - 2;
04674    }
04675    else if (WN_operator(wn) == OPR_PICCALL)
04676    {
04677       Is_True(WN_entry_name(wn) != 0, 
04678               ("Expected non-null WN_entry_name for PICCALL in WN_call()"));
04679       ST2C_use_translate(call_tokens, &St_Table[WN_entry_name(wn)], context);
04680       func_ty = ST_pu_type(&St_Table[WN_entry_name(wn)]);
04681       return_to_param = W2X_Unparse_Target->Func_Return_To_Param(func_ty);
04682       return_ty = W2X_Unparse_Target->Func_Return_Type(func_ty);
04683       first_arg_idx = (return_to_param? 1 : 0);
04684       last_arg_idx = WN_kid_count(wn) - 2;
04685    }
04686    else /* OPR_INTRINSIC_CALL */
04687    {
04688       Is_True(WN_operator(wn) == OPR_INTRINSIC_CALL,
04689               ("Invalid operator for WN2C_call()"));
04690 
04691       Append_Token_String(call_tokens,
04692                           WN_intrinsic_name((INTRINSIC)WN_intrinsic(wn)));
04693 
04694       /* Note, we may have a void return type for implicit return through
04695        * argument 0.  Should be represented by a mismatch between the
04696        * rtype (void) and the return type in the wtable!
04697        */
04698       func_ty = (TY_IDX) 0;
04699       return_ty = WN_intrinsic_return_ty(WN_opcode(wn),
04700                                          (INTRINSIC)WN_intrinsic(wn), wn);
04701       return_to_param = WN_intrinsic_return_to_param(return_ty);
04702       first_arg_idx =  (return_to_param? 1 : 0);
04703       last_arg_idx = WN_kid_count(wn) - 1;
04704    }
04705    
04706    /* Append the argument list to the function reference.  No need to
04707     * reset CONTEXT_needs_lvalue(context), since this is statement and
04708     * CONTEXT_needs_lvalue(context) must be FALSE.
04709     */
04710    Append_Token_Special(call_tokens, '(');
04711    CONTEXT_set_top_level_expr(context); /* To avoid top-level parenthesis */
04712    if (func_ty != (TY_IDX) 0 && TY_has_prototype(func_ty))
04713       param_tylist = TY_parms(func_ty);
04714    else
04715       param_tylist = (TYLIST_IDX) 0;
04716    for (arg_idx = first_arg_idx; arg_idx <= last_arg_idx; arg_idx++)
04717    {
04718       arg_tokens = New_Token_Buffer();
04719 
04720       // In translating the PARM nodes, use the actual argument type rather
04721       // than the PARM type to do casting of argument expression types.
04722       //
04723       if (Tylist_Table[param_tylist] != TY_IDX_ZERO)
04724          CONTEXT_set_given_lvalue_ty(context,
04725                                      TYLIST_item(Tylist_Table[param_tylist]));
04726       else
04727          CONTEXT_set_given_lvalue_ty(context,
04728                                      WN_Tree_Type(WN_kid(wn, arg_idx)));
04729       
04730       Is_True(WN_operator(WN_kid(wn, arg_idx)) == OPR_PARM,
04731               ("Expected OPR_PARM as CALL argument"));
04732       
04733       (void)WN2C_translate(arg_tokens, WN_kid(wn, arg_idx), context);
04734 
04735       Append_And_Reclaim_Token_List(call_tokens, &arg_tokens);
04736       if (Tylist_Table[param_tylist] != TY_IDX_ZERO)
04737          param_tylist = TYLIST_next(param_tylist);
04738       if (arg_idx < last_arg_idx)
04739          Append_Token_Special(call_tokens, ',');
04740    }
04741    Append_Token_Special(call_tokens, ')');
04742 
04743    /* Update the call site information to denote this one */
04744    if (WN2C_Prev_CallSite == NULL)
04745       WN2C_Prev_CallSite = PUinfo_Get_CallSites();
04746    else
04747       WN2C_Prev_CallSite = CALLSITE_next(WN2C_Prev_CallSite);
04748 
04749    Is_True(CALLSITE_call(WN2C_Prev_CallSite) == wn,
04750            ("CALLSITE out of sequence in WN2C_call()"));
04751 
04752    /* Next, save off the function return value to a (temporary)
04753     * variable or a return-register, as is appropriate.
04754     */
04755    if (return_ty != (TY_IDX) 0              && 
04756        TY_kind(return_ty) != KIND_VOID      &&
04757        WN_opcode(wn) != OPC_VCALL           &&
04758        WN_opcode(wn) != OPC_VICALL          &&
04759        WN_opcode(wn) != OPC_VPICCALL        &&
04760        WN_opcode(wn) != OPC_VINTRINSIC_CALL)
04761    {
04762       WN2C_Function_Call_Lhs(call_tokens,
04763                              return_to_param,
04764                              return_ty,
04765                              WN_kid0(wn), /* First Argument */
04766                              context);
04767    }
04768    Append_And_Reclaim_Token_List(tokens, &call_tokens);
04769 
04770    return EMPTY_STATUS;
04771 } /* WN2C_call */
04772 
04773 
04774 static STATUS 
04775 WN2C_eval(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04776 {
04777    /* As far as C is concerned, treat this as a transparent node! */
04778    Is_True(WN_operator(wn) == OPR_EVAL,
04779            ("Invalid operator for WN2C_eval()"));
04780 
04781    return WN2C_translate(tokens, WN_kid0(wn), context);
04782 } /* WN2C_eval */
04783 
04784 
04785 static STATUS 
04786 WN2C_prefetch(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04787 {
04788    /* Prefetch information is currently added in a comment */
04789    INT pflag;
04790    
04791    Is_True(WN_operator(wn) == OPR_PREFETCH || WN_operator(wn) == OPR_PREFETCHX,
04792            ("Invalid operator for WN2C_prefetch()"));
04793 
04794    /* Get the prefetch identifier and address expression */
04795    if (WN_operator(wn) == OPR_PREFETCH)
04796    {
04797       Append_Token_String(tokens, 
04798          Concat3_Strings("/* PREFETCH(", Ptr_as_String(wn), ")"));
04799       (void)WN2C_translate(tokens, WN_kid0(wn), context);
04800       Append_Token_String(tokens, 
04801          Concat2_Strings("OFFS=", Number_as_String(WN_offset(wn), "%lld")));
04802    }
04803    else /* (WN_operator(wn) == OPR_PREFETCHX) */
04804    {
04805       Append_Token_String(tokens, 
04806          Concat3_Strings("/* PREFETCHX(", Ptr_as_String(wn), ")"));
04807       (void)WN2C_translate(tokens, WN_kid0(wn), context);
04808       Append_Token_Special(tokens, '+');
04809       (void)WN2C_translate(tokens, WN_kid1(wn), context);
04810    }
04811       
04812    /* Emit the prefetch flags information (pf_cg.h) on a separate line */
04813    pflag = WN_prefetch_flag(wn);
04814    Set_Current_Indentation(Current_Indentation()+3);
04815    Append_Indented_Newline(tokens, 1);
04816    Append_Token_String(tokens, PF_GET_READ(pflag)? "read" : "write");
04817    Append_Token_String(tokens, 
04818       Concat2_Strings("strid1=", 
04819                       Number_as_String(PF_GET_STRIDE_1L(pflag), "%lld")));
04820    Append_Token_String(tokens, 
04821       Concat2_Strings("strid2=", 
04822                       Number_as_String(PF_GET_STRIDE_2L(pflag), "%lld")));
04823    Append_Token_String(tokens, 
04824       Concat2_Strings("conf=", 
04825                       Number_as_String(PF_GET_CONFIDENCE(pflag), "%lld"))); 
04826    Set_Current_Indentation(Current_Indentation()-3); 
04827 
04828    /* Close the comment about this prefetch */
04829    Append_Token_String(tokens, "*/");
04830 
04831    return EMPTY_STATUS;
04832 } /* WN2C_prefetch */
04833 
04834 
04835 static STATUS 
04836 WN2C_comment(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04837 {
04838    Is_True(WN_operator(wn) == OPR_COMMENT, 
04839            ("Invalid operator for WN2C_comment()"));
04840 
04841    Append_Token_String(tokens, 
04842                        Concat3_Strings("/* ", Index_To_Str(WN_GetComment(wn)), " */"));
04843 
04844    return EMPTY_STATUS;
04845 } /* WN2C_comment */
04846 
04847 
04848 static STATUS 
04849 WN2C_iload(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04850 {
04851    /* Access a data object from the location (WN_kid0 + WN_load_offset),
04852     * where the type of data loaded is of type TY_pointed(WN_load_addr_ty(wn))
04853     * or of type WN_ty(wn).  When the address type denotes a struct we
04854     * try to find an element in the struct of type WN_ty(wn) or 
04855     * WN_opc_dtype(wn), and if found we load that object, otherwise we
04856     * load an object of type TY_pointed(WN_load_addr_ty(wn)).
04857     */
04858    TY_IDX       loaded_ty;
04859    TOKEN_BUFFER expr_tokens;
04860 
04861    Is_True(WN_operator(wn) == OPR_ILOAD || 
04862            (WN_operator(wn) == OPR_LDID && 
04863             ST_sclass(WN_st(wn)) == SCLASS_FORMAL_REF),
04864            ("Invalid operator for WN2C_iload()"));
04865 
04866    /* Special case for Purple */
04867    if (W2C_Only_Mark_Loads && !TY_Is_Pointer(WN_ty(wn)))
04868    {
04869       char buf[64];
04870       sprintf(buf, "#<%p>#", wn);
04871       Append_Token_String(tokens, buf);
04872       return EMPTY_STATUS;
04873    }
04874 
04875    /* Get the type of data to be loaded from memory */
04876    expr_tokens = New_Token_Buffer();
04877    if (WN_operator(wn) == OPR_LDID)
04878    {
04879       char load_address_area [sizeof (WN)];
04880       WN* load_address = (WN*) &load_address_area;
04881 
04882       WN2C_create_ref_param_lda(load_address, wn);
04883       WN2C_memref_lhs(expr_tokens, 
04884                       &loaded_ty,
04885                       load_address,        /* lhs address */
04886                       WN_store_offset(wn), /* offset from this address */
04887                       WN_ty(load_address), /* ref type for stored object */
04888                       WN_ty(wn),           /* type for stored object */
04889                       WN_opc_dtype(wn),    /* base-type for stored object */
04890                       context);
04891    }
04892    else
04893    {
04894       WN2C_memref_lhs(expr_tokens, 
04895                       &loaded_ty,
04896                       WN_kid0(wn),         /* address */
04897                       WN_load_offset(wn),  /* offset from this address */
04898                       WN_load_addr_ty(wn), /* ref type for loaded object */
04899                       WN_ty(wn),           /* type for loaded object */
04900                       WN_opc_dtype(wn),    /* base-type for stored object */
04901                       context);
04902 
04903    }
04904 
04905    TY_IDX type_loaded = WN_Tree_Type(wn);
04906    //WEI: if we're loading a field in a struct, the type we really want is
04907    //the type pointed by WN_load_addr_ty(wn), which is the actual type of the field
04908    /*
04909      if (WN_operator(wn) == OPR_ILOAD && 
04910      WN_field_id(wn) > 0 && TY_kind(type_loaded) == KIND_STRUCT) {
04911      type_loaded = TY_pointed(WN_load_addr_ty(wn));
04912      }
04913    */
04914 
04915    /* Cast the resultant value to the expected result type if 
04916     * different from the type of value loaded.
04917     */
04918    if (!WN2C_arithmetic_compatible_types(loaded_ty, type_loaded))
04919      WN2C_prepend_cast(expr_tokens, type_loaded, FALSE/*pointer_to_type*/);
04920 
04921    Append_And_Reclaim_Token_List(tokens, &expr_tokens);
04922 
04923    /* See if there is any prefetch information with this load */
04924    if (W2C_Emit_Prefetch && WN_MAP_Get(WN_MAP_PREFETCH, wn))
04925    {
04926      Set_Current_Indentation(Current_Indentation()+3);
04927      WN2C_Prefetch_Map(tokens, wn, context); /* between newlines */
04928      Set_Current_Indentation(Current_Indentation()-3);
04929    }
04930    return EMPTY_STATUS;
04931 } /* WN2C_iload */
04932 
04933 
04934 static STATUS 
04935 WN2C_iloadx(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04936 {
04937    TY_IDX object_ty;
04938 
04939    /* Both kid0 and kid1 must be LDID nodes representing pregs.
04940     * Load the contents of the pregs, add them together, and
04941     * load an object of the given type from the resultant address.
04942     */
04943    Is_True((WN_operator(wn) == OPR_ILOADX              &&
04944             WN_operator(WN_kid0(wn)) == OPR_LDID       &&
04945             WN_operator(WN_kid1(wn)) == OPR_LDID       &&
04946             ST_sym_class(WN_st(WN_kid0(wn))) == CLASS_PREG &&
04947             ST_sym_class(WN_st(WN_kid1(wn))) == CLASS_PREG),
04948            ("Invalid WN tree for for WN2C_iloadx()"));
04949 
04950    /* Get the type of object being loaded */
04951    object_ty =
04952       WN2C_MemAccess_Type(TY_pointed(WN_load_addr_ty(wn)), /* base_type */
04953                           WN_load_addr_ty(wn),             /* preferred type */
04954                           WN_opc_dtype(wn),           /* required mtype */
04955                           WN_load_offset(wn));        /* offset from base */
04956 
04957    WN2C_Load_From_PregIdx(tokens, 
04958                           WN_st(WN_kid0(wn)),          /* preg1 */
04959                           WN_load_offset(WN_kid0(wn)), /* preg_idx1 */
04960                           WN_st(WN_kid1(wn)),          /* preg2 */
04961                           WN_load_offset(WN_kid1(wn)), /* preg_idx2 */
04962                           object_ty,                   /* type to load */
04963                           context);
04964    
04965    /* Cast the resultant value to the result type, if it is different 
04966     * from the loaded type.
04967     */
04968    if (!WN2C_arithmetic_compatible_types(object_ty, WN_ty(wn)))
04969       WN2C_prepend_cast(tokens, WN_ty(wn), FALSE/*pointer_to_type*/);
04970 
04971    return EMPTY_STATUS;
04972 } /* WN2C_iloadx */
04973 
04974 
04975 static STATUS 
04976 WN2C_mload(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
04977 {
04978    /* Load an aggregate value, presumably as a function parameter,
04979     * under an OPR_EVAL node, or as the rhs of an assignment.
04980     */
04981    TY_IDX       base_ty;
04982    TY_IDX       loaded_ty;
04983    STATUS       load_status;
04984    TOKEN_BUFFER expr_tokens;
04985    
04986    Is_True(WN_operator(wn) == OPR_MLOAD,
04987            ("Invalid operator for WN2C_mload()"));
04988    Is_True(TY_Is_Pointer(WN_ty(wn)),
04989            ("Expected WN_ty to be a pointer in WN2C_mload()"));
04990    Is_True(WN_operator(WN_kid1(wn)) == OPR_INTCONST,
04991            ("Expected statically known size for WN2C_mload()"));
04992 
04993    /* Special case for Purple (cannot be a ptr, so always do it) */
04994    if (W2C_Only_Mark_Loads)
04995    {
04996       char buf[64];
04997       sprintf(buf, "#<%p>#", wn);
04998       Append_Token_String(tokens, buf);
04999       return EMPTY_STATUS;
05000    }
05001 
05002    /* Get the type of object being stored */
05003    base_ty = WN_Tree_Type(WN_kid0(wn));
05004    if (!TY_Is_Pointer(base_ty))
05005       base_ty = WN_ty(wn);
05006    if (WN_field_id(wn) != 0) {
05007      loaded_ty = Get_Field_Type(TY_pointed(WN_ty(wn)), WN_field_id(wn));
05008    } else {
05009      loaded_ty = TY_pointed(WN_ty(wn));
05010      loaded_ty = 
05011        WN2C_MemAccess_Type(TY_pointed(base_ty), /* base_type */
05012                            loaded_ty,           /* preferred type */
05013                            MTYPE_M,             /* required mtype */
05014                            WN_load_offset(wn)); /* offset from base */
05015    }
05016 
05017    /* Get the lvalue or address of the data to be loaded */
05018    expr_tokens = New_Token_Buffer();
05019    load_status = WN2C_lvalue_wn(expr_tokens, 
05020                                 WN_kid0(wn),  /* the base address */
05021                                 base_ty,      /* the base addr_ty */
05022                                 loaded_ty,    /* type of object loaded */
05023                                 WN_load_offset(wn), 
05024                                 context);
05025 
05026    /* Dereference the address from which we are loading, if necessary */
05027    if (!STATUS_is_lvalue(load_status))
05028       Prepend_Token_Special(expr_tokens, '*');
05029    
05030    Append_And_Reclaim_Token_List(tokens, &expr_tokens);
05031 
05032    return EMPTY_STATUS;
05033 } /* WN2C_mload */
05034 
05035 
05036 static STATUS 
05037 WN2C_array(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05038 {
05039    /* Use array addressing rules to return an address, unless
05040     * the context needs an lvalue and we can produce one, in which
05041     * case we return an lvalue and set STATUS_is_lvalue to be TRUE.
05042     */
05043    STATUS       base_addr_status;
05044    STATUS       return_status = EMPTY_STATUS;
05045    BOOL         treat_ptr_as_array;
05046    BOOL         set_ptr_as_array = FALSE;
05047    const BOOL   context_provides_base_ty = CONTEXT_array_basetype(context);
05048    const BOOL   context_needs_lvalue = CONTEXT_needs_lvalue(context);
05049    TOKEN_BUFFER tmp_tokens;
05050    INT32        dim;
05051    TY_IDX       base_ty; /* base-address for ARRAY node */
05052    TY_IDX       ety;     /* Type of element indexed */
05053 
05054    Is_True(WN_operator(wn) == OPR_ARRAY,
05055            ("Invalid operator for WN2C_array()"));
05056 
05057    /* Specially handle the case when we have an implicit ptr_as_array
05058     * case, identified when the pointed type appears to be the type
05059     * of element indexed rather than the array indexed into.
05060     */
05061    base_ty = WN_Tree_Type(WN_kid0(wn));
05062    if (TY_Is_Pointer(base_ty) &&
05063        (!TY_Is_Array(TY_pointed(base_ty)) ||
05064         (TY_size(TY_AR_etype(TY_pointed(base_ty))) < WN_element_size(wn) &&
05065          TY_size(TY_pointed(base_ty)) == WN_element_size(wn))))
05066    {
05067       if (!TY_ptr_as_array(Ty_Table[base_ty]))
05068       {
05069          Set_TY_ptr_as_array(Ty_Table[base_ty]); /* Temporary side-effect */
05070          set_ptr_as_array = TRUE;
05071       }
05072       treat_ptr_as_array = TRUE;
05073    }
05074    else
05075       treat_ptr_as_array = FALSE;
05076 
05077    /* Get the base address from which we are loading. Note that we
05078     * do handle pointers as arrays when there is no ambiguity, but
05079     * we still need to specially mark the case when we are indexing
05080     * an array of arrays.  The following should access the fifth 
05081     * element, each element consisting of 17 ints:
05082     *
05083     *    int (*a)[17]; .... a[5] ....
05084     *
05085     * This is presumably represented as (OPR_ARRAY (OPR_LDID a) ...),
05086     * but since the type of kid0 is ptr-to-arrayOfInts we erroneously
05087     * assume the type of wn is ptr-to-ints and erroneously generate
05088     * "(*a)[5]". 
05089     * TODO: Specially mark such array of array accesses to avoid this
05090     * anomaly (see also WN_Tree_Type()).  The front-end currently
05091     * does not mark ptrs as "ptr_as_array".  Should it?  Note that LNO
05092     * may explicitly mark such arrays (hence the need for the 
05093     * set_ptr_as_array flag).
05094     */
05095    tmp_tokens = New_Token_Buffer();
05096    CONTEXT_set_needs_lvalue(context);
05097    CONTEXT_reset_array_basetype(context);
05098    base_addr_status = WN2C_translate(tmp_tokens, WN_kid0(wn), context);
05099 
05100    if (treat_ptr_as_array)
05101    {
05102       if (set_ptr_as_array)
05103          Clear_TY_ptr_as_array(Ty_Table[base_ty]);  /* Reset w2c side-effect! */
05104       ety = TY_pointed(base_ty);
05105       WHIRL2C_parenthesize(tmp_tokens);
05106    }
05107    else if (!TY_Is_Pointer(base_ty))
05108    {
05109       /* Cast the base-expression to the desired resultant type
05110        * and treat this ptr as a ptr-as-array type.
05111        */
05112       treat_ptr_as_array = TRUE;
05113       if (context_provides_base_ty)
05114          base_ty = CONTEXT_given_base_ty(context);
05115       else
05116          base_ty = WN_Tree_Type(wn);
05117       ety = TY_pointed(base_ty);
05118       WN2C_prepend_cast(tmp_tokens, base_ty, FALSE/*pointer_to_type*/);
05119       WHIRL2C_parenthesize(tmp_tokens);
05120    }
05121    else
05122    {
05123       treat_ptr_as_array = FALSE;
05124       ety = TY_AR_etype(TY_pointed(base_ty));
05125 
05126       /* If the base is a real address (as opposed to an lvalue or an
05127        * array value which according to C semantics can viewed as an address)
05128        * then dereference the address to get to the actual array.
05129        */
05130       if (!STATUS_is_lvalue(base_addr_status) &&
05131           !STATUS_is_array_as_address(base_addr_status))
05132       {
05133          Prepend_Token_Special(tmp_tokens, '*');
05134          WHIRL2C_parenthesize(tmp_tokens);
05135       }
05136    }
05137 
05138    /* Generate an address or an lvalue, as requested from the 
05139     * context of this ARRAY node.
05140     */
05141    if (TY_Is_Array(ety))
05142       STATUS_set_array_as_address(return_status); /* array as address value */
05143    else if (context_needs_lvalue)
05144       STATUS_set_lvalue(return_status);           /* indexed is lvalue */
05145    else
05146       Prepend_Token_Special(tmp_tokens, '&'); /* create address value */
05147    Append_And_Reclaim_Token_List(tokens, &tmp_tokens);
05148    CONTEXT_reset_needs_lvalue(context);
05149 
05150    /* Append the index expressions */
05151    if (treat_ptr_as_array || 
05152        Stab_Array_Has_Dynamic_Bounds(TY_pointed(base_ty)))
05153    {
05154       /* The array has been declared as a pointer to the element types,
05155        * so use calculated offsets based on the element-type.
05156        */
05157       Append_Token_Special(tokens, '[');  
05158       CONTEXT_reset_top_level_expr(context); /* parenthesize idx exprs */
05159       WN2C_Normalize_Idx_To_Onedim(tokens, wn, context);
05160       Append_Token_Special(tokens, ']');
05161    }
05162    else
05163    {
05164       CONTEXT_set_top_level_expr(context); /* To avoid top-level parenthesis */
05165       for (dim = 0; dim < WN_num_dim(wn); dim++)
05166       {
05167          Append_Token_Special(tokens, '[');
05168          (void)WN2C_translate(tokens, WN_array_index(wn, dim), context);
05169          Append_Token_Special(tokens, ']');
05170       }
05171    }
05172    
05173    return return_status;
05174 } /* WN2C_array */
05175 
05176 
05177 static STATUS 
05178 WN2C_intrinsic_op(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05179 {
05180    /* An intrinsic operator expression.  Generate the call as is,
05181     * regardless how the return value is returned, since we know
05182     * the consumer of the value is the surrounding expression.  This
05183     * call is not related to the call-info generated by PUinfo.
05184     */
05185    INT          arg_idx;
05186    TY_IDX       return_ty, result_ty;
05187    TOKEN_BUFFER call_tokens;
05188 
05189    Is_True(WN_operator(wn) == OPR_INTRINSIC_OP,
05190            ("Invalid operator for WN2C_intrinsic_op()"));
05191 
05192    /* A buffer to hold the tokens representing the function call */
05193    call_tokens = New_Token_Buffer();
05194    Append_Token_String(call_tokens,
05195                        WN_intrinsic_name((INTRINSIC)WN_intrinsic(wn)));
05196 
05197    /* Append the argument list to the function reference.
05198     */
05199    Append_Token_Special(call_tokens, '(');
05200    CONTEXT_reset_needs_lvalue(context);
05201    CONTEXT_set_top_level_expr(context); /* To avoid top-level parenthesis */
05202    for (arg_idx = 0; arg_idx <= WN_kid_count(wn) - 1; arg_idx++)
05203    {
05204       (void)WN2C_translate(call_tokens, WN_kid(wn, arg_idx), context);
05205       if (arg_idx < WN_kid_count(wn) - 1)
05206          Append_Token_Special(call_tokens, ',');
05207    }
05208    Append_Token_Special(call_tokens, ')');
05209 
05210    if (WN_intrinsic(wn) == INTRN_TLD_ADDR) {
05211      result_ty = WN_Tree_Type(wn);
05212      //  WN2C_prepend_cast(call_tokens, result_ty, FALSE/*pointer_to_type*/);
05213    } else {
05214      /* See if we need to cast the resultant value */
05215      result_ty = Stab_Mtype_To_Ty(WN_opc_rtype(wn));
05216    }
05217    return_ty = Stab_Mtype_To_Ty(TY_mtype(WN_intrinsic_return_ty(
05218                                                                 WN_opcode(wn),
05219                                                                 (INTRINSIC)WN_intrinsic(wn),
05220                                                                 wn)));
05221    
05222    if (!WN2C_arithmetic_compatible_types(return_ty, result_ty))
05223      WN2C_prepend_cast(call_tokens, result_ty, FALSE/*pointer_to_type*/);
05224 
05225    Append_And_Reclaim_Token_List(tokens, &call_tokens);
05226 
05227    return EMPTY_STATUS;
05228 } /* WN2C_intrinsic_op */
05229 
05230 
05231 static STATUS 
05232 WN2C_tas(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05233 {
05234    STATUS status;
05235    TOKEN_BUFFER cast_tokens;
05236    
05237    Is_True(WN_operator(wn) == OPR_TAS,
05238            ("Invalid operator for WN2C_tas()"));
05239 
05240    if (WN2C_arithmetic_compatible_types(WN_ty(wn), WN_Tree_Type(WN_kid0(wn))))
05241    {
05242       status = WN2C_translate(tokens, WN_kid0(wn), context);
05243    }
05244    else
05245    {
05246       cast_tokens = New_Token_Buffer();
05247       CONTEXT_reset_needs_lvalue(context); /* Cast value, not lvalue */
05248       status = WN2C_translate(cast_tokens, WN_kid0(wn), context);
05249       WN2C_prepend_cast(cast_tokens, WN_ty(wn), FALSE/*pointer_to_type*/);
05250       Append_And_Reclaim_Token_List(tokens, &cast_tokens);
05251    }
05252    
05253    return status;
05254 } /* WN2C_tas */
05255 
05256 
05257 static STATUS 
05258 WN2C_select(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05259 {
05260    /* To be absolutely correct, we should evaluate both kid1 and kid2,
05261     * but since this would require the use of temporaries and does not
05262     * appear to be necessary we simply translate it into a conditional
05263     * expression.
05264     */
05265    Is_True(WN_operator(wn) == OPR_SELECT || 
05266            WN_operator(wn) == OPR_CSELECT,
05267            ("Invalid operator for WN2C_select()"));
05268 
05269    Append_Token_Special(tokens, '(');
05270    (void)WN2C_translate(tokens, WN_kid0(wn), context);
05271    Append_Token_Special(tokens, '?');
05272    (void)WN2C_translate(tokens, WN_kid1(wn), context);
05273    Append_Token_Special(tokens, ':');
05274    (void)WN2C_translate(tokens, WN_kid((wn),2), context);
05275    Append_Token_Special(tokens, ')');
05276 
05277    return EMPTY_STATUS;
05278 } /* WN2C_select */
05279 
05280 
05281 static STATUS 
05282 WN2C_cvt(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05283 {
05284    TOKEN_BUFFER expr_tokens;
05285 
05286    Is_True(WN_operator(wn) == OPR_CVT,
05287            ("Invalid operator for WN2C_cvt()"));
05288 
05289    /* Cast to the desired type, assuming a cvt never is redundant.
05290     */
05291    expr_tokens = New_Token_Buffer();
05292    CONTEXT_reset_needs_lvalue(context); /* no need for an lvalue */
05293    (void)WN2C_translate(expr_tokens, WN_kid0(wn), context);
05294    WHIRL2C_parenthesize(expr_tokens);
05295    WN2C_prepend_cast(expr_tokens, 
05296                      Stab_Mtype_To_Ty(WN_opc_rtype(wn)), 
05297                      FALSE/*pointer_to_type*/);
05298    Append_And_Reclaim_Token_List(tokens, &expr_tokens);
05299    
05300    return EMPTY_STATUS;
05301 } /* WN2C_cvt */
05302 
05303 
05304 static STATUS 
05305 WN2C_cvtl(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05306 {
05307    /* Treat this simply as a regular type conversion, where the
05308     * resultant type is given as the rtype scaled down to the
05309     * given bitlength.
05310     */
05311    TY_IDX      object_ty, result_ty;
05312    TOKEN_BUFFER expr_tokens;
05313    STATUS       status;
05314    
05315    Is_True(WN_operator(wn) == OPR_CVTL,
05316            ("Invalid operator for WN2C_cvtl()"));
05317    
05318    /* Get the result type and the type of value to be converted */
05319    result_ty = WN_Tree_Type(wn);
05320    object_ty = WN_Tree_Type(WN_kid0(wn));
05321    
05322    /* Translate the expression and make certain we end up with a
05323     * value of the expected type.
05324     */
05325    expr_tokens = New_Token_Buffer();
05326    if (WN2C_arithmetic_compatible_types(result_ty, object_ty))
05327    {
05328       /* This is a noop in C, since no casting is necessary */
05329       status = WN2C_translate(expr_tokens, WN_kid0(wn), context);
05330    }
05331    else
05332    {
05333       /* Translate and cast the resultant value to the desired result type */
05334       CONTEXT_reset_needs_lvalue(context); /* no need for an lvalue */
05335       status = WN2C_translate(expr_tokens, WN_kid0(wn), context);
05336       WHIRL2C_parenthesize(expr_tokens);
05337       WN2C_prepend_cast(expr_tokens, result_ty, FALSE/*pointer_to_type*/);
05338    }
05339    Append_And_Reclaim_Token_List(tokens, &expr_tokens);
05340 
05341    return status;
05342 } /* WN2C_cvtl */
05343 
05344 
05345 static STATUS 
05346 WN2C_realpart(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05347 {
05348    Is_True(WN_operator(wn) == OPR_REALPART,
05349            ("Invalid operator for WN2C_realpart"));
05350 
05351    CONTEXT_reset_needs_lvalue(context); /* Denotes a value, not an lvalue */
05352    WN2C_translate(tokens, WN_kid0(wn), context);
05353    Append_Token_Special(tokens, '.');
05354    Append_Token_String(tokens, TY2C_Complex_Realpart_Name);
05355    
05356    return EMPTY_STATUS;
05357 } /* WN2C_realpart */
05358 
05359 
05360 static STATUS 
05361 WN2C_imagpart(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05362 {
05363    Is_True(WN_operator(wn) == OPR_IMAGPART,
05364            ("Invalid operator for WN2C_imagpart"));
05365 
05366    CONTEXT_reset_needs_lvalue(context); /* Denotes a value, not an lvalue */
05367    WN2C_translate(tokens, WN_kid0(wn), context);
05368    Append_Token_Special(tokens, '.');
05369    Append_Token_String(tokens, TY2C_Complex_Imagpart_Name);
05370    
05371    return EMPTY_STATUS;
05372 } /* WN2C_imagpart */
05373 
05374 
05375 static STATUS 
05376 WN2C_paren(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05377 {
05378    STATUS status;
05379 
05380    Is_True(WN_operator(wn) == OPR_PAREN,
05381            ("Invalid operator for WN2C_paren()"));
05382 
05383    Append_Token_Special(tokens, '(');
05384    CONTEXT_set_top_level_expr(context);
05385    status = WN2C_translate(tokens, WN_kid0(wn), context);
05386    Append_Token_Special(tokens, ')');
05387 
05388    return status;
05389 } /* WN2C_paren */
05390 
05391 
05392 static STATUS 
05393 WN2C_complex(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05394 {
05395    UINT        tmp_idx;
05396    const char *tmpvar_name;
05397    
05398    Is_True(WN_operator(wn) == OPR_COMPLEX,
05399            ("Invalid operator for WN2C_complex()"));
05400 
05401    tmp_idx = Stab_Lock_Tmpvar(Stab_Mtype_To_Ty(WN_opc_rtype(wn)),
05402                               ST2C_Declare_Tempvar);
05403    tmpvar_name = W2CF_Symtab_Nameof_Tempvar(tmp_idx);
05404 
05405    /* Evaluate children to values, not to lvalues */
05406    CONTEXT_reset_needs_lvalue(context);
05407 
05408    Append_Token_Special(tokens, '('); /* getting complex structure */
05409 
05410    /* Assign real_part */
05411    Append_Token_Special(tokens, '('); /* getting real part */
05412    Append_Token_String(tokens, tmpvar_name);
05413    Append_Token_Special(tokens, '.');
05414    Append_Token_String(tokens, TY2C_Complex_Realpart_Name);
05415    Append_Token_Special(tokens, '=');
05416    (void)WN2C_translate(tokens, WN_kid0(wn), context);
05417    Append_Token_Special(tokens, ')'); /* gotten real part */
05418    Append_Token_Special(tokens, ',');
05419 
05420    /* Assign imaginary_part */
05421    Append_Token_Special(tokens, '('); /* getting imaginary part */
05422    Append_Token_String(tokens, tmpvar_name);
05423    Append_Token_Special(tokens, '.');
05424    Append_Token_String(tokens, TY2C_Complex_Imagpart_Name);
05425    Append_Token_Special(tokens, '=');
05426    (void)WN2C_translate(tokens, WN_kid1(wn), context);
05427    Append_Token_Special(tokens, ')'); /* gotten real part */
05428    Append_Token_Special(tokens, ',');
05429 
05430    /* Evaluate to complex value */
05431    Append_Token_String(tokens, tmpvar_name);
05432    Append_Token_Special(tokens, ')'); /* gotten complex number */
05433 
05434    Stab_Unlock_Tmpvar(tmp_idx);
05435    
05436    return EMPTY_STATUS;
05437 } /* WN2C_complex */
05438 
05439 
05440 static STATUS 
05441 WN2C_bnor(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05442 {
05443    const TY_IDX result_ty = Stab_Mtype_To_Ty(WN_opc_rtype(wn));
05444    TOKEN_BUFFER opnd;
05445    
05446    Is_True(WN_operator(wn) == OPR_BNOR,
05447            ("Invalid operator for WN2C_bnor()"));
05448 
05449    /* Evaluate children to values, not to lvalues */
05450    CONTEXT_reset_needs_lvalue(context);
05451    
05452    CONTEXT_reset_top_level_expr(context);
05453    Append_Token_Special(tokens, '~');
05454    Append_Token_Special(tokens, '(');
05455    opnd = WN2C_Translate_Arithmetic_Operand(WN_kid0(wn), result_ty, context);
05456    Append_And_Reclaim_Token_List(tokens, &opnd);
05457    Append_Token_Special(tokens, '|');
05458    opnd = WN2C_Translate_Arithmetic_Operand(WN_kid1(wn), result_ty, context);
05459    Append_And_Reclaim_Token_List(tokens, &opnd);
05460    Append_Token_Special(tokens, ')');
05461 
05462    return EMPTY_STATUS;
05463 } /* WN2C_bnor */
05464 
05465 
05466 static STATUS 
05467 WN2C_madd(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05468 {
05469    const TY_IDX result_ty = Stab_Mtype_To_Ty(WN_opc_rtype(wn));
05470    TOKEN_BUFFER opnd;
05471    
05472    Is_True(WN_operator(wn) == OPR_MADD,
05473            ("Invalid operator for WN2C_madd()"));
05474 
05475    /* Evaluate children to values, not to lvalues */
05476    CONTEXT_reset_needs_lvalue(context);
05477    
05478    CONTEXT_reset_top_level_expr(context);
05479    Append_Token_Special(tokens, '(');
05480    opnd = WN2C_Translate_Arithmetic_Operand(WN_kid1(wn), result_ty, context);
05481    Append_And_Reclaim_Token_List(tokens, &opnd);
05482    Append_Token_Special(tokens, '*');
05483    opnd = WN2C_Translate_Arithmetic_Operand(WN_kid(wn,2), result_ty, context);
05484    Append_And_Reclaim_Token_List(tokens, &opnd);
05485    Append_Token_Special(tokens, '+');
05486    opnd = WN2C_Translate_Arithmetic_Operand(WN_kid0(wn), result_ty, context);
05487    Append_And_Reclaim_Token_List(tokens, &opnd);
05488    Append_Token_Special(tokens, ')');
05489 
05490    return EMPTY_STATUS;
05491 } /* WN2C_madd */
05492 
05493 
05494 static STATUS 
05495 WN2C_msub(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05496 {
05497    const TY_IDX result_ty = Stab_Mtype_To_Ty(WN_opc_rtype(wn));
05498    TOKEN_BUFFER opnd;
05499    
05500    Is_True(WN_operator(wn) == OPR_SUB,
05501            ("Invalid operator for WN2C_msub()"));
05502 
05503    /* Evaluate children to values, not to lvalues */
05504    CONTEXT_reset_needs_lvalue(context);
05505    
05506    CONTEXT_reset_top_level_expr(context);
05507    Append_Token_Special(tokens, '(');
05508    opnd = WN2C_Translate_Arithmetic_Operand(WN_kid1(wn), result_ty, context);
05509    Append_And_Reclaim_Token_List(tokens, &opnd);
05510    Append_Token_Special(tokens, '*');
05511    opnd = WN2C_Translate_Arithmetic_Operand(WN_kid(wn,2), result_ty, context);
05512    Append_And_Reclaim_Token_List(tokens, &opnd);
05513    Append_Token_Special(tokens, '-');
05514    opnd = WN2C_Translate_Arithmetic_Operand(WN_kid0(wn), result_ty, context);
05515    Append_And_Reclaim_Token_List(tokens, &opnd);
05516    Append_Token_Special(tokens, ')');
05517 
05518    return EMPTY_STATUS;
05519 } /* WN2C_msub */
05520 
05521 
05522 static STATUS 
05523 WN2C_nmadd(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05524 {
05525    const TY_IDX result_ty = Stab_Mtype_To_Ty(WN_opc_rtype(wn));
05526    TOKEN_BUFFER opnd;
05527    
05528    Is_True(WN_operator(wn) == OPR_NMADD,
05529            ("Invalid operator for WN2C_nmadd()"));
05530 
05531    /* Evaluate children to values, not to lvalues */
05532    CONTEXT_reset_needs_lvalue(context);
05533    
05534    CONTEXT_reset_top_level_expr(context);
05535    Append_Token_Special(tokens, '-');
05536    Append_Token_Special(tokens, '(');
05537    opnd = WN2C_Translate_Arithmetic_Operand(WN_kid1(wn), result_ty, context);
05538    Append_And_Reclaim_Token_List(tokens, &opnd);
05539    Append_Token_Special(tokens, '*');
05540    opnd = WN2C_Translate_Arithmetic_Operand(WN_kid(wn,2), result_ty, context);
05541    Append_And_Reclaim_Token_List(tokens, &opnd);
05542    Append_Token_Special(tokens, '+');
05543    opnd = WN2C_Translate_Arithmetic_Operand(WN_kid0(wn), result_ty, context);
05544    Append_And_Reclaim_Token_List(tokens, &opnd);
05545    Append_Token_Special(tokens, ')');
05546 
05547    return EMPTY_STATUS;
05548 } /* WN2C_nmadd */
05549 
05550 
05551 static STATUS 
05552 WN2C_nmsub(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05553 {
05554    const TY_IDX result_ty = Stab_Mtype_To_Ty(WN_opc_rtype(wn));
05555    TOKEN_BUFFER opnd;
05556    
05557    Is_True(WN_operator(wn) == OPR_NMSUB,
05558            ("Invalid operator for WN2C_nmsub()"));
05559 
05560    /* Evaluate children to values, not to lvalues */
05561    CONTEXT_reset_needs_lvalue(context);
05562    
05563    CONTEXT_reset_top_level_expr(context);
05564    Append_Token_Special(tokens, '-');
05565    Append_Token_Special(tokens, '(');
05566    opnd = WN2C_Translate_Arithmetic_Operand(WN_kid1(wn), result_ty, context);
05567    Append_And_Reclaim_Token_List(tokens, &opnd);
05568    Append_Token_Special(tokens, '*');
05569    opnd = WN2C_Translate_Arithmetic_Operand(WN_kid(wn,2), result_ty, context);
05570    Append_And_Reclaim_Token_List(tokens, &opnd);
05571    Append_Token_Special(tokens, '-');
05572    opnd = WN2C_Translate_Arithmetic_Operand(WN_kid0(wn), result_ty, context);
05573    Append_And_Reclaim_Token_List(tokens, &opnd);
05574    Append_Token_Special(tokens, ')');
05575 
05576    return EMPTY_STATUS;
05577 } /* WN2C_nmsub */
05578 
05579 
05580 static STATUS 
05581 WN2C_ldid(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05582 {
05583    /* This is similar to the WN2C_iload case, except that pregs must 
05584     * be handled specially!
05585     */
05586    TY_IDX       object_ty;    /* Type of object loaded */
05587    TY_IDX       base_addr_ty; /* Type of (qualified) address loaded from */
05588    TY_IDX       lda_st_ty;    /* Formal reference parameter type */
05589    STATUS       load_status;
05590    TOKEN_BUFFER expr_tokens;
05591    STAB_OFFSET  addr_offset;
05592 
05593 
05594    Is_True(WN_operator(wn) == OPR_LDID || 
05595            (WN_operator(wn) == OPR_LDA && 
05596             ST_sclass(WN_st(wn)) == SCLASS_FORMAL_REF),
05597            ("Invalid operator for WN2C_ldid()"));
05598 
05599    /* Special case for Purple */
05600    if (W2C_Only_Mark_Loads && !TY_Is_Pointer(WN_ty(wn)))
05601    {
05602       char buf[64];
05603       sprintf(buf, "#<%p>#", wn);
05604       Append_Token_String(tokens, buf);
05605       return EMPTY_STATUS;
05606    }
05607 
05608    if (WN_operator(wn) == OPR_LDID &&
05609        ST_sclass(WN_st(wn)) == SCLASS_FORMAL_REF)
05610       return WN2C_iload(tokens, wn, context); /* Treat LDID as indirect load */
05611    else if (WN_operator(wn) == OPR_LDA)
05612    {
05613       lda_st_ty = ST_type(WN_st(wn));
05614       Set_ST_type(WN_st(wn), Stab_Pointer_To(ST_type(WN_st(wn))));
05615    }
05616 
05617    /* Get the load expression */
05618    addr_offset = WN_load_offset(wn);
05619    expr_tokens = New_Token_Buffer();   
05620    TY_IDX prefered_ty = WN_ty(wn);
05621    if (ST_sym_class(WN_st(wn)) == CLASS_PREG)
05622    {
05623       /* When loading a preg, always load it as a value of the type
05624        * with which it is declared.
05625        */
05626       char buffer[64];
05627       object_ty = PUinfo_Preg_Type(ST_type(WN_st(wn)), addr_offset);
05628       if (addr_offset == -1) { 
05629          switch (TY_mtype(Ty_Table[WN_ty(wn)])) { 
05630          case MTYPE_I8:
05631          case MTYPE_U8:
05632          case MTYPE_I1:
05633          case MTYPE_I2:
05634          case MTYPE_I4:
05635          case MTYPE_U1:
05636          case MTYPE_U2:
05637          case MTYPE_U4:
05638             sprintf(buffer, "reg%d", First_Int_Preg_Return_Offset);
05639             Append_Token_String(expr_tokens, buffer); 
05640             break;
05641          case MTYPE_F4:
05642          case MTYPE_F8:
05643          case MTYPE_FQ:
05644          case MTYPE_C4:
05645          case MTYPE_C8:
05646          case MTYPE_CQ:
05647             sprintf(buffer, "reg%d", First_Float_Preg_Return_Offset);
05648             Append_Token_String(expr_tokens, buffer); 
05649             break;
05650          case MTYPE_M: 
05651             Fail_FmtAssertion ("MLDID of Return_Val_Preg not allowed in middle"
05652                " of expression");
05653             break; 
05654          default:
05655             Fail_FmtAssertion ("Unexpected type in WN2C_ldid()");
05656             break;
05657          } 
05658       } 
05659       else 
05660       {  
05661         WN2C_Append_Preg(expr_tokens, 
05662                          WN_st(wn),   /* preg */
05663                          addr_offset, /* preg index */
05664                          object_ty,   /* preg type */
05665                          context);
05666       }  
05667    }
05668    else
05669    {
05670       /* Get the lhs, preferably as an lvalue, but possibly as an address.
05671        */
05672      //FIX:  For field accesses, set preferred type to that of the field
05673 
05674      if (WN_operator(wn) == OPR_LDID &&
05675          TY_Is_Structured(prefered_ty) &&
05676          WN_field_id(wn) != 0 ) {
05677        prefered_ty = Get_Field_Type(prefered_ty, WN_field_id(wn));   
05678      }
05679      WN2C_SymAccess_Type(&base_addr_ty,
05680                          &object_ty,
05681                          ST_type(WN_st(wn)), /* base_type */
05682                          prefered_ty,          /* preferred type */
05683                          WN_opc_dtype(wn),   /* required mtype */
05684                          addr_offset);       /* offset from base */
05685      //cout << "IN LDID: OBJECT TYPE: " << object_ty << endl; 
05686 
05687       /* Get the lvalue or address of the data to be loaded */
05688       load_status = WN2C_lvalue_st(expr_tokens,
05689                                    WN_st(wn),    /* base symbol loaded from */
05690                                    base_addr_ty, /* address loaded from */
05691                                    object_ty,    /* type of object loaded */
05692                                    addr_offset,
05693                                    context);
05694 
05695       /* Dereference the address from which we are loading, if necessary */
05696       if (!STATUS_is_lvalue(load_status))
05697          Prepend_Token_Special(expr_tokens, '*');
05698 
05699    //need output (*type) for void pointer----fzhao
05700    if (TY_kind(ST_type(WN_st(wn))) == KIND_POINTER &&
05701           TY_kind(TY_pointed(ST_type(WN_st(wn))))==KIND_VOID &&
05702           TY_kind(TY_pointed(WN_ty(wn))) != KIND_VOID) {
05703 
05704       Prepend_Token_String(expr_tokens,"*)");
05705 
05706       if (!TY_Is_Structured(TY_pointed(WN_ty(wn))))
05707            Prepend_Token_String(expr_tokens,
05708                            Scalar_C_Names[TY_mtype(TY_pointed(WN_ty(wn)))].pseudo_name);
05709        else {
05710             Prepend_Token_String(expr_tokens,TY_name(TY_pointed(WN_ty(wn))));
05711             Prepend_Token_String(expr_tokens,"struct ");
05712         }
05713         Prepend_Token_Special(expr_tokens, '(');
05714      }
05715   }
05716    
05717    /* Cast the resultant value to the expected result type if different 
05718     * from the type of value loaded.
05719     */
05720 
05721    //FIX: Compare to prefered type instead
05722    if (!WN2C_arithmetic_compatible_types(object_ty, prefered_ty))
05723    {
05724       
05725       if (!TY_Is_Structured(object_ty) && !TY_Is_Structured(WN_ty(wn)))
05726          WN2C_prepend_cast(expr_tokens, WN_ty(wn), FALSE/*pointer_to_type*/);
05727       else
05728       {
05729          /* Assign the expr_tokens to a temporary, cast the address of the
05730           * temporary to a pointer to a WN_ty(wn), then dereference.
05731           */
05732          const UINT  tmp_idx = Stab_Lock_Tmpvar(object_ty, 
05733                                                 ST2C_Declare_Tempvar);
05734          const char *tmpvar_name = W2CF_Symtab_Nameof_Tempvar(tmp_idx);
05735 
05736          /* Generate "(tmpvar = e," */
05737          Append_Token_Special(tokens, '(');
05738          Append_Token_String(tokens, tmpvar_name);
05739          Append_Token_Special(tokens, '=');
05740          Append_And_Reclaim_Token_List(tokens, &expr_tokens);
05741          Append_Token_Special(tokens, ',');
05742 
05743          /* Generate "*(ty *)&tmpvar)" */
05744          expr_tokens = New_Token_Buffer();
05745          Append_Token_Special(expr_tokens, '&');
05746          Append_Token_String(expr_tokens, tmpvar_name);
05747          WN2C_prepend_cast(expr_tokens, WN_ty(wn), TRUE/*pointer_to_type*/);
05748          Prepend_Token_Special(expr_tokens, '*');
05749          Append_Token_Special(expr_tokens, ')');
05750          Stab_Unlock_Tmpvar(tmp_idx);
05751       }
05752    }
05753    Append_And_Reclaim_Token_List(tokens, &expr_tokens);
05754 
05755    if (WN_operator(wn) == OPR_LDA)
05756       Set_ST_type(WN_st(wn), lda_st_ty);
05757 
05758    return EMPTY_STATUS;
05759 } /* WN2C_ldid */
05760 
05761 
05762 static STATUS 
05763 WN2C_lda(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05764 {
05765    TY_IDX       object_ty;
05766    STATUS       lda_status;
05767    TOKEN_BUFFER expr_tokens;
05768    STAB_OFFSET  lda_offset;
05769 
05770    Is_True(WN_operator(wn) == OPR_LDA,
05771            ("Invalid operator for WN2C_lda()"));
05772    Is_True(ST_sym_class(WN_st(wn)) != CLASS_PREG, 
05773            ("Cannot take the address of a preg"));
05774 
05775    if (ST_sclass(WN_st(wn)) == SCLASS_FORMAL_REF)
05776       return WN2C_ldid(tokens, wn, context);  /* Treat LDA as a direct load */
05777 
05778    expr_tokens = New_Token_Buffer();
05779    if (ST_sym_class(WN_st(wn)) == CLASS_CONST &&
05780        TCON_ty(STC_val(WN_st(wn))) != MTYPE_STRING)
05781    {
05782       /* A constant (Fortran input?), so refer to it's address 
05783        * via a non-shared temporary variable.
05784        */
05785       UINT tmp_idx = 
05786          Stab_Lock_Tmpvar(ST_type(WN_st(wn)), &ST2C_Declare_Tempvar);
05787       const char *tmp_name = W2CF_Symtab_Nameof_Tempvar(tmp_idx);
05788 
05789       Append_Token_Special(tokens, '(');
05790       if (TY_Is_Complex(ST_type(WN_st(wn))))
05791          WN2C_Assign_Complex_Const(expr_tokens,
05792                                    tmp_name,
05793                                    Extract_Complex_Real(STC_val(WN_st(wn))),
05794                                    Extract_Complex_Imag(STC_val(WN_st(wn))));
05795       else
05796       {
05797          Append_Token_String(expr_tokens, tmp_name);
05798          Append_Token_Special(expr_tokens, '=');
05799          TCON2C_translate(expr_tokens, STC_val(WN_st(wn)));
05800       }
05801       Append_Token_Special(expr_tokens, ',');
05802       Append_Token_Special(expr_tokens, '&');
05803       Append_Token_String(expr_tokens, tmp_name);
05804       Append_Token_Special(expr_tokens, ')');
05805 
05806       if (!TY_Is_Pointer(WN_ty(wn)) ||
05807           !WN2C_arithmetic_compatible_types(ST_type(WN_st(wn)),
05808                                             TY_pointed(WN_ty(wn))))
05809       {
05810          WN2C_prepend_cast(expr_tokens, WN_ty(wn), FALSE/*ptr_to_type*/);
05811       }
05812       lda_status = EMPTY_STATUS;
05813    }
05814    else if ((ST_sym_class(WN_st(wn)) == CLASS_FUNC ?
05815              ST_pu_type(WN_st(wn)) : ST_type(WN_st(wn))) == 0)
05816    {
05817       // in case of compiler generated symbols, the type may be null
05818       //
05819       const char *tmp_name = ST_name(WN_st(wn));
05820       if (tmp_name == NULL)
05821       {
05822          UINT tmp_idx = 
05823             Stab_Lock_Tmpvar(MTYPE_To_TY(MTYPE_I4), &ST2C_Declare_Tempvar);
05824          tmp_name = W2CF_Symtab_Nameof_Tempvar(tmp_idx);
05825       }
05826       Append_Token_String(expr_tokens, tmp_name);
05827       lda_status = EMPTY_STATUS;
05828    }
05829    else /* The normal case */
05830    {
05831       lda_offset = WN_lda_offset(wn);
05832       if (ST_sym_class(WN_st(wn)) == CLASS_CONST &&
05833           TCON_ty(STC_val(WN_st(wn))) == MTYPE_STRING)
05834       {
05835          /* front-end typing is unreliable for this case, so hard
05836           * code the expected referenced type here.
05837           */
05838          object_ty = Stab_Mtype_To_Ty(MTYPE_U1);
05839       }
05840       else if (TY_Is_Pointer(WN_ty(wn)))
05841       {
05842          TY_IDX wn_st_type = ST_sym_class(WN_st(wn)) == CLASS_FUNC ?
05843                                     ST_pu_type(WN_st(wn)) : ST_type(WN_st(wn));
05844          object_ty =
05845             WN2C_MemAccess_Type(
05846                wn_st_type,                   /* base_type */
05847                TY_pointed(WN_ty(wn)),        /* preferred type */
05848                TY_mtype(wn_st_type),         /* required mtype */
05849                lda_offset);                  /* offset from base */
05850 
05851         /*if the object type is "struct"(union) need to output the corresponding
05852           selector------fzhao
05853          */
05854          if (TY_Is_Structured(object_ty) && WN_field_id(wn) != 0 )
05855             object_ty = Get_Field_Type(object_ty,WN_field_id(wn));
05856 
05857       }
05858       else
05859 
05860       {
05861          object_ty = ST_sym_class(WN_st(wn)) == CLASS_FUNC ?
05862                                     ST_pu_type(WN_st(wn)) : ST_type(WN_st(wn));
05863       }
05864       
05865       /* Get the lvalue or address for the identifier */
05866       expr_tokens = New_Token_Buffer();
05867       lda_status = 
05868          WN2C_lvalue_st(expr_tokens, 
05869                         WN_st(wn),  /* base st and the addr ty */
05870                         Stab_Pointer_To(ST_sym_class(WN_st(wn)) == CLASS_FUNC ?
05871                                    ST_pu_type(WN_st(wn)) : ST_type(WN_st(wn))),
05872                         object_ty,  /* type addressed */
05873                         lda_offset, 
05874                         context);
05875 
05876       /* Convert an lvalue into an address value, if necessary.*/
05877       if (!TY_Is_Pointer(WN_ty(wn)) ||
05878           !WN2C_arithmetic_compatible_types(object_ty, TY_pointed(WN_ty(wn))))
05879       {
05880          if (STATUS_is_lvalue(lda_status))
05881             Prepend_Token_Special(expr_tokens, '&');
05882          
05883 //       WN2C_prepend_cast(expr_tokens, WN_ty(wn), FALSE/*ptr_to_type*/);
05884 // unparsed code with the type casting will 
05885 // cause gcc/frontend issue warnings----FMZ
05886 
05887          STATUS_reset_lvalue(lda_status); /* Not returning an lvalue */
05888       }
05889       else if (STATUS_is_lvalue(lda_status) && !CONTEXT_needs_lvalue(context))
05890       {
05891          Prepend_Token_Special(expr_tokens, '&');
05892          STATUS_reset_lvalue(lda_status); /* We not returning an lvalue */
05893       }
05894    }
05895    Append_And_Reclaim_Token_List(tokens, &expr_tokens);
05896 
05897    return lda_status;
05898 } /* WN2C_lda */
05899 
05900 
05901 static STATUS 
05902 WN2C_const(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05903 {
05904    /* This handles constants pointed to through an ST entry
05905     * (used for shared and non-integral constant values).
05906     */
05907    Is_True(WN_operator(wn) == OPR_CONST && 
05908            ST_sym_class(WN_st(wn)) == CLASS_CONST,
05909            ("Invalid operator for WN2C_const"));
05910    
05911    CONTEXT_reset_needs_lvalue(context); /* Denotes a value, not an lvalue */
05912    if (!TY_Is_Complex(WN_Tree_Type(wn)))
05913       TCON2C_translate(tokens, STC_val(WN_st(wn)));
05914    else
05915    {
05916       UINT tmp_idx = 
05917          Stab_Lock_Tmpvar(WN_Tree_Type(wn), &ST2C_Declare_Tempvar);
05918       const char *tmp_name = W2CF_Symtab_Nameof_Tempvar(tmp_idx);
05919       
05920       /* A complex constant, so refer to it via a non-shared 
05921        * temporary variable.
05922        */
05923       Append_Token_Special(tokens, '(');
05924       WN2C_Assign_Complex_Const(tokens,
05925                                 tmp_name,
05926                                 Extract_Complex_Real(STC_val(WN_st(wn))),
05927                                 Extract_Complex_Imag(STC_val(WN_st(wn))));
05928       Append_Token_Special(tokens, ',');
05929       Append_Token_String(tokens, tmp_name);
05930       Append_Token_Special(tokens, ')'); /* gotten complex structure */
05931    }
05932 
05933    return EMPTY_STATUS;
05934 } /* WN2C_const */
05935 
05936 
05937 static STATUS 
05938 WN2C_intconst(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05939 {
05940    Is_True(WN_operator(wn) == OPR_INTCONST,
05941            ("Invalid operator for WN2C_intconst()"));
05942 
05943    CONTEXT_reset_needs_lvalue(context); /* Denotes a value, not an lvalue */
05944    TCON2C_translate(tokens, Host_To_Targ(WN_opc_rtype(wn), WN_const_val(wn)));
05945    
05946    return EMPTY_STATUS;
05947 } /* WN2C_intconst */
05948 
05949 
05950 static STATUS 
05951 WN2C_comma(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05952 {
05953    Is_True(WN_operator(wn) == OPR_COMMA,
05954            ("Invalid operator for WN2C_comma()"));
05955 
05956    CONTEXT_reset_top_level_expr(context);
05957    Append_Token_Special(tokens, '(');
05958    Append_Token_Special(tokens, '(');
05959    WN2C_Translate_Comma_Sequence(tokens, WN_first(WN_kid0(wn)), context);
05960    Append_Token_Special(tokens, ')');
05961    Append_Token_Special(tokens, ',');
05962    WN2C_translate(tokens, WN_kid1(wn), context);
05963    Append_Token_Special(tokens, ')');
05964    return EMPTY_STATUS;
05965 } /* WN2C_comma */
05966 
05967 
05968 static STATUS 
05969 WN2C_rcomma(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
05970 {
05971    /* Assign the rhs to a temporary, do the side-effects and return
05972     * the temporary as the value of the expression.
05973     */
05974    UINT         tmp_idx;
05975    const char  *tmp_name;
05976          
05977    Is_True(WN_operator(wn) == OPR_RCOMMA,
05978            ("Invalid operator for WN2C_romma()"));
05979 
05980    CONTEXT_reset_top_level_expr(context);
05981    Append_Token_Special(tokens, '(');
05982 
05983    tmp_idx = Stab_Lock_Tmpvar(WN_Tree_Type(WN_kid0(wn)), 
05984                               &ST2C_Declare_Tempvar);
05985    tmp_name = W2CF_Symtab_Nameof_Tempvar(tmp_idx);
05986    Append_Token_String(tokens, tmp_name);
05987    Append_Token_Special(tokens, '=');
05988    WN2C_translate(tokens, WN_kid0(wn), context);
05989    Append_Token_Special(tokens, ',');
05990    Append_Token_Special(tokens, '(');
05991    WN2C_Translate_Comma_Sequence(tokens, WN_first(WN_kid1(wn)), context);
05992    Append_Token_Special(tokens, ')');
05993    Append_Token_Special(tokens, ',');
05994    Append_Token_String(tokens, tmp_name);
05995    Append_Token_Special(tokens, ')');
05996    return EMPTY_STATUS;
05997 } /* WN2C_rcomma */
05998 
05999 
06000 static STATUS
06001 WN2C_parm(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
06002 {
06003    /* TODO: handle opcode parms properly, i.e. take some advantage
06004     * of the information provided in this packaging of argument 
06005     * expressions.  For now, just skip these nodes.
06006     */
06007    TOKEN_BUFFER parm_tokens;
06008    STATUS       status;
06009    TY_IDX       parm_ty = CONTEXT_given_lvalue_ty(context);
06010 
06011    CONTEXT_reset_given_lvalue_ty(context);
06012 
06013    Is_True(WN_operator(wn) == OPR_PARM,
06014            ("Invalid operator for WN2C_parm()"));
06015 
06016    if (parm_ty == TY_IDX_ZERO)
06017    {
06018       // Not provided by context (e.g. for intrinsic_op).
06019       //
06020       parm_ty = WN_ty(wn);
06021    }
06022    
06023    if (WN2C_assignment_compatible_types(parm_ty, WN_Tree_Type(WN_kid0(wn))))
06024       status = WN2C_translate(tokens, WN_kid0(wn), context);
06025    else
06026    {
06027       parm_tokens = New_Token_Buffer();
06028       CONTEXT_reset_top_level_expr(context);
06029       WN2C_translate(parm_tokens, WN_kid0(wn), context);
06030       WN2C_prepend_cast(parm_tokens, parm_ty, FALSE/*pointer_to_type*/);
06031       Append_And_Reclaim_Token_List(tokens, &parm_tokens);
06032       status = EMPTY_STATUS;
06033    }
06034    return status;
06035 } /* WN2C_parm */
06036 
06037 
06038 static STATUS
06039 WN2C_alloca(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
06040 {
06041   STATUS status ;
06042 
06043   Append_Token_String(tokens,"__opr_alloca");
06044   Append_Token_Special(tokens,'(');
06045   status = WN2C_translate(tokens,WN_kid0(wn),context);
06046   Append_Token_Special(tokens,')');
06047 
06048   return status;
06049 }
06050 
06051 static STATUS
06052 WN2C_dealloca(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
06053 {
06054 
06055   INT16 n,i;
06056   STATUS status ;
06057 
06058   n = WN_kid_count(wn);
06059 
06060   WN2C_Stmt_Newline(tokens,WN_linenum(wn));
06061   Append_Token_String(tokens,"__opr_dealloca");
06062   Append_Token_Special(tokens,'(');
06063 
06064   i = 0 ;
06065   while (i < n)
06066   {
06067     status = WN2C_translate(tokens,WN_kid(wn,i),context);
06068     if (++i < n)
06069       Append_Token_Special(tokens,',');
06070   }
06071   Append_Token_Special(tokens,')');
06072   return status ;
06073 }
06074 
06075 static STATUS
06076 WN2C_extract_bits(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
06077 {
06078        //output ((... >>of) & 0xff..f)
06079    STATUS status ;
06080    UINT  of = WN_bit_offset(wn);
06081    UINT  sz = WN_bit_size(wn)/4;
06082    Is_True(WN_operator(wn) == OPR_EXTRACT_BITS,
06083            ("Invalid operator for WN2C_extract_bits()"));
06084 
06085       Append_Token_Special(tokens,'(');
06086       Append_Token_Special(tokens,'(');
06087       status = WN2C_translate(tokens,WN_kid0(wn),context);
06088       Append_Token_Special(tokens,')');
06089       Append_Token_String(tokens,">>");
06090       TCON2C_translate(tokens,
06091                     Host_To_Targ(MTYPE_I4,of));
06092       Append_Token_Special(tokens, ')');
06093       Append_Token_String(tokens,"& 0x");
06094       while (sz) {
06095            Append_Token_Special(tokens, 'f');
06096            --sz;
06097        }      
06098       
06099    return status;
06100  
06101 }
06102 
06103 static STATUS
06104 WN2C_compose_bits(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
06105 {
06106    // ((... & 0xff..f) << of)
06107    STATUS status ;
06108    UINT  of = WN_bit_offset(wn);
06109           //shift of bits (for compose_bit,it is left shift (<< of)
06110    UINT sz = WN_bit_size(wn)/4;
06111    Is_True(WN_operator(wn) == OPR_COMPOSE_BITS,
06112            ("Invalid operator for WN2C_compose_bits()"));
06113 
06114       Append_Token_Special(tokens,'(');
06115       Append_Token_Special(tokens,'(');
06116       status = WN2C_translate(tokens,WN_kid1(wn),context);
06117       Append_Token_Special(tokens,')');
06118       Append_Token_String(tokens,"& 0x");
06119 
06120       while (sz) {
06121            Append_Token_Special(tokens, 'f');
06122            --sz;
06123        }
06124       Append_Token_Special(tokens, ')');
06125       Append_Token_String(tokens,"<<");
06126       TCON2C_translate(tokens,
06127                     Host_To_Targ(MTYPE_I4,of));
06128 
06129    return status;
06130 }
06131 /*------------------------ exported routines --------------------------*/
06132 /*---------------------------------------------------------------------*/
06133 
06134 
06135 void 
06136 WN2C_initialize(void)
06137 {
06138    INT opr;
06139    INT map;
06140 
06141    /* Reset the WN2C_Opr_Handle array */
06142    for (opr = 0; opr < NUMBER_OF_OPERATORS; opr++)
06143       WN2C_Opr_Handler[opr] = &WN2C_unsupported;
06144 
06145    /* Initialize the WN2C_Opr_Handle array */
06146    for (map = 0; map < NUMBER_OF_OPR2HANDLER_MAPS; map++)
06147       WN2C_Opr_Handler[WN2C_Opr_Handler_Map[map].opr] =
06148          WN2C_Opr_Handler_Map[map].handler;
06149 
06150    /* Reset the WN2C_Opc2cname array.  This has already been
06151     * implicitly done by declaring it as static:
06152     *
06153     *    OPCODE   opc;
06154     *    for (opc = 0; opc < NUMBER_OF_OPCODES; opc++)
06155     *       WN2C_Opc2cname[opc] = NULL;
06156     *
06157     * Initialize the WN2C_Opc2cname array
06158     */
06159    for (map = 0; map < NUMBER_OF_OPC2CNAME_MAPS; map++)
06160       WN2C_Opc2cname[WN2C_Opc2cname_Map[map].opc] = 
06161          WN2C_Opc2cname_Map[map].cname;
06162    
06163 } /* WN2C_initialize */
06164 
06165 
06166 void 
06167 WN2C_finalize(void)
06168 {
06169    /* Free up information pertaining temporary whirl2c variables,
06170     * recover the "pointer" fields where we have created them
06171     * during whirl2c processing, and reclaim the Type_Buffers.
06172     * Also, reset the "referenced" flag for file-level symbols.
06173     */
06174    Stab_Free_Tmpvars();
06175 } /* WN2C_finalize */
06176 
06177 
06178 BOOL 
06179 WN2C_new_symtab(void)
06180 {
06181    /* Returns TRUE if the Current_Symtab is different from the last
06182     * time this function was called.  This is useful to determine if
06183     * the symtab has changed (in which case we should emit new 
06184     * declarations).  Used when processing WN block nodes.
06185     */
06186    static SYMTAB_IDX WN2C_Current_Symtab = 0;
06187    const BOOL new_symtab = (CURRENT_SYMTAB != WN2C_Current_Symtab);
06188 
06189    if (new_symtab)
06190       WN2C_Current_Symtab = CURRENT_SYMTAB;
06191    return new_symtab;
06192 } /* WN2C_new_symtab */
06193 
06194 
06195 STATUS 
06196 WN2C_translate(TOKEN_BUFFER tokens, const WN *wn, CONTEXT context)
06197 {
06198    /* Dispatch to the appropriate handler for this construct,
06199     * The handlers should all have the same prototype, just in
06200     * case we later decide to do this dispatch via a handler 
06201     * table instead of via this switch statement.
06202     */
06203    return WN2C_Opr_Handler[WN_operator(wn)](tokens, wn, context);
06204 } /* WN2C_translate */
06205 
06206 
06207 void
06208 WN2C_translate_structured_types(void)
06209 {
06210    Write_String(W2C_File[W2C_DOTH_FILE], NULL/* No srcpos map */,
06211                 "/* Types */\n");
06212    WN2C_Append_Symtab_Types(NULL, /* token_buffer */
06213                             2);   /* lines between decls */
06214 } /* WN2C_translate_structured_types */
06215 
06216 
06217 STATUS 
06218 WN2C_translate_file_scope_defs(CONTEXT context)
06219 {
06220     /* Make the global symbol table the Current_Symtab and write 
06221      * the declarations to file.
06222      */
06223    CURRENT_SYMTAB = GLOBAL_SYMTAB;
06224    WN2C_new_symtab();
06225 
06226    //WEI: don't see why this needs to be called
06227 //#if 0 WEI set "#if 0/#endif" cause some static constant
06228 // missed output to the corresponding w2c.h file.This cause bug #19 (see bug
06229 // track website),get back the function call----fzhao
06230 
06231 /* we have to keep dumpout "ST_IS_CONST_VAR" symtab entry and get rid of
06232    "CLASS_CONST" entry dumpout. Change the function "WN2C_Append_Symtab_Consts"
06233     instead.----------fzhao
06234  */
06235 
06236    Write_String(W2C_File[W2C_DOTH_FILE], NULL/* No srcpos map */,
06237                 "/* File-level symbolic constants */\n");
06238    WN2C_Append_Symtab_Consts(NULL, /* token_buffer */ 
06239                              TRUE, /* use const_tab */
06240                              2,    /* lines between decls */
06241                              context);
06242 //#endif
06243 
06244    Write_String(W2C_File[W2C_DOTH_FILE], NULL/* No srcpos map */,
06245                 "/* File-level vars and routines */\n");
06246    WN2C_Append_Symtab_Vars(NULL, /* token_buffer */
06247                            2,    /* lines between decls */
06248                            context);
06249 
06250    return EMPTY_STATUS;
06251 } /* WN2C_translate_file_scope_defs */
06252 
06253 
06254 STATUS 
06255 WN2C_translate_purple_main(TOKEN_BUFFER tokens, 
06256                            const WN    *pu, 
06257                            const char  *region_name,
06258                            CONTEXT      context)
06259 {
06260    static const char prp_return_var_name[] = "prp___return";
06261 
06262    TY_IDX    return_ty;
06263    const ST *param_st;
06264    INT       first_param, param;
06265 
06266    Is_True(WN_operator(pu) == OPR_FUNC_ENTRY, 
06267            ("Invalid opcode for WN2C_translate_purple_main()"));
06268 
06269    /* Write function header, and begin the body on a new line
06270     */
06271    CONTEXT_set_srcpos(context, WN_Get_Linenum(pu));
06272    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
06273    Append_Token_String(tokens, "int main()");
06274 
06275    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
06276    Append_Token_Special(tokens, '{');
06277 
06278    /* Insert parameters as local variables
06279     */
06280    Increment_Indentation();
06281    first_param = (PUINFO_RETURN_TO_PARAM? 1 : 0);
06282    for (param = first_param; param < WN_num_formals(pu); param++)
06283    {
06284       param_st = WN_st(WN_formal(pu, param));
06285       Append_Indented_Newline(tokens, 1);
06286       ST2C_decl_translate(tokens, param_st, context);
06287       Append_Token_Special(tokens, ';');
06288    }
06289 
06290    /* We do not really care what is returned from the purplized region,
06291     * but for correctness we insert a declaration for any return variable
06292     * here, with a default name.
06293     */
06294    return_ty = PUINFO_RETURN_TY;
06295    if (return_ty != (TY_IDX) 0 && TY_kind(return_ty) != KIND_VOID)
06296    {
06297       TOKEN_BUFFER return_tokens = New_Token_Buffer();
06298 
06299       Append_Token_String(return_tokens, prp_return_var_name);
06300       TY2C_translate_unqualified(return_tokens, return_ty);
06301       Append_Indented_Newline(tokens, 1);
06302       Append_And_Reclaim_Token_List(tokens, &return_tokens);
06303    }
06304 
06305    /* Insert a placeholder for initialization of parameters
06306     */
06307    Append_Indented_Newline(tokens, 1);
06308    Append_Token_String(tokens, "<#PRP_XSYM:INIT_PARAM ");
06309    WN2C_Append_Purple_Funcinfo(tokens);
06310    Append_Token_String(tokens, "#>");
06311 
06312    /* Insert call to purple region routine
06313     */
06314    Append_Indented_Newline(tokens, 1);
06315    Append_Token_String(tokens,
06316                        "/***** Call to extracted purple region ****");
06317    Append_Indented_Newline(tokens, 1);
06318    Append_Token_String(tokens, "*/");
06319    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
06320    if (return_ty != (TY_IDX) 0 && TY_kind(return_ty) != KIND_VOID)
06321    {
06322       Append_Token_String(tokens, prp_return_var_name);
06323       Append_Token_Special(tokens, '=');
06324    }
06325    Append_Token_String(tokens, region_name);
06326    Append_Token_Special(tokens, '(');
06327    for (param = 0; param < WN_num_formals(pu); param++)
06328    {
06329       if (param > 0)
06330          Append_Token_Special(tokens, ',');
06331       param_st = WN_st(WN_formal(pu, param));
06332       Append_Token_String(tokens, W2CF_Symtab_Nameof_St(param_st));
06333    }
06334    Append_Token_Special(tokens, ')');
06335    Append_Token_Special(tokens, ';');
06336 
06337    /* Insert a placeholder for final testing of parameters
06338     */
06339    Append_Indented_Newline(tokens, 1);
06340    Append_Token_String(tokens, "<#PRP_XSYM:TEST_PARAM ");
06341    WN2C_Append_Purple_Funcinfo(tokens);
06342    Append_Token_String(tokens, "#>");
06343 
06344    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
06345    Append_Token_String(tokens, "return 0;");
06346 
06347    Decrement_Indentation();
06348    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
06349    Append_Token_Special(tokens, '}');
06350    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
06351    WN2C_Stmt_Newline(tokens, CONTEXT_srcpos(context));
06352    
06353    return EMPTY_STATUS;
06354 } /* WN2C_translate_purple_main */
06355 
06356 
06357 void
06358 WN2C_memref_lhs(TOKEN_BUFFER tokens,
06359                 TY_IDX      *memref_typ,
06360                 const WN    *lhs,
06361                 STAB_OFFSET  memref_ofst,
06362                 TY_IDX       memref_addr_ty, 
06363                 TY_IDX       memref_object_ty, 
06364                 MTYPE        dtype,
06365                 CONTEXT      context)
06366 {
06367    /* Get the lvalue for an indirect memory reference (iload or
06368     * istore), returning the type of the resultant lvalue.
06369     */
06370    TY_IDX  base_ty;
06371    STATUS  lhs_status;
06372 
06373    /* Get the type of object being stored and the base-address from
06374     * which the store occurs.
06375    */
06376    base_ty = WN_Tree_Type(lhs);
06377    if (!TY_Is_Pointer(base_ty))
06378       base_ty = memref_addr_ty;
06379    *memref_typ = TY_pointed(memref_addr_ty);
06380    *memref_typ = WN2C_MemAccess_Type(TY_pointed(base_ty),/* base_type */
06381                                      *memref_typ,        /* preferred type */
06382                                      dtype,              /* required mtype */
06383                                      memref_ofst);       /* offset from base */
06384    
06385    /* Avoid a later cast if possible */
06386    //if (TY_mtype(*memref_typ) == TY_mtype(memref_object_ty))
06387    //   *memref_typ = memref_object_ty;
06388 
06389    /* Get the lhs, preferably as an lvalue, but possibly as an 
06390     * address.
06391     */
06392    lhs_status = WN2C_lvalue_wn(tokens,
06393                                lhs,         /* the base address */
06394                                base_ty,     /* the base addr_ty */
06395                                *memref_typ, /* type of object stored */
06396                                memref_ofst,
06397                                context);
06398 
06399    /* Dereference the address into which we are storing, if 
06400     * necessary.
06401     */
06402    if (!STATUS_is_lvalue(lhs_status))  
06403       Prepend_Token_Special(tokens, '*');
06404 } /* WN2C_memref_lhs */
06405 
06406 
06407 void
06408 WN2C_stid_lhs(TOKEN_BUFFER tokens,
06409               TY_IDX      *stored_typ,
06410               const ST    *lhs_st,
06411               STAB_OFFSET  stid_ofst,
06412               TY_IDX       stid_ty, 
06413               MTYPE        dtype,
06414               CONTEXT      context)
06415 {
06416    /* Get the lvalue for the lhs of an stid assignment.
06417     */
06418    TY_IDX  base_ty;
06419    STATUS  lhs_status;
06420 
06421    if (ST_sym_class(lhs_st) == CLASS_PREG)
06422    {
06423       /* For assignments to pregs, we never cast the lhs, instead
06424        * casting the rhs to fit the type of the preg.
06425        */
06426       *stored_typ = PUinfo_Preg_Type(ST_type(lhs_st), stid_ofst);
06427       WN2C_Append_Preg(tokens, 
06428                        lhs_st,    /* preg */
06429                        stid_ofst,   /* preg index */
06430                        *stored_typ,/* preg type */
06431                        context);
06432    }
06433    else
06434    {
06435       /* Get the lhs, preferably as an lvalue, but possibly as an 
06436        * address.
06437        */
06438      
06439 
06440       WN2C_SymAccess_Type(&base_ty,
06441                           stored_typ,
06442                           ST_type(lhs_st), /* base_type */
06443                           stid_ty,         /* preferred type */
06444                           dtype,           /* required mtype */
06445                           stid_ofst);      /* offset from base */
06446       lhs_status = WN2C_lvalue_st(tokens,
06447                                   lhs_st,      /* base stored into */
06448                                   base_ty,     /* base ref stored into */
06449                                   *stored_typ, /* type of object stored */
06450                                   stid_ofst,
06451                                   context);
06452 
06453       /* Dereference the address into which we are storing, if 
06454        * necessary 
06455        */
06456       if (!STATUS_is_lvalue(lhs_status))
06457          Prepend_Token_Special(tokens, '*');
06458    }
06459 } /* WN2C_stid_lhs */
06460 
06461 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines