Open64 (mfef90, whirl2f, and IR tools)
TAG: version-openad; SVN changeset: 916
|
00001 /* 00002 00003 Copyright (C) 2000, 2001 Silicon Graphics, Inc. All Rights Reserved. 00004 00005 This program is free software; you can redistribute it and/or modify it 00006 under the terms of version 2 of the GNU General Public License as 00007 published by the Free Software Foundation. 00008 00009 This program is distributed in the hope that it would be useful, but 00010 WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00012 00013 Further, this software is distributed without any warranty that it is 00014 free of the rightful claim of any third person regarding infringement 00015 or the like. Any license provided herein, whether implied or 00016 otherwise, applies only to this software file. Patent licenses, if 00017 any, provided herein do not apply to combinations of this program with 00018 other software, or any other product whatsoever. 00019 00020 You should have received a copy of the GNU General Public License along 00021 with this program; if not, write the Free Software Foundation, Inc., 59 00022 Temple Place - Suite 330, Boston MA 02111-1307, USA. 00023 00024 Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pky, 00025 Mountain View, CA 94043, or: 00026 00027 http://www.sgi.com 00028 00029 For further information regarding this notice, see: 00030 00031 http://oss.sgi.com/projects/GenInfo/NoticeExplan 00032 00033 */ 00034 00035 00036 /* ==================================================================== 00037 * ==================================================================== 00038 * 00039 * 00040 * Revision history: 00041 * 07-Oct-94 - Original Version 00042 * 00043 * Description: 00044 * 00045 * 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