Open64 (mfef90, whirl2f, and IR tools)  TAG: version-openad; SVN changeset: 916
wn2f.cxx
Go to the documentation of this file.
00001 /*
00002 
00003   Copyright (C) 2000, 2001 Silicon Graphics, Inc.  All Rights Reserved.
00004 
00005   This program is free software; you can redistribute it and/or modify it
00006   under the terms of version 2 of the GNU General Public License as
00007   published by the Free Software Foundation.
00008 
00009   This program is distributed in the hope that it would be useful, but
00010   WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00012 
00013   Further, this software is distributed without any warranty that it is
00014   free of the rightful claim of any third person regarding infringement 
00015   or the like.  Any license provided herein, whether implied or 
00016   otherwise, applies only to this software file.  Patent licenses, if 
00017   any, provided herein do not apply to combinations of this program with 
00018   other software, or any other product whatsoever.  
00019 
00020   You should have received a copy of the GNU General Public License along
00021   with this program; if not, write the Free Software Foundation, Inc., 59
00022   Temple Place - Suite 330, Boston MA 02111-1307, USA.
00023 
00024   Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pky,
00025   Mountain View, CA 94043, or:
00026 
00027   http://www.sgi.com
00028 
00029   For further information regarding this notice, see:
00030 
00031   http://oss.sgi.com/projects/GenInfo/NoticeExplan
00032 
00033 */
00034 
00035 
00036 /* ====================================================================
00037  * ====================================================================
00038  *
00039 
00040  *
00041  * Revision history:
00042  *  12-Apr-95 - Original Version
00043  *
00044  * Description:
00045  *
00046  *   Translate a WN subtree to Fortran by means of an inorder recursive
00047  *   descent traversal of the WHIRL IR.  Note that the routines to
00048  *   handle expressions, statements, and loads/stores have been
00049  *   separated into different source files.  However, the interfaces
00050  *   to those source-files should only ever be accessed from this file.
00051  *
00052  *      WN2F_translate:
00053  *         Translates an arbitrary WN tree into a sequence of tokens,
00054  *         appended to the end of the given token-buffer.  The task of
00055  *         translation will be dispatched to a member in a set of
00056  *         "handler" routines, and these handler routines should
00057  *         only be called from this routine.
00058  *
00059  * ====================================================================
00060  * ====================================================================
00061  */
00062 
00063 #ifdef _KEEP_RCS_ID
00064 /*REFERENCED*/
00065 #endif
00066 
00067 #include <alloca.h>
00068 #include <set>
00069 
00070 #include "x_string.h"        // for strcasecmp()
00071 #include "whirl2f_common.h"
00072 #include "PUinfo.h"          /* From be/whirl2c directory */
00073 #include "wn2f.h"
00074 #include "wn2f_stmt.h"       /* Only used by this module */
00075 #include "wn2f_pragma.h"     /* Only used by this module */
00076 #include "wn2f_expr.h"       /* Only used by this module */
00077 #include "wn2f_load_store.h" /* Only used by this module */
00078 #include "wn2f_io.h"         /* Only used by this module */
00079 #include "st2f.h"
00080 #include "ty2f.h"
00081 #include "tcon2f.h"
00082 #include "unparse_target.h"
00083 #include "ty_ftn.h"
00084 
00085 extern WN_MAP *W2F_Construct_Map;   /* Defined in w2f_driver.c */
00086 extern BOOL    W2F_Prompf_Emission; /* Defined in w2f_driver.c */
00087 char * sgi_comment_str = "CSGI$ " ;
00088 
00089 
00090 static BOOL  PU_Need_End_Contains = FALSE;  // f90 needs CONTAINS/END around nested procs.
00091 static BOOL  PU_Dangling_Contains = FALSE;  // f90 have done CONTAINS, need END...
00092 static INT32 PU_Host_Func_Id = 0 ;           // func id for END/CONTAINS
00093 
00094 WN* PU_Body=NULL;
00095 
00096 static void WN2F_End_Routine_Strings(TOKEN_BUFFER tokens, INT32 func_id);
00097 
00098 /*---------------- Buffers to hold intermediate results ----------------*/
00099 /*----------------------------------------------------------------------*/
00100  
00101 /* Should be initialized when entering a PU block and reclaimed 
00102  * when exiting a PU block.
00103  */
00104 TOKEN_BUFFER Data_Stmt_Tokens = NULL; /* Defined in init2f.c */
00105 
00106 
00107 /*-------------------- Function handle for each OPR -------------------*/
00108 /*---------------------------------------------------------------------*/
00109 
00110 /* Type of handler-functions for translation from WHIRL to Fortran.
00111  */
00112 typedef WN2F_STATUS (*WN2F_HANDLER_FUNC)(TOKEN_BUFFER, WN*, WN2F_CONTEXT);
00113 
00114 
00115 /* Declarations of top-level and exceptional handler-functions for 
00116  * translation from WHIRL to Fortran.  The others are declared through
00117  * "wn2f_stmt.h", "wn2f_expr.h", and "wn2f_load_store.h".
00118  */
00119 static WN2F_STATUS 
00120    WN2F_ignore(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context);
00121 static WN2F_STATUS 
00122    WN2F_unsupported(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context);
00123 static WN2F_STATUS 
00124    WN2F_func_entry(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context);
00125 static WN2F_STATUS 
00126    WN2F_altentry(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context);
00127 static WN2F_STATUS 
00128    WN2F_comment(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context);
00129 
00130 
00131 /* WN2F_Handler[] maps an OPR (../common/com/opcode_gen_core.h) to
00132  * the handler-function that translates it to Fortran.  This table
00133  * will be dynamically initialized through WN2F_initialize().  This
00134  * dynamic initialization ensures that the initiated elements of the
00135  * table are valid regardless of future changes to the OPERATOR
00136  * enumeration.  Operators not yet correctly handled by whirl2f, and
00137  * therefore not present in the WN2F_Opr_Handler_list[], will be
00138  * handled by WN2F_unsupported().
00139  */
00140 #define NUMBER_OF_OPERATORS (OPERATOR_LAST + 1)
00141 static WN2F_HANDLER_FUNC WN2F_Handler[NUMBER_OF_OPERATORS];
00142 
00143 typedef struct WN2F_Opr_Handler
00144 {
00145    OPERATOR           opr;
00146    WN2F_HANDLER_FUNC  handler;
00147 } WN2F_OPR_HANDLER;
00148 
00149 #define NUMBER_OF_OPR_HANDLERS \
00150    (sizeof(WN2F_Opr_Handler_List) / sizeof(WN2F_OPR_HANDLER))
00151 
00152 static const WN2F_OPR_HANDLER WN2F_Opr_Handler_List[] =
00153 {
00154    {OPR_FUNC_ENTRY, &WN2F_func_entry},
00155    {OPR_BLOCK, &WN2F_block},
00156    {OPR_REGION_EXIT, &WN2F_goto},
00157 /*   {OPR_SWITCH, &WN2F_switch}, Not a Fortran construct! */
00158    {OPR_COMPGOTO, &WN2F_compgoto},
00159    {OPR_DO_LOOP, &WN2F_do_loop},
00160    {OPR_DO_WHILE, &WN2F_do_while},
00161    {OPR_WHILE_DO, &WN2F_while_do},
00162    {OPR_IF, &WN2F_if},
00163    {OPR_GOTO, &WN2F_goto},
00164    {OPR_AGOTO, &WN2F_agoto},
00165    {OPR_ALTENTRY, &WN2F_altentry},
00166    {OPR_FALSEBR, &WN2F_condbr},
00167    {OPR_TRUEBR, &WN2F_condbr},
00168    {OPR_RETURN, &WN2F_return},
00169    {OPR_RETURN_VAL, &WN2F_return_val},
00170    {OPR_LABEL, &WN2F_label},
00171    {OPR_ISTORE, &WN2F_istore},
00172    {OPR_PSTORE, &WN2F_pstore},   
00173    {OPR_ISTOREX, &WN2F_istorex},
00174    {OPR_MSTORE, &WN2F_mstore},
00175    {OPR_STID, &WN2F_stid},
00176    {OPR_PSTID, &WN2F_pstid},   
00177    {OPR_CALL, &WN2F_call},
00178    {OPR_INTRINSIC_CALL, &WN2F_intrinsic_call},
00179    {OPR_ICALL, &WN2F_call},
00180    {OPR_PICCALL, &WN2F_call},
00181    {OPR_EVAL, &WN2F_eval},
00182    {OPR_PREFETCH, &WN2F_prefetch},
00183    {OPR_PREFETCHX, &WN2F_prefetch},
00184    {OPR_PRAGMA, &WN2F_pragma},
00185    {OPR_XPRAGMA, &WN2F_pragma},
00186    {OPR_IO, &WN2F_io},
00187    {OPR_COMMENT, &WN2F_comment},
00188    {OPR_ILOAD, &WN2F_iload},
00189    {OPR_ILOADX, &WN2F_iloadx},
00190    {OPR_MLOAD, &WN2F_mload},
00191    {OPR_ARRAY, &WN2F_array},
00192 
00193    {OPR_ARRAYEXP,&WN2F_arrayexp},      
00194    {OPR_ARRSECTION,&WN2F_arrsection},  
00195    {OPR_TRIPLET,&WN2F_triplet},        
00196    {OPR_SRCTRIPLET,&WN2F_src_triplet},        
00197    {OPR_WHERE,&WN2F_where},            
00198    {OPR_INTRINSIC_OP, &WN2F_intrinsic_op},
00199    {OPR_TAS, &WN2F_tas},
00200    {OPR_SELECT, &WN2F_select},
00201    {OPR_CVT, &WN2F_cvt},
00202    {OPR_CVTL, &WN2F_cvtl},
00203    {OPR_NEG, &WN2F_unaryop},
00204    {OPR_ABS, &WN2F_unaryop},
00205    {OPR_SQRT, &WN2F_unaryop},
00206    {OPR_REALPART, &WN2F_realpart},
00207    {OPR_IMAGPART, &WN2F_imagpart},
00208    {OPR_PAREN, &WN2F_paren},
00209    {OPR_RND, &WN2F_unaryop},
00210    {OPR_TRUNC, &WN2F_unaryop},
00211    {OPR_CEIL, &WN2F_ceil},
00212    {OPR_FLOOR, &WN2F_floor},
00213    {OPR_BNOT, &WN2F_unaryop},
00214    {OPR_LNOT, &WN2F_unaryop},
00215    {OPR_ADD, &WN2F_binaryop},
00216    {OPR_SUB, &WN2F_binaryop},
00217    {OPR_MPY, &WN2F_binaryop},
00218    {OPR_DIV, &WN2F_binaryop},
00219    {OPR_MOD, &WN2F_binaryop},
00220    {OPR_REM, &WN2F_binaryop},
00221    {OPR_MAX, &WN2F_binaryop},
00222    {OPR_MIN, &WN2F_binaryop},
00223    {OPR_BAND, &WN2F_binaryop},
00224    {OPR_BIOR, &WN2F_binaryop},
00225    {OPR_BNOR, &WN2F_bnor},
00226    {OPR_BXOR, &WN2F_binaryop},
00227    {OPR_LAND, &WN2F_binaryop},
00228    {OPR_LIOR, &WN2F_binaryop},
00229    {OPR_CAND, &WN2F_binaryop},
00230    {OPR_CIOR, &WN2F_binaryop},
00231    {OPR_SHL, &WN2F_binaryop},
00232    {OPR_ASHR, &WN2F_ashr},
00233    {OPR_LSHR, &WN2F_lshr},
00234    {OPR_COMPLEX, &WN2F_complex},
00235    {OPR_RECIP, &WN2F_recip},
00236    {OPR_RSQRT, &WN2F_rsqrt},
00237    {OPR_MADD, &WN2F_madd},
00238    {OPR_MSUB, &WN2F_msub},
00239    {OPR_NMADD, &WN2F_nmadd},
00240    {OPR_NMSUB, &WN2F_nmsub},
00241    {OPR_EQ, &WN2F_eq},
00242    {OPR_NE, &WN2F_ne},
00243    {OPR_GT, &WN2F_binaryop},
00244    {OPR_GE, &WN2F_binaryop},
00245    {OPR_LT, &WN2F_binaryop},
00246    {OPR_LE, &WN2F_binaryop},
00247    {OPR_LDID, &WN2F_ldid},
00248    {OPR_LDA, &WN2F_lda},
00249    {OPR_CONST, &WN2F_const},
00250    {OPR_INTCONST, &WN2F_intconst},
00251    {OPR_PARM, &WN2F_parm},
00252    {OPR_TRAP, &WN2F_ignore},
00253    {OPR_ASSERT, &WN2F_ignore},
00254    {OPR_FORWARD_BARRIER, &WN2F_ignore},
00255    {OPR_BACKWARD_BARRIER, &WN2F_ignore},
00256    {OPR_ALLOCA, &WN2F_alloca},
00257    {OPR_DEALLOCA, &WN2F_dealloca},
00258    {OPR_USE, &WN2F_use_stmt},
00259    {OPR_IMPLICIT_BND, &WN2F_implicit_bnd},  
00260    {OPR_NAMELIST, &WN2F_namelist_stmt},
00261    {OPR_INTERFACE, &WN2F_interface_blk},
00262    {OPR_SWITCH,&WN2F_switch},
00263    {OPR_CASEGOTO,&WN2F_casegoto},
00264    {OPR_NULLIFY,&WN2F_nullify_stmt},
00265    {OPR_ARRAY_CONSTRUCT,&WN2F_ar_construct},
00266    {OPR_IMPLIED_DO,&WN2F_noio_implied_do},
00267    {OPR_IDNAME, &WN2F_idname},
00268    {OPR_STRCTFLD, &WN2F_strctfld},
00269    {OPR_COMMA, &WN2F_comma}
00270    
00271 }; /* WN2F_Opr_Handler_List */
00272 
00273 
00274 /*------------------ Statement newline directives ----------------------*/
00275 /*----------------------------------------------------------------------*/
00276 
00277 void 
00278 WN2F_Stmt_Newline(TOKEN_BUFFER tokens,
00279                   const char  *label,
00280                   SRCPOS       srcpos,
00281                   WN2F_CONTEXT context)
00282 {
00283    if (WN2F_CONTEXT_no_newline(context))
00284    {
00285       if (W2F_File[W2F_LOC_FILE] != NULL)
00286          Append_Srcpos_Map(tokens, srcpos);
00287    }
00288    else
00289    {
00290       if (W2F_Emit_Linedirs)
00291          Append_Srcpos_Directive(tokens, srcpos);
00292       Append_F77_Indented_Newline(tokens, 1, label);
00293       if (W2F_File[W2F_LOC_FILE] != NULL)
00294          Append_Srcpos_Map(tokens, srcpos);
00295    }
00296 } /* WN2F_Stmt_Newline */
00297 
00298 
00299 /*--------------------------- Prompf processing ------------------------*/
00300 /*----------------------------------------------------------------------*/
00301 
00302 
00303 static void
00304 WN2F_Begin_Prompf_Transformed_Func(TOKEN_BUFFER tokens, INT32 func_id)
00305 {
00306    Append_F77_Directive_Newline(tokens, sgi_comment_str) ;
00307    Append_Token_String(tokens, "start");
00308    Append_Token_String(tokens, Number_as_String(func_id, "%llu"));
00309 }
00310 
00311 static void
00312 WN2F_End_Prompf_Transformed_Func(TOKEN_BUFFER tokens, INT32 func_id)
00313 {
00314    Append_F77_Directive_Newline(tokens, sgi_comment_str) ;
00315    Append_Token_String(tokens, "end");
00316    Append_Token_String(tokens, Number_as_String(func_id, "%llu"));
00317 } 
00318 
00319 
00320 /*------------ Translation of addressing and dereferencing -------------*/
00321 /*----------------------------------------------------------------------*/
00322 
00323 /* just used to maintain the state of the recursions when */
00324 /* marking FLDs in nested addresses                       */
00325 
00326 class LOC_INFO{
00327 
00328 private:
00329   FLD_PATH_INFO * _flds_left;   /* points to tail of fld_path */
00330   STAB_OFFSET _off;             /* offset of last FLD used in fld_path */
00331   BOOL   _base_is_array;        /* was ST of address an array? */
00332 
00333 public:
00334   WN * _nested_addr;
00335 
00336   LOC_INFO(FLD_PATH_INFO * path) {
00337     _flds_left = path;
00338 
00339     _off  = 0;
00340     _nested_addr = NULL;
00341     _base_is_array = FALSE ;
00342   }
00343 
00344   void WN2F_Find_And_Mark_Nested_Address(WN * addr);
00345 #ifdef FMZDBG
00346   void debugpathinfo(void);
00347 #endif
00348 };
00349 
00350 #ifdef FMZDBG
00351 void LOC_INFO::
00352 debugpathinfo(void)
00353 {
00354          FLD_PATH_INFO *fld_path_test;
00355          fld_path_test = _flds_left;
00356          printf("****In the file LOC_INFO::debugpathinf******\n");
00357          while (fld_path_test)
00358           {
00359            printf("\t***Field name in the path is :: %s\n",
00360                         FLD_name(fld_path_test->fld));
00361            if (fld_path_test->arr_wn)
00362              printf("\t***WN opr is %d \n",
00363                         WN_operator(fld_path_test->arr_wn)); 
00364            else 
00365              printf("\t***no WN find in the path\n");
00366 
00367            fld_path_test = fld_path_test->next; 
00368 
00369           }
00370 
00371         printf("****Out of the file LOC_INFO::debugpathinf******\n");
00372 }
00373 #endif
00374 
00375 void LOC_INFO::
00376 WN2F_Find_And_Mark_Nested_Address(WN * addr)
00377 {
00378   /* If this address expression contains nested ARRAY nodes */
00379   /* (and isn't a character expression), the ARRAYs refer   */
00380   /* to structure components, eg: aaa(1).kkk(3) yields      */
00381   /* ARRAY(ADD(const,ARRAY(LDA)). Add a pointer to the      */
00382   /* array elements of the fld path, associating each with  */
00383   /* corresponding OPC_ARRAY. TY2F_Translate_Fld_Path will  */
00384   /* write the subscript list.                              */
00385 
00386 
00387   /* In general, just the lowest LDID/LDA remains to be     */
00388   /* processed, however if the lowest ARRAY node is not a   */
00389   /* fld, and belongs to the address ST, then return that   */
00390   /* ARRAY.                                                 */
00391   switch (WN_operator(addr))
00392   {
00393   case OPR_ARRAY: 
00394   case OPR_ARRSECTION:
00395     {
00396      WN * kid;     
00397 #if 0 
00398      if (WN_operator(addr)==OPR_ARRAYEXP)
00399         addr = WN_kid0(addr);
00400 #endif
00401       kid = WN_kid0(addr);
00402       WN2F_Find_And_Mark_Nested_Address(kid);
00403       if ((_flds_left && _flds_left->arr_elt) &&
00404           (!(_base_is_array)))
00405       {
00406         _flds_left-> arr_wn = addr;
00407         _flds_left = TY2F_Point_At_Path(_flds_left,_off);
00408       } 
00409       else 
00410         _nested_addr = addr;
00411 
00412       _base_is_array = FALSE;
00413     }
00414     break;
00415 
00416 
00417   case OPR_ARRAYEXP: 
00418      WN * kid;     
00419      kid = WN_kid0(addr);
00420      WN2F_Find_And_Mark_Nested_Address(kid);
00421       _base_is_array = FALSE;
00422     break;
00423 
00424   case OPR_ADD:
00425     {
00426       WN * cnst = WN_kid0(addr);
00427       WN * othr = WN_kid1(addr);
00428 
00429       if (WN_operator(cnst) != OPR_INTCONST) 
00430       {
00431         cnst = WN_kid1(addr);
00432         othr = WN_kid0(addr);
00433       }
00434       WN2F_Find_And_Mark_Nested_Address(othr);
00435       _off = WN_const_val(cnst);
00436       _base_is_array = FALSE;
00437     }
00438     break;
00439 
00440   case OPR_LDID:
00441     _off = 0;
00442     _nested_addr = addr;
00443     _flds_left = TY2F_Point_At_Path(_flds_left,_off);
00444     _base_is_array = ((TY_kind(WN_ty(addr)) == KIND_POINTER) && 
00445                       (TY_kind(TY_pointed(WN_ty(addr))) == KIND_ARRAY));
00446     break;
00447 
00448   case OPR_LDA:
00449     _off = WN_lda_offset(addr);
00450     _nested_addr = addr;
00451     _base_is_array = ((TY_kind(WN_ty(addr)) == KIND_POINTER) &&
00452                       (TY_kind(TY_pointed(WN_ty(addr))) == KIND_ARRAY ||
00453                         TY_is_f90_deferred_shape(TY_pointed(WN_ty(addr)))));
00454     break;
00455 
00456   case OPR_ILOAD:
00457     _off = 0;
00458     _nested_addr = addr;
00459     _flds_left = TY2F_Point_At_Path(_flds_left,0);
00460     _base_is_array = ((TY_kind(WN_ty(addr)) == KIND_POINTER) && 
00461                       (TY_kind(TY_pointed(WN_ty(addr))) == KIND_ARRAY));
00462     break;
00463 
00464   default:
00465 
00466     ASSERT_WARN((0),
00467                 (DIAG_W2F_UNEXPECTED_OPC,"WN2F_Find_And_Mark_Nested_Address"));
00468 
00469     break;
00470   }
00471   return;
00472 }
00473 
00474 
00475 extern WN_OFFSET
00476 WN2F_Sum_Offsets(WN *addr)
00477 {
00478   /* Accumulate any offsets (ADDs) in this address   */
00479   /* tree. Used for computing Fld paths              */
00480 
00481   BOOL sum = 0;
00482 
00483   switch (WN_operator(addr))
00484   {
00485     case OPR_ARRAY: 
00486     case OPR_ARRAYEXP:
00487     case OPR_ARRSECTION:
00488     sum += WN2F_Sum_Offsets(WN_kid0(addr));
00489     break;
00490 
00491     case OPR_ADD:
00492     sum += WN2F_Sum_Offsets(WN_kid0(addr));
00493     sum += WN2F_Sum_Offsets(WN_kid1(addr));
00494     break;
00495 
00496     case OPR_INTCONST:
00497     sum = WN_const_val(addr);
00498     break;
00499   }
00500   return sum;
00501 }
00502 
00503 
00504 void 
00505 WN2F_Address_Of(TOKEN_BUFFER tokens)
00506 {
00507    Prepend_Token_Special(tokens, '(');
00508    Prepend_Token_String(tokens, "loc%");
00509    Append_Token_Special(tokens, '(');
00510 } /* WN2F_Address_Of */
00511 
00512 WN2F_STATUS
00513 WN2F_Offset_Symref(TOKEN_BUFFER tokens, 
00514                    ST          *st,         /* base-symbol */
00515                    TY_IDX       addr_ty,    /* expected base-address type */
00516                    TY_IDX       object_ty,  /* object type */
00517                    STAB_OFFSET  offset,     /* offset from base-address */
00518                    WN2F_CONTEXT context)
00519 {
00520    /* Given a symbol and an offset within the location of the symbol,
00521     * append a Fortran expression to "tokens" to access an object
00522     * of the given "object_ty" at this location.  
00523     *
00524     * The base symbol will unconditionally be treated as having an
00525     * lvalue (address) type as given by "addr_ty", except when "deref"
00526     * is TRUE, when the rvalue of the base-symbol is assumed to have
00527     * the "addr_ty" and must either explicitly (for POINTER variables) 
00528     * or implicitly (for pass by reference arguments) be dereferenced. 
00529     * Note that for a compatible base-type and object-type, this is simply
00530     * a reference to the given ST_name();  in all other cases we expect 
00531     * the object_ty to be a field (FLD) within the base-type (KIND_STRUCT)
00532     * or an offset within an array.
00533     *
00534     * Note that we must have special handling for common-blocks and
00535     * equivalences.  Note that "addr_ty" may be different from
00536     * "Stab_Pointer_To(ST_type(st))", both for "deref" cases and 
00537     * ptr_as_array variables.
00538     */
00539    TY_IDX       base_ty = TY_pointed(addr_ty);
00540    const BOOL deref_val = WN2F_CONTEXT_deref_addr(context);
00541    BOOL       deref_fld;
00542    void     (*translate_var_ref)(TOKEN_BUFFER, ST *);
00543 
00544 
00545  #ifdef __USE_COMMON_BLOCK_NAME__
00546 
00547    /* Do the symbol translation from the base of BASED symbols */
00548    if (Stab_Is_Based_At_Common_Or_Equivalence(st))
00549    {
00550       offset += ST_ofst(st); /* offset of based symbol */
00551       st = ST_base(st);      /* replace based symbol with its base */
00552 
00553       base_ty = ST_type(st);
00554       addr_ty = Stab_Pointer_To(base_ty);
00555       Set_BE_ST_w2fc_referenced(st);
00556    }
00557 
00558    /* Do the symbol translation from the base of fully split common symbols */
00559    if (ST_is_split_common(st))
00560    {
00561 #if 0
00562       offset += Stab_Full_Split_Offset(st);  /* offset of split common now zero. */
00563 #endif
00564       Clear_BE_ST_w2fc_referenced(st); 
00565       st = ST_full(st);
00566       Set_BE_ST_w2fc_referenced(st);
00567       base_ty = ST_type(st);
00568 
00569       if (TY_is_Pointer(base_ty))
00570          base_ty = TY_pointed(base_ty);
00571 
00572       if (TY_is_f90_pointer(base_ty))
00573          base_ty = TY_pointed(base_ty);
00574 
00575       addr_ty = Stab_Pointer_To(base_ty);
00576    }
00577 #endif 
00578 
00579 
00580    /* Select variable-reference translation function */
00581    if (deref_val                      && 
00582        ST_sclass(st) != SCLASS_FORMAL && 
00583        TY_Is_Pointer(ST_type(st)) && !TY_is_f90_pointer(ST_type(st)))
00584    {
00585       /* An explicitly dereference */
00586       translate_var_ref = &ST2F_deref_translate;
00587    }
00588    else
00589    {
00590       /* A direct reference or an implicit dereference */
00591       translate_var_ref = &ST2F_use_translate;
00592    }
00593 
00594    if (WN2F_Can_Assign_Types(base_ty, object_ty) || 
00595        (TY_kind(base_ty) == KIND_FUNCTION &&
00596         TY_kind(base_ty) == TY_kind(object_ty) &&
00597         TY_kind(object_ty) != KIND_STRUCT ))
00598    {
00599       /* Since the types are compatible, we cannot have an offset
00600        * into one of the objects.  Simply generate a reference to
00601        * the symbol.
00602        */
00603 
00604       ASSERT_WARN(offset==0, (DIAG_W2F_UNEXPEXTED_OFFSET,
00605                               offset, "WN2F_Offset_Symref"));
00606 
00607       translate_var_ref(tokens, st);
00608    }
00609    else if (TY_Is_Array(base_ty))
00610    {
00611       ASSERT_DBG_WARN(WN2F_Can_Assign_Types(TY_AR_etype(base_ty), object_ty),
00612                       (DIAG_W2F_INCOMPATIBLE_TYS, "WN2F_Offset_Symref"));
00613 
00614       if (TY_Is_Character_String(base_ty))
00615       {
00616 # if 0
00617          Append_Token_String(tokens, "ichar");
00618          Append_Token_Special(tokens, '(');
00619 # endif
00620          translate_var_ref(tokens, st);
00621          TY2F_Translate_ArrayElt(tokens, base_ty, offset);
00622 #if 0
00623          Append_Token_Special(tokens, ')');
00624 #endif
00625 
00626       }
00627       else
00628       {
00629          translate_var_ref(tokens, st);
00630       if (!WN2F_CONTEXT_has_no_arr_elmt(context)) {
00631            TY2F_Translate_ArrayElt(tokens, base_ty, offset);
00632            reset_WN2F_CONTEXT_has_no_arr_elmt(context);
00633         }
00634       }
00635    }
00636    else /* incompatible base and object types */
00637    {
00638 
00639 #if 0    //we use OPR_STRCTFLD to get the fld_path--FMZ August 2005
00640 /* we add OPR_STRCTFLD for X%Y, fld_path calculate no longer needed */
00641       FLD_PATH_INFO *fld_path;
00642 
00643       
00644       /* Get the path to the (undereferenced) object type.
00645        *
00646        * The following should no longer be necessary, since the
00647        * appropriate dereferencing of a field should happen in the 
00648        * translation of the field-path, not through a change of the
00649        * object type in the context.
00650        *
00651        *   if (deref)
00652        *     fld_path = 
00653        *        TY2F_Get_Fld_Path(base_ty, Stab_Pointer_To(object_ty), offset);
00654        *    else
00655        */
00656 
00657       /* We only dereference a field when the base need not be 
00658        * dereferenced.  We never need to have both dereferenced, 
00659        * since pointers cannot occur in RECORDS and common/
00660        * equivalence blocks cannot be referenced through pointer 
00661        * identifiers.
00662        */
00663       deref_fld = (deref_val && !TY_Is_Pointer(ST_type(st)))? TRUE : FALSE;
00664       if (deref_fld)
00665          object_ty = Stab_Pointer_To(object_ty);
00666 
00667       fld_path = TY2F_Get_Fld_Path(base_ty, object_ty, offset);
00668 
00669       if (fld_path == NULL)
00670       {
00671         /* return vars for entry points may have equivalence classes  */
00672         /* without anything at offset 0. Just put out the ST of the   */
00673         /* return variable, as we don't put out the equivalence group */
00674 
00675         if (ST_is_return_var(st)) 
00676          (void)translate_var_ref(tokens, st);
00677         else
00678         {
00679           ASSERT_DBG_WARN(FALSE, 
00680                           (DIAG_W2F_NONEXISTENT_FLD_PATH,
00681                            "WN2F_Offset_Symref"));
00682           Append_Token_String(tokens, "SOMEWHERE_IN");
00683           Append_Token_Special(tokens, '(');
00684           (void)translate_var_ref(tokens, st);
00685           Append_Token_Special(tokens, ')');
00686          }
00687       }
00688       else
00689       {
00690 //       if (!Stab_Is_Common_Block(st) && !Stab_Is_Equivalence_Block(st))
00691          {
00692             /* Base the path at the st object, and separate it from 
00693              * the remainder of the path with the field selection 
00694              * operator ('.').
00695              */
00696             (void)translate_var_ref(tokens, st);
00697             TY2F_Fld_Separator(tokens);
00698          }
00699 # if 0
00700          if (Stab_Is_Equivalence_Block(st) &&
00701              (ST_is_return_var(st) ||
00702               (PUinfo_current_func != NULL && 
00703                 (PUINFO_RETURN_TO_PARAM && st == PUINFO_RETURN_PARAM))))
00704             TY2F_Translate_Fld_Path(tokens, fld_path, 
00705                                     deref_fld,FALSE, TRUE,context);
00706          else
00707 # endif
00708 
00709             TY2F_Translate_Fld_Path(tokens, fld_path, 
00710                                     deref_fld, 
00711 //                                  (Stab_Is_Common_Block(st) || 
00712 //                                   Stab_Is_Equivalence_Block(st)),
00713                                     FALSE ,
00714                                     FALSE/*as_is*/,
00715                                     context);
00716 
00717          TY2F_Free_Fld_Path(fld_path);
00718       } /* if (the field was found) */
00719 #else  
00720          (void)translate_var_ref(tokens, st);
00721 #endif
00722 
00723    } /* if (base-type is compatible with object-type */
00724    
00725    return EMPTY_WN2F_STATUS;
00726 } /* WN2F_Offset_Symref */
00727 
00728 
00729 WN2F_STATUS
00730 WN2F_Offset_Memref(TOKEN_BUFFER tokens, 
00731                    WN          *addr,       /* base-address expression */
00732                    TY_IDX       addr_ty,    /* expected base-address type */
00733                    TY_IDX       object_ty,  /* object type */
00734                    STAB_OFFSET  offset,     /* offset from base-address */
00735                    WN2F_CONTEXT context)
00736 {
00737    /* Given an address expression and an offset from this address,
00738     * append a Fortran expression to "tokens" to access an object
00739     * of the given "object_ty" at this offset address.  I.e. this
00740     * is a dereferencing operation on the base-address. The resultant
00741     * value (e.g. after a struct-field access) may be further
00742     * dereferenced.
00743     *
00744     * The address expression is unconditionally treated as an expression
00745     * of the addr_ty.
00746     *
00747     * For non-zero offsets, or when "!WN2F_Can_Assign_Types(object_ty,
00748     * TY_pointed(addr_ty))", we expect the base-address to denote the
00749     * address of a structure or an array, where an object of the given 
00750     * object_ty can be found at the given offset.
00751     *
00752     * Since Fortran does not have an explicit (only implicit) dereference
00753     * operation we cannot first calculate the address and then 
00754     * dereference. This constrains the kind of expression we may handle
00755     * here.  Note that equivalences and common-blocks always should be 
00756     * accessed through an LDID or an LDA(?) node.
00757     */
00758 
00759    const BOOL deref_fld = WN2F_CONTEXT_deref_addr(context);
00760 
00761    /* Prepare to dereference the base-address expression */
00762    set_WN2F_CONTEXT_deref_addr(context);
00763 
00764    if (WN2F_Is_Address_Preg(addr,addr_ty))
00765    {
00766      /* Optimizer may put address PREGS into ARRAYs */
00767      /* and high level type is more or less useless */
00768      /* just go with WN tree ADDs etc.              */
00769 
00770     (void)WN2F_translate(tokens, addr, context);
00771 
00772      if (offset != 0)
00773      {
00774        Append_Token_Special(tokens, '+');
00775        Append_Token_String(tokens, Number_as_String(offset, "%lld"));
00776      }
00777    }
00778    else 
00779    {
00780 
00781      TY_IDX base_ty = TY_pointed(addr_ty);
00782 
00783 
00784 // deferred shape or f90 pointer
00785 // base_ty and object_ty not proper set in some cases
00786     if (TY_Is_Array(base_ty) &&
00787         TY_is_f90_deferred_shape(base_ty) &&
00788         !TY_Is_Array(object_ty) )
00789           base_ty = TY_AR_etype(base_ty);
00790 
00791      if (WN2F_Can_Assign_Types(base_ty, object_ty))
00792      {
00793       /* Since the types are compatible, we cannot have an offset
00794        * into one of the objects, and we further dispatch the task
00795        * of translation.
00796        */
00797 
00798 /* Since we do not generate dope vector for pointer, we could have 
00799    this kind of situation: such as ---FMZ
00800          type mytype
00801             integer i
00802             type(mytpe),pointer:: next
00803          end type mytype
00804          type(mytype) pv1,pv2
00805          pv1%next=pv2
00806 
00807 */
00808       ASSERT_WARN(offset==0, (DIAG_W2F_UNEXPEXTED_OFFSET,
00809                               offset, "WN2F_Offset_Memref"));
00810 
00811       (void)WN2F_translate(tokens, addr, context);
00812      }
00813      else /* Accessing a field in a record or an element of an array */
00814      {
00815        if (TY_Is_Array(base_ty))
00816        {
00817          ASSERT_DBG_WARN(WN2F_Can_Assign_Types(TY_AR_etype(base_ty), 
00818                                                object_ty),
00819                          (DIAG_W2F_INCOMPATIBLE_TYS, "WN2F_Offset_Memref"));
00820 
00821          if (TY_Is_Character_String(base_ty))
00822          {
00823 # if 0
00824             Append_Token_String(tokens, "ichar");
00825             Append_Token_Special(tokens, '(');
00826 # endif
00827             (void)WN2F_translate(tokens, addr, context); /* String lvalue */
00828 # if 0
00829             Append_Token_Special(tokens, ')');
00830 # endif
00831 
00832          }
00833          else
00834          {
00835             (void)WN2F_translate(tokens, addr, context); /* Array lvalue */
00836          }
00837        }
00838 
00839        else if ((WN_opc_operator(addr) == OPR_LDA || 
00840                  WN_opc_operator(addr) == OPR_LDID) &&
00841                 (TY_kind(base_ty) != KIND_STRUCT) &&
00842                 (Stab_Is_Common_Block(WN_st(addr)) || 
00843                  Stab_Is_Equivalence_Block(WN_st(addr))))
00844        {
00845          /* A common-block or equivalence-block, both of which we handle
00846           * only in WN2F_Offset_Symref().
00847           */
00848 
00849          ASSERT_WARN(WN2F_Can_Assign_Types(ST_type(WN_st(addr)), base_ty) ,
00850                      (DIAG_W2F_INCOMPATIBLE_TYS, "WN2F_Offset_Symref"));
00851 
00852          if (WN_opc_operator(addr) == OPR_LDA)
00853            reset_WN2F_CONTEXT_deref_addr(context);
00854          (void)WN2F_Offset_Symref(tokens, 
00855                                   WN_st(addr),
00856                                   addr_ty,                      /* base */
00857                                   object_ty,                    /* object */
00858                                   offset + WN_lda_offset(addr), /* offset */
00859                                   context);
00860        }
00861 
00862        else /* Neither common-block nor equivalence field-access */
00863        {
00864          /* Find the path to the field we wish to access and append
00865           * this path to the base-object reference.
00866           */
00867 
00868          FLD_PATH_INFO *fld_path;
00869 
00870          /* Get any offset given by an address ADDition node.  The type
00871           * of the addition, as given by WN_Tree_Type(), is the type
00872           * of base-object within which we are accessing, so the addr_ty
00873           * is already set up correctly to handle the combined offsets.
00874           */
00875 
00876          WN_OFFSET tmp = WN2F_Sum_Offsets(addr);
00877 
00878          if (tmp < TY_size(TY_pointed(addr_ty)))
00879              offset += tmp;
00880          else 
00881              offset = tmp;
00882       
00883          if (WN_operator(addr)==OPR_ARRAYEXP) 
00884                addr = WN_kid0(addr); 
00885 
00886           fld_path = TY2F_Get_Fld_Path(base_ty, object_ty, offset);
00887 
00888 #ifdef FMZDBG
00889   {
00890          FLD_PATH_INFO *fld_path_test;
00891          fld_path_test = fld_path;
00892          while (fld_path_test)
00893           {
00894            printf("\t***Field name in the path is :: %s\n",
00895                         FLD_name(fld_path_test->fld));
00896            if (fld_path_test->arr_wn)
00897              printf("\t***WN opr is %d \n",
00898                         WN_operator(fld_path_test->arr_wn)); 
00899            else 
00900              printf("\t***no WN found in the path\n");
00901 
00902            fld_path_test = fld_path_test->next; 
00903 
00904           }
00905    }
00906 #endif
00907 
00908          ASSERT_DBG_WARN(fld_path != NULL,
00909                          (DIAG_W2F_NONEXISTENT_FLD_PATH, 
00910                           "WN2F_Offset_Memref"));
00911 
00912 
00913          /* May have ARRAY(ADD(ARRAY(LDA),CONST)) or some such. */
00914          /* The deepest ARRAY (with the address) is handled     */
00915          /* by the WN2F_array processing, but the others        */
00916          /* are field references with array components.         */
00917 
00918          LOC_INFO det(fld_path);
00919 #ifdef FMZDBG
00920          det.debugpathinfo();
00921 #endif
00922          det.WN2F_Find_And_Mark_Nested_Address(addr);
00923 #ifdef FMZDBG
00924          det.debugpathinfo();
00925 #endif
00926          addr = det._nested_addr; 
00927          /* Get the base expression to precede the path */
00928 
00929          (void)WN2F_translate(tokens, addr, context);
00930 
00931          /* Append the path-name, perhaps w/o array subscripts. */
00932 #if 0 
00933           if (fld_type_z &&  offset_add) {
00934                  fld_path = TY2F_Get_Fld_Path(fld_type_z, fld_type_z, offset_add);
00935               } 
00936 #endif
00937 
00938 #ifdef FMZDBG
00939   {
00940          FLD_PATH_INFO *fld_path_test;
00941          fld_path_test = fld_path;
00942          while (fld_path_test)
00943           {
00944            printf("\t***Field name in the path is :: %s\n",
00945                         FLD_name(fld_path_test->fld));
00946            if (fld_path_test->arr_wn)
00947              printf("\t***WN opr is %d \n",
00948                         WN_operator(fld_path_test->arr_wn)); 
00949            else 
00950              printf("\t***no WN find in the path\n");
00951 
00952            fld_path_test = fld_path_test->next; 
00953           }
00954   }
00955 #endif
00956 
00957          if (fld_path != NULL) 
00958              {
00959                   TY2F_Fld_Separator(tokens);
00960                   TY2F_Translate_Fld_Path(tokens, 
00961                                    fld_path, 
00962                                    deref_fld, 
00963                                    FALSE/*common*/,
00964                                    FALSE/*as_is*/,
00965                                    context);
00966 #if 0 
00967                  }                               
00968               }
00969              fld_type_z = FLD_type(fld_path->fld);
00970 #endif
00971              TY2F_Free_Fld_Path(fld_path);
00972            }
00973            else
00974            {
00975              Append_Token_String(tokens, 
00976                                Number_as_String(offset, 
00977                                                 "<field-at-offset=%lld>"));
00978           }
00979 
00980        } /* if (neither common-block nor equivalence field-access */
00981 
00982      } /* if (object_ty is incompatible with base_ty) */
00983    } /* else */
00984 
00985    return EMPTY_WN2F_STATUS;
00986 } /* WN2F_Offset_Memref */
00987 
00988 /*---------------- Translation of function entry points ----------------*/
00989 /*----------------------------------------------------------------------*/
00990 
00991 void
00992 WN2F_Entry_Point(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
00993 {
00994    /* This will translate an alternate or function entry point with
00995     * parameter declarations into Fortran.  Note that the 
00996     * PUinfo_current_func will not change as a result of this call.
00997     *
00998     */
00999    ST    **param_st;
01000    INT     param, num_formals;
01001 
01002    ASSERT_DBG_FATAL(WN_opcode(wn) == OPC_ALTENTRY || 
01003                     WN_opcode(wn) == OPC_FUNC_ENTRY,
01004                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_Entry_Point"));
01005 
01006    if (WN_opcode(wn) == OPC_ALTENTRY)
01007       num_formals = WN_kid_count(wn);
01008    else
01009       num_formals = WN_num_formals(wn);
01010 
01011    /* Accumulate the parameter ST entries */
01012    param_st = (ST **)alloca((num_formals + 1) * sizeof(ST *));
01013    for (param = 0; param < num_formals; param++)
01014    {
01015       param_st[param] = WN_st(WN_formal(wn, param));
01016    }
01017    /* Terminate the list of parameter STs */
01018    param_st[num_formals] = NULL;
01019 
01020    /* Write out the entry point with parameter declarations 
01021     * on a new line.
01022     */
01023    //   WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
01024    ST2F_func_header(tokens, 
01025                     &St_Table[WN_entry_name(wn)], 
01026                     param_st, 
01027                     num_formals,
01028                     WN_opcode(wn) == OPC_ALTENTRY);
01029 
01030 } /* WN2F_Entry_Point */
01031 
01032 
01033 /*--------- The operator handlers implemented in this module ----------*/
01034 /*---------------------------------------------------------------------*/
01035 
01036 
01037 static WN2F_STATUS
01038 WN2F_ignore(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
01039 {
01040    return EMPTY_WN2F_STATUS;
01041 } /* WN2F_ignore */
01042 
01043 
01044 static WN2F_STATUS
01045 WN2F_unsupported(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
01046 {
01047    /* Warn about opcodes we cannot translate, but keep translating.
01048     */
01049    ASSERT_WARN(FALSE,
01050                (DIAG_W2F_CANNOT_HANDLE_OPC, WN_opc_name(wn), WN_opcode(wn)));
01051 
01052    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
01053    Append_Token_String(tokens, Concat3_Strings("<", WN_opc_name(wn), ">"));
01054    
01055    return EMPTY_WN2F_STATUS;
01056 } /* WN2F_unsupported */
01057 
01058 
01059 static WN2F_STATUS
01060 WN2F_func_entry(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
01061 {
01062    /* Add tokens for the function header and body to "tokens".  Note
01063     * that the whole function definition will appended to the buffer,
01064     * while the task of writing the tokens to file and freeing up
01065     * the buffer is left to the caller.
01066     *
01067     * Assume that Current_Symtab has been updated (see bedriver.c).
01068     * Note that Current_PU is not maintained, but we instead get to
01069     * it through PUinfo_current_func.
01070     *
01071     */
01072    INT32 func_id = 0;
01073 
01074    ASSERT_DBG_FATAL(WN_opcode(wn) == OPC_FUNC_ENTRY, 
01075                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_func_entry"));
01076    
01077    /* Write prompf information */
01078 
01079    if (W2F_Prompf_Emission) {
01080       func_id = WN_MAP32_Get(*W2F_Construct_Map, wn);
01081       WN2F_Begin_Prompf_Transformed_Func(tokens, func_id);
01082    }
01083 
01084    /* For local declarations, set the indentation to the current
01085     * indentation */
01086 
01087    PUinfo_local_decls_indent = Current_Indentation();
01088 
01089     PU_Body=WN_func_body(wn);
01090 
01091    /* Translate the function header */
01092    WN2F_Entry_Point(tokens, wn, context);
01093    
01094    /* Emit the function pragmas before local variables */
01095    if (!W2F_No_Pragmas)
01096       WN2F_pragma_list_begin(PUinfo_pragmas, 
01097                              WN_first(WN_func_pragmas(wn)),
01098                              context);
01099    
01100    set_WN2F_CONTEXT_new_pu(context);
01101    (void)WN2F_translate(tokens, WN_func_body(wn), context);
01102 
01103    /* While necessary for regions, we probably need not end any pragmas
01104     * in a func_entry, but we make the call anyway;  for consistency.
01105     */
01106    if (!W2F_No_Pragmas)
01107       WN2F_pragma_list_end(tokens,
01108                            WN_first(WN_func_pragmas(wn)),
01109                            context);
01110 
01111    WN2F_Stmt_Newline(tokens,NULL, WN_Get_Linenum(wn), context); 
01112 
01113    WN2F_End_Routine_Strings(tokens,func_id);
01114 
01115    return EMPTY_WN2F_STATUS;
01116  }
01117 
01118 WN2F_STATUS 
01119 WN2F_altentry(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
01120 {
01121    /* This is very similar to a func_entry, but without the function
01122     * body.
01123     */
01124    ASSERT_DBG_FATAL(WN_opcode(wn) == OPC_ALTENTRY,
01125                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_altentry"));
01126    
01127    /* Translate the function entry point */
01128    WN2F_Entry_Point(tokens, wn, context);
01129 
01130    return EMPTY_WN2F_STATUS;
01131 } /* WN2F_altentry */
01132 
01133 
01134 WN2F_STATUS 
01135 WN2F_comment(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
01136 {
01137    ASSERT_DBG_FATAL(WN_opcode(wn) == OPC_COMMENT,
01138                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_comment"));
01139 
01140    /* Used to avoid comments with special interpretation.  Note that
01141       this is basically a prefix test.
01142     */
01143    static char* avoid[] = {
01144      "ENDLOOP",
01145      /* original text of I/O stmt is saved in comment nodes */
01146      /*   open, close, rewind, backspace, format? */
01147      "read", "write", "print" 
01148    };
01149    static int avoidSZ = sizeof(avoid) / sizeof(char*);
01150    
01151    const char* com = Index_To_Str(WN_GetComment(wn));
01152    
01153    for (int i = 0; i < avoidSZ; ++i) {
01154      const char* str = avoid[i];
01155      if (ux_strncasecmp(com, str, strlen(str)) == 0) { 
01156        return EMPTY_WN2F_STATUS; 
01157      }
01158    }
01159    
01160    WHIRL2F_Append_Comment(tokens, com, 0, 0);
01161    
01162    return EMPTY_WN2F_STATUS;
01163 } /* WN2F_comment */
01164 
01165 
01166 /*------------------------ exported routines --------------------------*/
01167 /*---------------------------------------------------------------------*/
01168 
01169 
01170 void 
01171 WN2F_initialize(void)
01172 {
01173    INT opr;
01174    INT map;
01175 
01176    /* Reset the WN2F_Handler array */
01177    for (opr = 0; opr < NUMBER_OF_OPERATORS; opr++)
01178       WN2F_Handler[opr] = &WN2F_unsupported;
01179 
01180    /* Initialize the WN2F_Handler array */
01181    for (map = 0; map < NUMBER_OF_OPR_HANDLERS; map++)
01182       WN2F_Handler[WN2F_Opr_Handler_List[map].opr] =
01183          WN2F_Opr_Handler_List[map].handler;
01184 
01185    WN2F_Stmt_initialize();
01186    WN2F_Expr_initialize();
01187    WN2F_Load_Store_initialize();
01188    WN2F_Io_initialize();
01189    
01190 } /* WN2F_initialize */
01191 
01192 
01193 void 
01194 WN2F_finalize(void)
01195 {
01196    /* Reset the auxiliary WN translator modules, and the stab_attr
01197     * facility.
01198     */
01199    WN2F_Stmt_finalize();
01200    WN2F_Expr_finalize();
01201    WN2F_Load_Store_finalize();
01202    WN2F_Io_finalize();
01203    Stab_Free_Tmpvars();
01204 } /* WN2F_finalize */
01205 
01206 // utility to interpret context information 
01207 
01208 void 
01209 WN2F_dump_context( WN2F_CONTEXT c)
01210 {
01211   printf ("(");
01212 
01213   if (WN2F_CONTEXT_new_pu(c))            printf (" new_pu") ;
01214   if (WN2F_CONTEXT_insert_induction(c))  printf (" induct_tmp_reqd") ;
01215   if (WN2F_CONTEXT_deref_addr(c))        printf (" deref") ;
01216   if (WN2F_CONTEXT_no_newline(c))        printf (" no_newline") ;
01217   if (WN2F_CONTEXT_has_logical_arg(c))   printf (" logical_arg") ;
01218   if (WN2F_CONTEXT_no_parenthesis(c))    printf (" no_paren") ;
01219   if (WN2F_CONTEXT_keyword_ioctrl(c))    printf (" ioctrl") ;
01220   if (WN2F_CONTEXT_io_stmt(c))           printf (" in_io") ;
01221   if (WN2F_CONTEXT_deref_io_item(c))     printf (" deref_io") ;
01222   if (WN2F_CONTEXT_origfmt_ioctrl(c))    printf (" varfmt")   ;
01223   if (WN2F_CONTEXT_emit_stid(c))         printf (" emit_stid") ;
01224   if (WN2F_CONTEXT_explicit_region(c))   printf (" region_pragma") ;
01225   if (WN2F_CONTEXT_fmt_io(c))            printf (" formatted io") ;
01226   if (WN2F_CONTEXT_cray_io(c))           printf (" craylib") ;
01227   printf (")\n");
01228 }
01229 
01230 
01231 WN2F_STATUS 
01232 WN2F_translate(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
01233 {   
01234    const BOOL parenthesize = !WN2F_CONTEXT_no_parenthesis(context);
01235 
01236    /* Determine whether we are in a context where we expect this
01237     * expression to have logically valued arguments, or whether
01238     * we are entering a context where we expect this expression
01239     * to be a logically valued argument.
01240     */
01241    if (OPCODE_is_boolean(WN_opcode(wn)) && 
01242        WN2F_expr_has_boolean_arg(WN_opcode(wn)))  /* expect logical args */
01243    {
01244       /* Note that this may also be a logical argument, so
01245        * WN2F_CONTEXT_is_logical_arg(context) may also hold TRUE.
01246        */
01247       set_WN2F_CONTEXT_has_logical_arg(context);
01248    }
01249    else if (WN2F_CONTEXT_has_logical_arg(context)) /* is a logical arg */
01250    {
01251       /* This is the only place where we should need to check whether
01252        * this is expected to be a logical valued expression. I.e. the
01253        * only place where we apply WN2F_CONTEXT_has_logical_arg(context).
01254        * However, it may be set at other places (e.g. in wn2f_stmt.c).
01255        */
01256       reset_WN2F_CONTEXT_has_logical_arg(context);
01257       set_WN2F_CONTEXT_is_logical_arg(context);
01258    }
01259    else
01260    {
01261       reset_WN2F_CONTEXT_has_logical_arg(context);
01262       reset_WN2F_CONTEXT_is_logical_arg(context);
01263    }
01264    
01265    /* Dispatch to the appropriate handler for this construct.
01266     */
01267    OPERATOR op = WN_opc_operator(wn);
01268    WN2F_STATUS ret = WN2F_Handler[WN_opc_operator(wn)](tokens, wn, context);
01269    
01270    /* reset: this flag should only affect children of 'wn', not any siblings */
01271    reset_WN2F_CONTEXT_has_logical_arg(context);
01272    
01273    return ret;
01274 } /* WN2F_translate */
01275 
01276 WN2F_STATUS 
01277 WN2F_translate_purple_main(TOKEN_BUFFER tokens,
01278                            WN          *pu, 
01279                            const char  *region_name,
01280                            WN2F_CONTEXT context)
01281 {
01282    static const char prp_return_var_name[] = "prp___return";
01283    extern BOOL Use_Purple_Array_Bnds_Placeholder; /* Defined in ty2f.c */
01284 
01285    TY_IDX return_ty;
01286    ST  *param_st;
01287    INT  first_param, param, implicit_parms = 0;
01288 
01289    ASSERT_DBG_FATAL(WN_opcode(pu) == OPC_FUNC_ENTRY,
01290                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_translate_purple_main"));
01291 
01292    /* Write program header
01293     */
01294    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(pu), context);
01295    Append_Token_String(tokens, "PROGRAM MAIN");
01296 
01297 # if 0
01298    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(pu), context);
01299    Append_Token_String(tokens, "IMPLICIT NONE");
01300 # endif
01301 
01302    /* Write program local variables (region parameters)
01303     */
01304    Use_Purple_Array_Bnds_Placeholder = TRUE;
01305    first_param = ST2F_FIRST_PARAM_IDX(ST_type(WN_entry_name(pu)));
01306    for (param = first_param; 
01307         (param+implicit_parms) < WN_num_formals(pu); 
01308         param++)
01309    {
01310       param_st = WN_st(WN_formal(pu, param));
01311       if (STAB_PARAM_HAS_IMPLICIT_LENGTH(param_st))
01312          implicit_parms++;
01313 
01314       Append_F77_Indented_Newline(tokens, 1, NULL/*label*/);
01315       
01316       ST2F_decl_translate(tokens, param_st);
01317       Append_F77_Indented_Newline(tokens, 1, NULL/*label*/);
01318       Append_Token_String(tokens, "SAVE");
01319       Append_Token_String(tokens, W2CF_Symtab_Nameof_St(param_st));
01320 
01321    } /* while more params */
01322    Use_Purple_Array_Bnds_Placeholder = FALSE;
01323 
01324    /* We do not really care what is returned from the purplized region,
01325     * but for correctness we insert a declaration for any return variable
01326     * here, with a default name.  We also insert a declaration of the
01327     * purple_region.
01328     */
01329    return_ty = W2X_Unparse_Target->Func_Return_Type(ST_type(WN_entry_name(pu)));
01330    if (return_ty != (TY_IDX) 0 && TY_kind(return_ty) != KIND_VOID)
01331    {
01332       TOKEN_BUFFER return_tokens = New_Token_Buffer();
01333 
01334       /* Append the function declaration
01335        */
01336       Append_Token_String(return_tokens, region_name);
01337       if (TY_Is_Pointer(return_ty)) /* Cannot return ptr in ftn */
01338          TY2F_translate(return_tokens, 
01339                         Stab_Mtype_To_Ty(TY_mtype(return_ty)));
01340       else
01341          TY2F_translate(return_tokens, return_ty);
01342 
01343       Append_F77_Indented_Newline(tokens, 1, NULL/*label*/);
01344       Append_Token_String(tokens, "EXTERNAL");
01345       Append_Token_String(tokens, region_name);
01346       Append_F77_Indented_Newline(tokens, 1, NULL/*label*/);
01347       Append_And_Reclaim_Token_List(tokens, &return_tokens);
01348 
01349       /* Append the return variable
01350        */
01351       return_tokens = New_Token_Buffer();
01352       Append_Token_String(return_tokens, prp_return_var_name);
01353       if (TY_Is_Pointer(return_ty)) /* Cannot return ptr in ftn */
01354          TY2F_translate(return_tokens, 
01355                         Stab_Mtype_To_Ty(TY_mtype(return_ty)));
01356       else
01357          TY2F_translate(return_tokens, return_ty);
01358 
01359       Append_F77_Indented_Newline(tokens, 1, NULL/*label*/);
01360       Append_And_Reclaim_Token_List(tokens, &return_tokens);
01361    }
01362 
01363    /* Insert a placeholder for initialization of parameters
01364     */
01365    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(pu), context);
01366    Append_Token_String(tokens, "<#PRP_XSYM:INIT_PARAM");
01367    WN2F_Append_Purple_Funcinfo(tokens);
01368    Append_Token_String(tokens, "#>");
01369 
01370    /* Insert call to purple region routine
01371     */
01372    WHIRL2F_Append_Comment(tokens, 
01373                           "**** Call to extracted purple region ****",
01374                           1, 1);
01375    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(pu), context);
01376    if (return_ty != (TY_IDX) 0 && TY_kind(return_ty) != KIND_VOID)
01377    {
01378       Append_Token_String(tokens, prp_return_var_name);
01379       Append_Token_Special(tokens, '=');
01380    }
01381    else
01382       Append_Token_String(tokens, "CALL");
01383    Append_Token_String(tokens, region_name);
01384    Append_Token_Special(tokens, '(');
01385    for (param = first_param; 
01386         (param+implicit_parms) < WN_num_formals(pu);
01387         param++)
01388    {
01389       if (param > first_param)
01390          Append_Token_Special(tokens, ',');
01391 
01392       param_st = WN_st(WN_formal(pu, param));
01393       Append_Token_String(tokens, W2CF_Symtab_Nameof_St(param_st));
01394    }
01395    Append_Token_Special(tokens, ')');
01396 
01397    /* Insert a placeholder for final testing of parameters
01398     */
01399    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(pu), context);
01400    Append_Token_String(tokens, "<#PRP_XSYM:TEST_PARAM");
01401    WN2F_Append_Purple_Funcinfo(tokens);
01402    Append_Token_String(tokens, "#>");
01403 
01404    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(pu), context); 
01405    Append_Token_String(tokens, "END");
01406    Append_Token_String(tokens, "!");
01407    Append_Token_String(tokens, "MAIN");
01408    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(pu), context); 
01409    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(pu), context); 
01410    
01411    return EMPTY_WN2F_STATUS;
01412 } /* WN2F_translate_purple_main */
01413 
01414 
01415 /*------------------------ sundry utilities  --------------------------*/
01416 /*---------------------------------------------------------------------*/
01417 
01418 extern void
01419 WN2F_Emit_End_Stmt(TOKEN_BUFFER tokens, BOOL start)
01420 {
01421   /* For F90 host routine don't know about first/last internal procedures until
01422    * they're processed, so the host didn't get an END.  Emit the enclosing 
01423    * CONTAINS/END if required.
01424    */ 
01425 
01426   if (PU_Need_End_Contains) 
01427   {
01428     if (start)
01429     {
01430       if(PU_Dangling_Contains) 
01431       {
01432         PU_Dangling_Contains = FALSE;
01433         Append_Token_String(tokens,"CONTAINS");
01434         if (W2F_Prompf_Emission) 
01435           WN2F_End_Prompf_Transformed_Func(tokens, PU_Host_Func_Id);
01436         Append_Token_Special(tokens, '\n');
01437       }
01438     }
01439     else 
01440     { 
01441       PU_Need_End_Contains = FALSE;
01442       if (Is_Empty_Token_Buffer(tokens))
01443         Append_F77_Indented_Newline(tokens,0,NULL);
01444       Append_Token_String(tokens,"END");
01445 
01446       /* if wasn't really a host, but just had nested parallel routines */
01447       /* emit id now, because it wasn't emitted on the CONTAINS         */
01448 
01449       if (W2F_Prompf_Emission && PU_Dangling_Contains)
01450         WN2F_End_Prompf_Transformed_Func(tokens, PU_Host_Func_Id);
01451       Append_Token_Special(tokens,'\n');
01452     }
01453   }
01454 }
01455 
01456 static void
01457 WN2F_End_Routine_Strings(TOKEN_BUFFER tokens, INT32 func_id)
01458 {
01459   // figures out how to END the current function.
01460   // An f77 routine, or f90 non-host just needs an END.
01461   // An f90 host requires a CONTAINs plus an END when the
01462   // last internal routine was seen. Distinguish functions
01463   // and subroutines for f90. 
01464 
01465   PU & pu = Pu_Table[ST_pu(PUINFO_FUNC_ST)];
01466 
01467   if (WN2F_F90_pu) {
01468     if (PU_has_nested(pu) ) 
01469     {
01470       PU_Need_End_Contains = TRUE;
01471       PU_Dangling_Contains = TRUE;
01472       PU_Host_Func_Id = func_id; 
01473     }
01474     else {
01475 
01476       char * p ;
01477 
01478       if (PU_is_mainpu(pu)) 
01479         p = "END PROGRAM";
01480 
01481       else {
01482         TY_IDX rt = PUINFO_RETURN_TY;
01483 
01484         if (TY_kind(rt) == KIND_VOID) {
01485           if (ST_is_in_module(PUINFO_FUNC_ST) && !PU_is_nested_func(pu))  
01486             p = "END MODULE";
01487           else
01488           if (ST_is_block_data(PUINFO_FUNC_ST))
01489             p = "END BLOCK DATA";
01490           else
01491           p = "END SUBROUTINE";
01492         }
01493         else
01494           p = "END FUNCTION";
01495       }
01496       Append_Token_String(tokens,p);
01497 
01498       if (W2F_Prompf_Emission) 
01499         WN2F_End_Prompf_Transformed_Func(tokens,func_id);
01500 
01501       Append_Token_Special(tokens, '\n');
01502     }                                             
01503 
01504   } else {  /* F77 routine */
01505 
01506     Append_Token_String(tokens, "END");
01507     Append_Token_String(tokens, "!");
01508     Append_Token_String(tokens, PUINFO_FUNC_NAME) ;
01509     
01510     if (W2F_Prompf_Emission) 
01511       WN2F_End_Prompf_Transformed_Func(tokens,func_id);
01512 
01513     Append_Token_Special(tokens, '\n');
01514     Append_Token_Special(tokens, '\n');
01515   }
01516 }
01517 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines