wn2f_stmt.cxx

Go to the documentation of this file.
00001 /*
00002 
00003   Copyright (C) 2000, 2001 Silicon Graphics, Inc.  All Rights Reserved.
00004 
00005   This program is free software; you can redistribute it and/or modify it
00006   under the terms of version 2 of the GNU General Public License as
00007   published by the Free Software Foundation.
00008 
00009   This program is distributed in the hope that it would be useful, but
00010   WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00012 
00013   Further, this software is distributed without any warranty that it is
00014   free of the rightful claim of any third person regarding infringement 
00015   or the like.  Any license provided herein, whether implied or 
00016   otherwise, applies only to this software file.  Patent licenses, if 
00017   any, provided herein do not apply to combinations of this program with 
00018   other software, or any other product whatsoever.  
00019 
00020   You should have received a copy of the GNU General Public License along
00021   with this program; if not, write the Free Software Foundation, Inc., 59
00022   Temple Place - Suite 330, Boston MA 02111-1307, USA.
00023 
00024   Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pky,
00025   Mountain View, CA 94043, or:
00026 
00027   http://www.sgi.com
00028 
00029   For further information regarding this notice, see:
00030 
00031   http://oss.sgi.com/projects/GenInfo/NoticeExplan
00032 
00033 */
00034 
00035 
00036 /* ====================================================================
00037  * ====================================================================
00038  *
00039  *
00040  * Revision history:
00041  *  12-Apr-95 - Original Version
00042  *
00043  * Description:
00044  *
00045  *   Translate a WN statement subtree to Fortran by means of an inorder 
00046  *   recursive descent traversal of the WHIRL IR.  Note that the routines
00047  *   handle expressions and loads/stores are in separate source files.
00048  *   Recursive translation of WN nodes should only use WN2F_Translate()!
00049  *
00050  *   Conventions:
00051  *
00052  *       + Newline characters or comments are prepended to a stmt in
00053  *         the translation of that stmt.
00054  *
00055  *
00056  * ====================================================================
00057  * ====================================================================
00058  */
00059 
00060 #ifdef _KEEP_RCS_ID
00061 /*REFERENCED*/
00062 #endif
00063 
00064 #include <iostream>
00065 
00066 #include <alloca.h>
00067 #include "whirl2f_common.h"
00068 #include "const.h"           /* For FOR_ALL_CONSTANTS */
00069 #include "pf_cg.h"
00070 #include "w2cf_parentize.h"
00071 #include "PUinfo.h"          /* In be/whirl2c directory */
00072 #include "wn2f.h"
00073 #include "st2f.h"
00074 #include "ty2f.h"
00075 #include "tcon2f.h"
00076 #include "wn2f_stmt.h"
00077 #include "wn2f_load_store.h"
00078 #include "wn2f_io.h"
00079 #include "wn2f_pragma.h"
00080 #include "init2f.h"
00081 #include "be_symtab.h"
00082 #include "intrn_info.h"              /* INTR macros */     
00083 #include "unparse_target.h"
00084 #include "ty_ftn.h"
00085 
00086 extern WN_MAP  W2F_Frequency_Map;   /* Defined in w2f_driver.c */
00087 extern WN_MAP *W2F_Construct_Map;   /* Defined in w2f_driver.c */
00088 extern BOOL    W2F_Prompf_Emission; /* Defined in w2f_driver.c */
00089 extern BOOL    W2F_Emit_Cgtag;      /* Defined in w2f_driver.c */
00090 
00091 extern TOKEN_BUFFER  param_tokens;
00092 
00093 static const char WN2F_Purple_Region_Name[] = "prp___region";
00094 static const char unnamed_interface[] = "unnamed interface"; 
00095 
00096 #define WN_pragma_nest(wn) WN_pragma_arg1(wn)
00097 
00098 
00099 /*----------------- Call and return site utilities --------------------*/
00100 /*---------------------------------------------------------------------*/
00101 
00102 /* Lists of return and call sites for the current PU,
00103  * initialized by means of "PUinfo.h" facilities.
00104  */
00105 static RETURNSITE *WN2F_Next_ReturnSite = NULL;
00106 static CALLSITE *WN2F_Prev_CallSite = NULL;
00107 
00108 
00109 static void
00110 WN2F_Load_Return_Reg(TOKEN_BUFFER tokens,
00111                      TY_IDX       return_ty,
00112                      const char * var_name,
00113                      STAB_OFFSET  var_offset,
00114                      MTYPE        preg_mtype,
00115                      PREG_IDX     preg_offset,
00116                      WN2F_CONTEXT context)
00117 {
00118    /* Load a preg value from the given variable at the given offset
00119     * from the base-address of the variable.
00120     */
00121    const TY_IDX preg_ty = Stab_Mtype_To_Ty(preg_mtype);
00122    TOKEN_BUFFER tmp_tokens = New_Token_Buffer();
00123    FLD_PATH_INFO *path ;
00124 
00125    /* Cast the rhs to the type of the preg, and dereference the
00126     * resultant address.
00127     */
00128    Append_Token_String(tmp_tokens, var_name);
00129    Append_Token_Special(tmp_tokens, WN2F_F90_pu ? '%' : '.');
00130    path = TY2F_Get_Fld_Path(return_ty,preg_ty,var_offset);
00131    TY2F_Translate_Fld_Path(tmp_tokens,path,FALSE,FALSE,FALSE,context);
00132    (void)TY2F_Free_Fld_Path(path);
00133 
00134    /* Assign the variable to the preg */
00135    ST2F_Use_Preg(tokens, preg_ty, preg_offset);
00136    Append_Token_Special(tokens, '=');
00137    Append_And_Reclaim_Token_List(tokens, &tmp_tokens);
00138 
00139 } /* WN2F_Load_Return_Reg */
00140 
00141 static void
00142 WN2F_Callsite_Directives(TOKEN_BUFFER tokens, 
00143                          WN          *call_wn,
00144                          ST          *func_st)
00145 {
00146    if (WN_Call_Inline(call_wn))
00147    {
00148       Append_F77_Directive_Newline(tokens, "C*$*");
00149       Append_Token_String(tokens, "inline");
00150       Append_Token_Special(tokens, '(');
00151       ST2F_use_translate(tokens, func_st);
00152       Append_Token_Special(tokens, ')');
00153    }
00154    else if (WN_Call_Dont_Inline(call_wn))
00155    {
00156       Append_F77_Directive_Newline(tokens, "C*$*");
00157       Append_Token_String(tokens, "noinline");
00158       Append_Token_Special(tokens, '(');
00159       ST2F_use_translate(tokens, func_st);
00160       Append_Token_Special(tokens, ')');
00161    }
00162 } /* WN2F_Callsite_Directives */
00163 
00164 
00165 static void
00166 WN2F_Function_Call_Lhs(TOKEN_BUFFER rhs_tokens,  /* The function call */
00167                        TY_IDX       return_ty,   /* The function return type */
00168                        WN2F_CONTEXT context)
00169 {
00170    /* PRECONDITION: return_ty != Void_Type and the function does not 
00171     * return its value to an address given as an implicit argument.
00172     *
00173     * Prepend to the rhs_tokens the assignments necessary to store
00174     * the function-call return value into a variable or registers.
00175     * If the return-value is not used anywhere, then assign it to
00176     * a (dummy) temporary variable.
00177     */
00178    TOKEN_BUFFER lhs_tokens = New_Token_Buffer();
00179    BOOL         return_value_is_used = TRUE;
00180    UINT         tmpvar_idx;
00181 
00182    /* Information pertaining to the return registers used for this
00183     * return type.
00184     */
00185    const RETURN_PREG return_info = PUinfo_Get_ReturnPreg(return_ty);
00186    const MTYPE       preg_mtype = RETURN_PREG_mtype(&return_info, 0);
00187    TY_IDX const      preg_ty  = Stab_Mtype_To_Ty(preg_mtype);
00188    const PREG_IDX    preg_num = RETURN_PREG_offset(&return_info, 0);
00189    const INT         num_pregs = RETURN_PREG_num_pregs(&return_info);
00190       
00191    /* Information pertaining to what location (other than return regs)
00192     * the return value should eventually be stored into, as was 
00193     * determined in the PUinfo.c analysis.
00194     */
00195    ST          *result_var   = (ST *)CALLSITE_return_var(WN2F_Prev_CallSite);
00196    const WN    *result_store = CALLSITE_store1(WN2F_Prev_CallSite);
00197    STAB_OFFSET  var_offset   = CALLSITE_var_offset(WN2F_Prev_CallSite);
00198    BOOL         need_result_in_regs = CALLSITE_in_regs(WN2F_Prev_CallSite);
00199 
00200             need_result_in_regs = FALSE;
00201       
00202    if (preg_mtype == MTYPE_V)
00203    {
00204       /* Does this ever occur without a VCALL? */
00205       return_value_is_used = FALSE;
00206    }
00207    else if (result_var != NULL )  
00208    {
00209       /* Should not have unexpected uses of return registers */
00210       ASSERT_WARN(!need_result_in_regs,
00211                   (DIAG_W2F_UNEXPEXTED_RETURNREG_USE, 
00212                    "WN2F_Function_Call_Lhs"));
00213          
00214       /* Assign the value directly to the variable/register, without
00215        * referencing the return registers.
00216        */
00217       if (ST_class(result_var) == CLASS_PREG)
00218          ST2F_Use_Preg(lhs_tokens, ST_type(result_var), var_offset);
00219 
00220       else if (TY_kind(ST_type(result_var)) == KIND_STRUCT)   /* avoid FLD selection of Offset_Symref */
00221          ST2F_use_translate(lhs_tokens,result_var);
00222 
00223       else
00224          WN2F_Offset_Symref(lhs_tokens,  
00225                             result_var, /* base variable */
00226                             Stab_Pointer_To(ST_type(result_var)), /* addr */
00227                             return_ty,  /* type of rhs */
00228                             var_offset, /* base offset */
00229                             context);
00230    }
00231    else if (result_store != NULL)
00232    {
00233       /* We have a store into an lvalue that is not a variable, so
00234        * it must be an OPR_ISTORE node with the rhs being an LDID
00235        * of the return register.  Do the exact same thing as would
00236        * be done in translating the ISTORE, but substitute the rhs
00237        * with the call expression.
00238        */
00239       ASSERT_DBG_FATAL(WN_operator(result_store) == OPR_ISTORE &&
00240                        WN_operator(WN_kid0(result_store)) == OPR_LDID, 
00241                        (DIAG_W2F_UNEXPECTED_OPC, "WN2F_Function_Call_Lhs()"));
00242 
00243       /* Should not have unexpected uses of return registers */
00244       ASSERT_WARN(!need_result_in_regs,
00245                   (DIAG_W2F_UNEXPEXTED_RETURNREG_USE,
00246                    "WN2F_Function_Call_Lhs"));
00247 
00248       /* Should have matching types in the assignment we are about
00249        * to generate.
00250        */
00251       ASSERT_WARN(WN2F_Can_Assign_Types(TY_pointed(WN_ty(result_store)),
00252                                         return_ty),
00253                   (DIAG_W2F_INCOMPATIBLE_TYS, "WN2F_Function_Call_Lhs"));
00254    
00255       fld_type_z = 0; 
00256       WN2F_Offset_Memref(lhs_tokens,
00257                          WN_kid1(result_store),          /* lhs of ISTORE */
00258                          WN_Tree_Type(WN_kid1(result_store)), /* base addr */
00259                          TY_pointed(WN_ty(result_store)),/* object to store */
00260                          WN_store_offset(result_store),  /* base offset */
00261                          context);
00262    } 
00263    else if (!need_result_in_regs)
00264    {
00265       /* The return registers are not referenced, so do not bother
00266        * assigning the return value to the return registers.
00267        */
00268       return_value_is_used = FALSE;
00269    }
00270    else if (num_pregs == 1 && TY_Is_Preg_Type(return_ty))
00271    {
00272       /* There is a single return register holding the return value,
00273        * so return the rhs into this register, after casting the rhs
00274        * to the appropriate type.  Note that preg_mtype and preg_num
00275        * holds the attributes of the single return register.
00276        */
00277       ASSERT_WARN(WN2F_Can_Assign_Types(preg_ty, return_ty),
00278                   (DIAG_W2F_INCOMPATIBLE_TYS, "WN2F_Function_Call_Lhs"));
00279       ST2F_Use_Preg(lhs_tokens, preg_ty, preg_num);
00280    }
00281    else /* Our most difficult case */
00282    {
00283      /* We need to store the call-result into a temporary variable,
00284       * then save the temporary variable into the return registers.
00285       */
00286 
00287      const UINT  tmp_idx = Stab_Lock_Tmpvar(return_ty, 
00288                                                 ST2F_Declare_Tempvar);
00289      const char *tmpvar_name = W2CF_Symtab_Nameof_Tempvar(tmp_idx);
00290          
00291      /* The lhs is simply the tmpvar */
00292      Append_Token_String(lhs_tokens, tmpvar_name);
00293 
00294      /* rhs to the lhs */
00295 
00296      WN2F_Stmt_Newline(rhs_tokens, (char*) NULL, (SRCPOS) NULL , context);
00297      WN2F_Load_Return_Reg(rhs_tokens,
00298                           return_ty, /* Type of tmpvar_name */
00299                           tmpvar_name,
00300                           0,
00301                           preg_mtype,
00302                           preg_num,
00303                           context);
00304 
00305      if (num_pregs > 1)
00306      {
00307          /* Get the offset into the value from which the second preg
00308           * needs to be loaded.
00309              */
00310          STAB_OFFSET value_offset = TY_size(Stab_Mtype_To_Ty(preg_mtype));
00311 
00312          /* Load the second register */
00313          WN2F_Stmt_Newline(rhs_tokens, (char*) NULL, (SRCPOS) NULL , context);
00314          const PREG_IDX preg_num2 = RETURN_PREG_offset(&return_info, 1);
00315          const MTYPE preg_mtype2  = RETURN_PREG_mtype(&return_info, 1);
00316 
00317          WN2F_Load_Return_Reg(rhs_tokens,
00318                               return_ty,   /* Type of tmpvar_name */
00319                               tmpvar_name, 
00320                               value_offset, /* Offset in tmpvar_name */
00321                               preg_mtype2, 
00322                               preg_num2, 
00323                               context);
00324      } /* if save call-value into both return pregs */
00325 
00326      Stab_Unlock_Tmpvar(tmp_idx);
00327 
00328    } /* if (various return cases) */ 
00329 
00330    /* If the return value is not referenced, we need to create a (dummy)
00331     * temporary variable to generate valid Fortran code.
00332     */
00333    if (!return_value_is_used)
00334    {
00335      tmpvar_idx = Stab_Lock_Tmpvar(return_ty, &ST2F_Declare_Tempvar);
00336      Append_Token_String(lhs_tokens, W2CF_Symtab_Nameof_Tempvar(tmpvar_idx));
00337      Stab_Unlock_Tmpvar(tmpvar_idx);
00338    }
00339        
00340    Prepend_Token_Special(rhs_tokens, '=');
00341    Prepend_And_Reclaim_Token_List(rhs_tokens, &lhs_tokens);
00342 
00343 } /* WN2F_Function_Call_Lhs */
00344 
00345 
00346 /*----------------------- do_loop translation -------------------------*/
00347 /*---------------------------------------------------------------------*/
00348 
00349 /* The maximum number of (partial) operations available to manipulate
00350  * a do-loop termination-test expression.
00351  */
00352 #define MAX_TEST_OPERATIONS 16
00353 
00354 
00355 typedef struct Partial_Op
00356 {
00357    OPERATOR  opr;          /* Operation "opnd0 opr opnd1" or "opr(opnd0)" */
00358    INTRINSIC intr;         /* Operation "opnd0 opr opnd1" or "opr(opnd0)" */
00359    WN       *opnd1;        /* Second operand (opnd1), if applicable */
00360    BOOL      switch_opnds; /* Switch opnds for binary opr: "opnd1 opr opnd0" */
00361 } PARTIAL_OP;
00362 
00363 
00364 /* Data-structure representing operations (PARTIAL_OP) to be carried
00365  * out on both sides of a do-loop termination-test expression, such 
00366  * that the side referring to the index-variable is simplified to a
00367  * simple LDID of the index-variable, and the other side 
00368  * (DO_LOOP_BOUND.opnd0) is transformed to a suitable bound for a
00369  * Fortran DO loop.  The bound expression will be expressed as:
00370  *
00371  *   (op[n].opnd1 op[n].opr (....(op[0].opnd1 op[0].opr opnd0)))
00372  *
00373  * after which the original loop termination test has been transformed
00374  * into:
00375  *
00376  *      (idx_var comparison_opr bound)
00377  */
00378 typedef struct Do_Loop_Bound
00379 {
00380    OPERATOR   comparison_opr; /* Resultant comparison operator */
00381    WN        *opnd0;          /* Last operand in sequence of ops */
00382    INT        const0;         /* Constant to be added to opnd0 */
00383    UINT       num_ops;        /* Number of ops to be applied to opnd0 */
00384    PARTIAL_OP *op;            /* Sequence of ops to be applied to opnd0 */
00385 } DO_LOOP_BOUND;
00386 
00387 
00388 /* Conceptually, we may have to reverse the loop-termination comparison
00389  * to account for a negative multiplicative operand when reducing one
00390  * side of the comparison to an LDID of the index-variable.
00391  */
00392 #define WN2F_Reverse_Bounds_Comparison(comparison_opr) \
00393    (comparison_opr == OPR_GE? OPR_LE : \
00394     comparison_opr == OPR_LE? OPR_GE : \
00395     comparison_opr == OPR_GT? OPR_LT : \
00396     OPR_GT)
00397 
00398 
00399 static INTRINSIC 
00400 WN2F_Get_Divfloor_Intr(MTYPE mtype)
00401 {
00402    INTRINSIC intr;
00403    switch (mtype)
00404    {
00405    case MTYPE_I4:
00406       intr = INTRN_I4DIVFLOOR;
00407       break;
00408    case MTYPE_U4:
00409       intr = INTRN_U4DIVFLOOR;
00410       break;
00411    case MTYPE_I8:
00412       intr = INTRN_I8DIVFLOOR;
00413       break;
00414    case MTYPE_U8:
00415       intr = INTRN_U8DIVFLOOR;
00416       break;
00417    default:
00418       intr = INTRINSIC_NONE;
00419       break;
00420    }
00421    return intr;
00422 } /* WN2F_Get_Divfloor_Intr */
00423 
00424 
00425 static INTRINSIC 
00426 WN2F_Get_Divceil_Intr(MTYPE mtype)
00427 {
00428    INTRINSIC intr;
00429    switch (mtype)
00430    {
00431    case MTYPE_I4:
00432       intr = INTRN_I4DIVCEIL;
00433       break;
00434    case MTYPE_U4:
00435       intr = INTRN_U4DIVCEIL;
00436       break;
00437    case MTYPE_I8:
00438       intr = INTRN_I8DIVCEIL;
00439       break;
00440    case MTYPE_U8:
00441       intr = INTRN_U8DIVCEIL;
00442       break;
00443    default:
00444       intr = INTRINSIC_NONE;
00445       break;
00446    }
00447    return intr;
00448 } /* WN2F_Get_Divceil_Intr */
00449 
00450 
00451 static WN *
00452 WN2F_Get_DoLoop_StepSize(WN *step, ST *idx_var, STAB_OFFSET idx_ofst)
00453 {
00454    /* We require this to be an STID, but only warn about the cases
00455     * when we do not have an ADD with one operand being an LDID
00456     * of the idx_var.  Return the step-size, if the induction step
00457     * matches our pattern: (STID idx (ADD (LDID idx) stepsize));
00458     * otherwise return NULL.
00459     */
00460    WN *add;
00461    WN *step_size = NULL;
00462    
00463    ASSERT_DBG_FATAL(WN_operator(step) == OPR_STID && 
00464                     WN_st(step) == idx_var && WN_offset(step) == idx_ofst,
00465                     (DIAG_W2F_UNEXPECTED_OPC, "WN_Get_DoLoop_StepSize"));
00466 
00467    if (WN_operator(WN_kid0(step)) == OPR_ADD)
00468    {
00469       add = WN_kid0(step);
00470       if (WN_operator(WN_kid0(add)) == OPR_LDID &&
00471           WN_st(WN_kid0(add)) == idx_var)
00472       {
00473          step_size = WN_kid1(add);
00474       }
00475       else if (WN_operator(WN_kid1(add)) == OPR_LDID &&
00476                WN_st(WN_kid1(add)) == idx_var)
00477       {
00478          step_size = WN_kid0(add);
00479       }
00480       else
00481          ASSERT_DBG_WARN(FALSE,
00482                          (DIAG_W2F_UNEXPECTED_OPC, "WN_Get_DoLoop_StepSize"));
00483    }
00484    else
00485       ASSERT_DBG_WARN(FALSE,
00486                       (DIAG_W2F_UNEXPECTED_OPC, "WN_Get_DoLoop_StepSize"));
00487 
00488    return step_size;
00489 } /* WN2F_Get_DoLoop_StepSize */
00490 
00491 
00492 static UINT
00493 WN2F_LoopBound_VarRef(WN         *wn,          /* in parameter */
00494                       ST         *st,          /* in parameter */
00495                       STAB_OFFSET st_ofst,     /* in parameter */
00496                       INT        *ldid_in_kid, /* out parameter */
00497                       UINT        level)       /* in parameter */
00498 {
00499    /* Returns the number of references to the given ST within
00500     * the given WN.  Returns a large number (0xfffffff0) to indicate
00501     * an unkown number of references.  If there is exactly one such
00502     * reference, and it is an LDID, then we also return a valid path
00503     * through the given wn subtree (as a child-number sequence) in
00504     * "ldid_in_kid"; The end-of-path indicator is a child number of
00505     * "-1".
00506     *
00507     * Note that we also restrict the form of the path to only handle
00508     * a predetermined set of operations (NEG, ADD, SUB, MPY, DIV),
00509     * and when other operations are encountered then the ldid_in_kid
00510     * sequence will be prematurely terminated (-1).  Similarly,
00511     * the path cannot be longer than (MAX_TEST_OPERATIONS - level), 
00512     * where "level" is "0" (zero) for the outermost loop-bound
00513     * comparison expression, and represents the depth of the path
00514     * down to the level of the wn passed into this routine path.  When
00515     * the depth-level exceeds the limit, the top element of the 
00516     * ldid_in_kid sequence will become -1, and an unknown number of 
00517     * references (0xfffffff0) will be assumed.
00518     *
00519     * Hence, the number of references returned is correct when smaller
00520     * than 0xfffffff0.  The path is correct when it leads to an LDID
00521     * of the given ST before containing a -1 value.  The last element
00522     * on the ldid_in_kid path will always be set to -1.
00523     */
00524    UINT counter;
00525    
00526    if (level >= MAX_TEST_OPERATIONS)
00527    {
00528       /* Path overflowed, so give up and assume unknown number of 
00529        * references.  No element available in the ldid_in_kid sequence.
00530        */
00531       counter = 0xfffffff0;
00532    }
00533    else
00534    {
00535       *ldid_in_kid = -1; /* Reset this to the appropriate kid once known */
00536 
00537       if (WN_operator(wn) == OPR_LDID && 
00538           WN_st(wn) == st && WN_offset(wn) == st_ofst)
00539       {
00540          /* Found an LDID reference to the given st.  Terminate
00541           * the ldid_in_kid sequence with a -1 value.
00542           */
00543          counter = 1;
00544       }
00545       else switch (WN_operator(wn))
00546       {
00547       case OPR_NEG:
00548          counter = WN2F_LoopBound_VarRef(WN_kid0(wn), 
00549                                          st, 
00550                                          st_ofst, 
00551                                          ldid_in_kid+1, 
00552                                          level++);
00553          if (counter == 1)
00554             *ldid_in_kid = 0;  /* A single reference found in kid0 */
00555          break;
00556 
00557       case OPR_ADD:
00558       case OPR_SUB:
00559       case OPR_MPY:
00560       case OPR_DIV:
00561          counter = WN2F_LoopBound_VarRef(WN_kid0(wn),
00562                                          st, 
00563                                          st_ofst, 
00564                                          ldid_in_kid+1,
00565                                          level++);
00566          if (counter == 1)
00567          {
00568             counter += WN_num_var_refs(WN_kid1(wn), st, st_ofst);
00569             if (counter == 1)
00570                *ldid_in_kid = 0;  /* A single reference found in kid0 */
00571          }
00572          else if (counter == 0)
00573          {
00574             counter = WN2F_LoopBound_VarRef(WN_kid1(wn), 
00575                                             st, 
00576                                             st_ofst, 
00577                                             ldid_in_kid+1, 
00578                                             level++);
00579             if (counter == 1)
00580                *ldid_in_kid = 1;  /* A single reference found in kid1 */
00581          }
00582          else /* zero, more than one, or unknown number of references */
00583          {
00584             counter += WN_num_var_refs(WN_kid1(wn), st, st_ofst);
00585          }
00586          break;
00587       
00588       default:
00589          /* Encountered unexpected form of expression along this path */
00590          counter = WN_num_var_refs(wn, st, st_ofst);
00591          break;
00592       } /*switch*/
00593    }
00594 
00595    return counter;
00596 } /* WN2F_LoopBound_VarRef */
00597 
00598 
00599 static void
00600 WN2F_Get_Next_LoopBoundOp(PARTIAL_OP *op,       /* out */
00601                           OPERATOR   *comp_opr, /* in/out */
00602                           BOOL       *ok,       /* out */
00603                           WN         *wn,       /* in */
00604                           INT         idx_kid)  /* in */
00605 {
00606    /* Given an expression (wn) occurring on the lhs of a comparison
00607     * operator (comp_opr), determine and record the operation (op)
00608     * which will undo the effect of the expression with respect to
00609     * the subexpression representing the index-expression (idx_kid).
00610     *
00611     * The end-result should be that: op(wn) == WN_kid(wn, idx_kid).
00612     */
00613    ASSERT_DBG_WARN(*comp_opr == OPR_LE || *comp_opr == OPR_GE,
00614                    (DIAG_W2F_UNEXPECTED_OPC, "WN_Get_DoLoop_Bound"));
00615 
00616    if (idx_kid < 0)
00617    {
00618       /* Invalid path element */
00619       *ok = FALSE;
00620    }
00621    else
00622    {
00623       *ok = TRUE; /* until proven otherwise */
00624       switch (WN_operator(wn))
00625       {
00626       case OPR_NEG:
00627          /* -idx <= e0  -->  idx >= -e0 */
00628          /* -idx <  e0  -->  idx >  -e0 */
00629          op->intr = INTRINSIC_NONE;
00630          op->opr = OPR_NEG;
00631          op->opnd1 = NULL;
00632          op->switch_opnds = FALSE;
00633          *comp_opr = WN2F_Reverse_Bounds_Comparison(*comp_opr);
00634          break;
00635 
00636       case OPR_ADD:
00637          /* idx+e1 <= e0  -->  idx <= e0-e1 */
00638          op->intr = INTRINSIC_NONE;
00639          op->opr = OPR_SUB;
00640          op->opnd1 = WN_kid(wn, (idx_kid == 0)? 1 : 0);
00641          op->switch_opnds = FALSE;
00642          break;
00643 
00644       case OPR_SUB:
00645          op->intr = INTRINSIC_NONE;
00646          if (idx_kid == 0)
00647          {
00648             /* idx-e1 <= e0  -->  idx <= e0+e1 */
00649             op->opr = OPR_ADD;
00650             op->opnd1 = WN_kid1(wn);
00651             op->switch_opnds = FALSE;
00652          }
00653          else /* (idx_kid == 1) */
00654          {
00655             /* e1-idx <= e0  -->  idx >= e1-e0 */
00656             op->opr = OPR_SUB;
00657             op->opnd1 = WN_kid0(wn);
00658             op->switch_opnds = TRUE;
00659             *comp_opr = WN2F_Reverse_Bounds_Comparison(*comp_opr);
00660          }
00661          break;
00662 
00663       case OPR_MPY:
00664          /* While a regular division may be used in real arithmetics,
00665           * we operate with integral numbers and we must round to
00666           * the closest number that still makes the inequality hold.
00667           *
00668           * Since the lhs will always be an integer, a "<=" operator
00669           * which holds for a real rhs will also hold for the rhs
00670           * rounded down (DIVFLOOR).  Similarly, for a ">=" operator
00671           * the inequality will always hold for a rhs rounded up (DIVCEIL).
00672           *
00673           * Hence we get:
00674           *
00675           *    idx*e1 <= e0  ---(e1>=0)--->  idx <= DIVFLOOR(e0, e1)
00676           *    idx*e1 <= e0  ---(e1< 0)--->  idx >= DIVCEIL(e0, e1)
00677           *    idx*e1 >= e0  ---(e1>=0)--->  idx >= DIVCEIL(e0, e1)
00678           *    idx*e1 >= e0  ---(e1< 0)--->  idx <= DIVFLOOR(e0, e1)
00679           */
00680          op->opnd1 = WN_kid(wn, (idx_kid == 0)? 1 : 0);
00681          op->switch_opnds = FALSE;
00682          if (WN_operator(op->opnd1) != OPR_INTCONST ||
00683              WN_const_val(op->opnd1) == 0)
00684          {
00685             *ok = FALSE;
00686          }
00687          else
00688          {
00689             /* Update the inequality operator to what it should be after
00690              * the transformation.
00691              */
00692             if (WN_const_val(op->opnd1) < 0)
00693                *comp_opr = WN2F_Reverse_Bounds_Comparison(*comp_opr);
00694 
00695             /* Get the operator kind
00696              */
00697             op->opr = OPR_INTRINSIC_OP;
00698             op->intr = INTRINSIC_NONE;
00699             if (*comp_opr == OPR_LE)
00700                op->intr = WN2F_Get_Divfloor_Intr(WN_opc_rtype(wn));
00701             else  /* (*comp_opr == OPR_GE) */
00702                op->intr = WN2F_Get_Divceil_Intr(WN_opc_rtype(wn));
00703          }
00704          break;
00705 
00706       case OPR_DIV:
00707          if (idx_kid == 0)
00708          {
00709             /* idx/e1 <= e0  -->  idx <= e0*e1 WHERE e1 >= 0 */
00710             op->opr = OPR_MPY;
00711             op->opnd1 = WN_kid1(wn);
00712             op->switch_opnds = FALSE;
00713          }
00714          else /* (idx_kid == 1) */
00715          {
00716             /* e1/idx <= e0  -->  idx <= e1/e0 WHERE e1 >= 0 */
00717             op->opr = OPR_DIV;
00718             op->opnd1 = WN_kid0(wn);
00719             op->switch_opnds = TRUE;
00720          }
00721          if (WN_operator(op->opnd1) != OPR_INTCONST ||
00722              WN_const_val(op->opnd1) == 0)
00723          {
00724             *ok = FALSE;
00725          }
00726          else if (WN_const_val(op->opnd1) < 0)
00727          {
00728             /* idx/e1 <= e0  -->  idx >= e0*e1 WHERE e1 < 0 */
00729             *comp_opr = WN2F_Reverse_Bounds_Comparison(*comp_opr);
00730          }
00731          break;
00732 
00733       default:
00734          *ok = FALSE;
00735          break;
00736       }
00737    } /* if (idx_kid >= 0) */
00738 } /* WN2F_Get_Next_LoopBoundOp */
00739 
00740 
00741 static DO_LOOP_BOUND *
00742 WN2F_Get_DoLoop_Bound(WN         *end_test, 
00743                       ST         *idx_var,
00744                       STAB_OFFSET idx_ofst, 
00745                       WN         *step_size)
00746 {
00747    /* We expect a non-NULL step_size expression and try to transform
00748     * the loop-termination test (end_test) into a form with an LDID
00749     * of the index (idx_var) on the lhs of the test, the rhs of
00750     * correspondingly transformed by means of a DO_LOOP_BOUND.
00751     *
00752     * If the loop-termination test with the LDID as the lhs is
00753     * of a form which permits the rhs (DO_LOOP_BOUND) to be used
00754     * as a bound in a Fortran do-loop, then return a ptr to the
00755     * DO_LOOP_BOUND; otherwise we return a NULL ptr.
00756     */
00757    static PARTIAL_OP    partial_op[MAX_TEST_OPERATIONS];
00758 
00759    static DO_LOOP_BOUND bound = {(OPERATOR) 0,    /*comparison_opr: set every call*/
00760                                  NULL, /*opnd0:          set every call*/
00761                                  0,    /*const0:         set every call*/
00762                                  0,    /*num_ops:        set every call*/ 
00763                                  partial_op}; /*op: set here, once only */
00764 
00765    DO_LOOP_BOUND *boundp = NULL;
00766    OPERATOR       comparison_opr = WN_operator(end_test);
00767    INT            path_to_idx0[MAX_TEST_OPERATIONS];
00768    INT            path_to_idx1[MAX_TEST_OPERATIONS];
00769    INT           *path_to_idx; /* Pointer to path_to_idx0 or path_to_idx1 */
00770    INT            path_level;  /* Index into path_to_idx sequence */
00771    INT            idx_refs0;   /* Number of references to "idx_var" in kid0 */
00772    INT            idx_refs1;   /* Number of references to "idx_var" in kid1 */
00773    WN            *idx_expr;    /* Kid of "end_test" referring to "idx_var" */
00774    BOOL           bound_ok;    /* Bounds calculation thus far is fine? */
00775    
00776    if (step_size == NULL)
00777    {
00778      /* We can only deal with well-formed step-sizes */
00779    }
00780    else if (comparison_opr == OPR_LE || 
00781             comparison_opr == OPR_GE ||
00782             comparison_opr == OPR_LT || 
00783             comparison_opr == OPR_GT ||
00784             comparison_opr == OPR_NE )
00785    {
00786       /* We only handle LE, GE, LT, and GT loop termination tests.
00787        * Find a path in end_test to an only LDID reference to the
00788        * idx_var, and check to make sure this is the only reference
00789        * to the idx_var in the end_test.
00790        */
00791       idx_refs0 = WN2F_LoopBound_VarRef(WN_kid0(end_test), 
00792                                         idx_var, 
00793                                         idx_ofst,
00794                                         path_to_idx0,
00795                                         1);
00796       if (idx_refs0 <= 1)
00797       {
00798          idx_refs1 = WN2F_LoopBound_VarRef(WN_kid1(end_test), 
00799                                            idx_var, 
00800                                            idx_ofst, 
00801                                            path_to_idx1,
00802                                            1);
00803 
00804          if ((idx_refs0 + idx_refs1) == 1)
00805          {
00806             /* Set bound.opnd0 to the base expression for loop bound
00807              * calculation, where idx_expr will be the other side of 
00808              * the "end_test" expression.  Convert the comparison_opr
00809              * such that "idx_expr opr bound.opnd0" is equivalent to
00810              * the original end_test.
00811              */
00812             if (idx_refs0 == 1)
00813             {
00814                /* Idx reference in the lhs of the end-test */
00815                bound.opnd0 = WN_kid1(end_test);
00816                idx_expr = WN_kid0(end_test);
00817                path_to_idx = path_to_idx0;
00818             }
00819             else /* (idx_refs1 == 1) */
00820             {
00821                /* Idx reference in the rhs of the end-test */
00822                bound.opnd0 = WN_kid0(end_test);
00823                idx_expr = WN_kid1(end_test);
00824                path_to_idx = path_to_idx1;
00825                comparison_opr = WN2F_Reverse_Bounds_Comparison(comparison_opr);
00826             }
00827 
00828             /* The comparison_opr has been converted such that the
00829              * bound expression can be viewed as having the idx on the
00830              * lhs.  Next, convert a '<' or '>' operator, with respect
00831              * to the idx_expr, into a '<=' or '>=' repectively.
00832              */
00833             if (comparison_opr == OPR_LT)
00834             {
00835                /* Convert "i<n" into "i<=(n-1)" */
00836                bound.const0 = -1;         
00837                comparison_opr = OPR_LE;
00838             }
00839             else if (comparison_opr == OPR_GT)
00840             {
00841                /* Convert "i>n" into "i>=(n+1)" */
00842                bound.const0 = 1;         
00843                comparison_opr = OPR_GE;
00844             }
00845             else
00846                bound.const0 = 0;
00847 
00848             /* Traverse the idx_expr, collecting the sequence of operations
00849              * necessary to reduce it to an LDID of the the idx_var.
00850              */
00851             for (bound_ok = TRUE, path_level = 0; 
00852                  bound_ok && path_to_idx[path_level] >= 0;
00853                  path_level++)
00854             {
00855                WN2F_Get_Next_LoopBoundOp(&bound.op[path_level],
00856                                          &comparison_opr,
00857                                          &bound_ok,
00858                                          idx_expr, 
00859                                          path_to_idx[path_level]);
00860                idx_expr = WN_kid(idx_expr, path_to_idx[path_level]);
00861             }
00862             
00863             /* We can only generate a Fortran do-loop bound when the test
00864              * has been simplified to have an LDID of the index variable
00865              * as the lhs (idx_expr), and we have one of the following
00866              * two forms of loop (assuming the step-size is well-formed,
00867              * i.e. positive for the first case and negative for the second
00868              * case):
00869              *
00870              *    step_size >= 0:
00871              *    ---------------
00872              *        for (i=init; i<=bound; i+=step_size)
00873              *
00874              *    step_size <= 0:
00875              *    ---------------
00876              *        for (i=init; i>=bound; i+=step_size)
00877              */
00878             if (bound_ok &&
00879                 WN_operator(idx_expr) == OPR_LDID && 
00880                 WN_st(idx_expr) == idx_var            &&
00881                 WN_offset(idx_expr) == idx_ofst       &&
00882                 (WN_operator(step_size) != OPR_INTCONST ||
00883                  (WN_const_val(step_size) <= 0 && comparison_opr == OPR_GE) ||
00884                  (WN_const_val(step_size) >= 0 && comparison_opr == OPR_LE)))
00885             {
00886                /* All is well, so return the calculated bound! */
00887                boundp = &bound;
00888                bound.comparison_opr = comparison_opr;
00889                bound.num_ops = path_level;
00890             }
00891          } /* if exactly one ref to idx_var in lhs and rhs combined */
00892       } /* if no more than one lhs ref to idx_var */
00893    } /* if LE/GE/LT/GE loop termination test */
00894    else
00895       ASSERT_DBG_WARN(FALSE, (DIAG_W2F_UNEXPECTED_OPC, "WN_Get_DoLoop_Bound"));
00896 
00897    return boundp;
00898 } /* WN2F_Get_DoLoop_Bound */
00899 
00900 
00901 static WN2F_STATUS
00902 WN2F_Translate_DoLoop_Bound(TOKEN_BUFFER   tokens,
00903                             DO_LOOP_BOUND *bound,
00904                             WN2F_CONTEXT   context)
00905 {
00906    /* Note: Michael Wolf has a similar routine */
00907    TOKEN_BUFFER bound_expr = New_Token_Buffer();
00908    TOKEN_BUFFER opnd1_expr;
00909    UINT         op_idx;
00910    BOOL         is_intrinsic;
00911    char        *intrname;
00912    char         opname;
00913    
00914    WN2F_translate(bound_expr, bound->opnd0, context);
00915    if (bound->const0 != 0)
00916    {
00917       Append_Token_Special(bound_expr, '+');
00918       if (bound->const0<0) {
00919         Append_Token_Special(bound_expr,'(');
00920         Append_Token_String(bound_expr, Number_as_String(bound->const0, "%lld"));
00921         Append_Token_Special(bound_expr,')');
00922         }
00923       else
00924         Append_Token_String(bound_expr, Number_as_String(bound->const0, "%lld"));
00925    }
00926    for (op_idx = 0; op_idx < bound->num_ops; op_idx++)
00927    {
00928       is_intrinsic = FALSE;
00929 
00930       /* Get the operator */
00931       switch (bound->op[op_idx].opr)
00932       {
00933       case OPR_NEG:
00934          opname = '-';
00935          break;
00936       case OPR_ADD:
00937          opname = '+';
00938          break;
00939       case OPR_SUB:
00940          opname = '-';
00941          break;
00942       case OPR_MPY:
00943          opname = '*';
00944          break;
00945       case OPR_DIV:
00946          opname = '/';
00947          break;
00948       case OPR_INTRINSIC_OP:
00949          is_intrinsic = TRUE;
00950          switch (bound->op[op_idx].intr)
00951          {
00952          case INTRN_I4DIVFLOOR:
00953             intrname = "INTRN_I4DIVFLOOR";
00954             break;
00955          case INTRN_I8DIVFLOOR:
00956             intrname = "INTRN_I8DIVFLOOR";
00957             break;
00958          case INTRN_U4DIVFLOOR:
00959             intrname = "INTRN_U4DIVFLOOR";
00960             break;
00961          case INTRN_U8DIVFLOOR:
00962             intrname = "INTRN_U8DIVFLOOR";
00963             break;
00964          case INTRN_I4DIVCEIL:
00965             intrname = "INTRN_I4DIVCEIL";
00966             break;
00967          case INTRN_I8DIVCEIL:
00968             intrname = "INTRN_I8DIVCEIL";
00969             break;
00970          case INTRN_U4DIVCEIL:
00971             intrname = "INTRN_U4DIVCEIL";
00972             break;
00973          case INTRN_U8DIVCEIL:
00974             intrname = "INTRN_U8DIVCEIL";
00975             break;
00976          default:
00977             ASSERT_FATAL(FALSE, (DIAG_W2F_UNEXPECTED_DOLOOP_BOUNDOP, 
00978                                  "WN2F_Translate_DoLoop_Bound",
00979                                  OPERATOR_name(bound->op[op_idx].opr)));
00980          }
00981          break;
00982       default:
00983          ASSERT_FATAL(FALSE, (DIAG_W2F_UNEXPECTED_DOLOOP_BOUNDOP, 
00984                               "WN2F_Translate_DoLoop_Bound",
00985                               OPERATOR_name(bound->op[op_idx].opr)));
00986          break;
00987       }
00988       
00989       if (!is_intrinsic && bound->op[op_idx].opnd1 == NULL)
00990       {
00991          WHIRL2F_Parenthesize(bound_expr);
00992          Prepend_Token_Special(bound_expr, opname); /* Unary operation */
00993       }
00994       else /* Binary operation (all intrinsics we deal with are binary) */
00995       {
00996          /* Translate the second operand */
00997          opnd1_expr = New_Token_Buffer();
00998          (void)WN2F_translate(opnd1_expr, bound->op[op_idx].opnd1, context);
00999 
01000          /* Apply the second operand to the first one */
01001          if (is_intrinsic)
01002          {
01003             if (bound->op[op_idx].switch_opnds)
01004             {
01005                Prepend_Token_Special(bound_expr, ',');
01006                Prepend_And_Reclaim_Token_List(bound_expr, &opnd1_expr);
01007             }
01008             else
01009             {
01010                Append_Token_Special(bound_expr, ',');
01011                Append_And_Reclaim_Token_List(bound_expr, &opnd1_expr);
01012             }
01013             Prepend_Token_Special(bound_expr, '(');
01014             Append_Token_Special(bound_expr, ')');
01015             Prepend_Token_String(bound_expr, intrname);
01016          }
01017          else
01018          {
01019             WHIRL2F_Parenthesize(bound_expr);
01020             WHIRL2F_Parenthesize(opnd1_expr);
01021             if (bound->op[op_idx].switch_opnds)
01022             {
01023                Prepend_Token_Special(bound_expr, opname);
01024                Prepend_And_Reclaim_Token_List(bound_expr, &opnd1_expr);
01025             }
01026             else
01027             {
01028                Append_Token_Special(bound_expr, opname);
01029                Append_And_Reclaim_Token_List(bound_expr, &opnd1_expr);
01030             }
01031          }
01032       } /* if */
01033    } /* for */
01034 
01035    Append_And_Reclaim_Token_List(tokens, &bound_expr);
01036    return EMPTY_WN2F_STATUS;
01037 } /* WN2F_Translate_DoLoop_Bound */
01038 
01039 
01040 /*--------------------- prompf processing utilities -------------------*/
01041 /*---------------------------------------------------------------------*/
01042 
01043 static BOOL
01044 WN2F_Is_Loop_Region(const WN *region, WN2F_CONTEXT context)
01045 {
01046    /* Return TRUE if the given region is either a DOACROSS,
01047     * PARALLEL_DO, or a PDO region; otherwise, return FALSE.
01048     */
01049    BOOL predicate = (WN_operator(region) == OPR_REGION);
01050 
01051    if (predicate)
01052    {
01053       WN *pragma = WN_first(WN_region_pragmas(region));
01054 
01055       predicate = (pragma != NULL &&
01056                    (WN_pragma(pragma) == WN_PRAGMA_DOACROSS    ||
01057                     WN_pragma(pragma) == WN_PRAGMA_PARALLEL_DO ||
01058                     WN_pragma(pragma) == WN_PRAGMA_PDO_BEGIN) &&
01059                    WN_pragma_nest(pragma) <= 0 &&
01060                    !Ignore_Synchronized_Construct(pragma, context));
01061    }
01062    return predicate;
01063 } /* WN2F_Is_Loop_Region */
01064 
01065 
01066 /*
01067  *  See if this is a region construct. ie: a pragma in the list
01068  *  below. The end of the region is the implicit end of the construct.
01069 */
01070 
01071 static BOOL
01072 WN2F_Is_Parallel_Region(WN *region, WN2F_CONTEXT context)
01073 {
01074    BOOL predicate = (region != NULL && WN_operator(region) == OPR_REGION);
01075 
01076    if (predicate)
01077      {
01078        WN *pragma = WN_first(WN_region_pragmas(region));
01079 
01080        predicate = (pragma != NULL) &&
01081          (WN_pragma(pragma) == WN_PRAGMA_PARALLEL_BEGIN || 
01082           WN_pragma(pragma) == WN_PRAGMA_MASTER_BEGIN || 
01083           WN_pragma(pragma) == WN_PRAGMA_SINGLE_PROCESS_BEGIN ||
01084           WN_pragma(pragma) == WN_PRAGMA_PSECTION_BEGIN ||
01085           WN_pragma(pragma) == WN_PRAGMA_PARALLEL_SECTIONS ||
01086           WN_pragma(pragma) == WN_PRAGMA_PARALLEL_WORKSHARE) &&
01087             !Ignore_Synchronized_Construct(pragma, context);
01088  }
01089    return predicate;
01090 
01091 } /* WN2F_Is_Parallel_Region */
01092 
01093 
01094 static void
01095 WN2F_Prompf_Construct_Start(TOKEN_BUFFER tokens, WN *construct)
01096 {
01097    INT32 construct_id = WN_MAP32_Get(*W2F_Construct_Map, construct);
01098 
01099    if (construct_id != 0)
01100    {
01101       Append_F77_Directive_Newline(tokens,sgi_comment_str);
01102       Append_Token_String(tokens, "start");
01103       Append_Token_String(tokens, Number_as_String(construct_id, "%llu"));
01104    }
01105 } /* WN2F_Prompf_Construct_Start */
01106 
01107 
01108 static void
01109 WN2F_Prompf_Construct_End(TOKEN_BUFFER tokens, WN *construct)
01110 {
01111    INT32 construct_id = WN_MAP32_Get(*W2F_Construct_Map, construct);
01112 
01113    if (construct_id != 0)
01114    {
01115       Append_F77_Directive_Newline(tokens, sgi_comment_str);
01116       Append_Token_String(tokens, "end");
01117       Append_Token_String(tokens, Number_as_String(construct_id, "%llu"));
01118    }
01119 } /* WN2F_Prompf_Construct_End */
01120 
01121 
01122 static void
01123 WN2F_Start_Prompf_Transformed_Loop(TOKEN_BUFFER tokens, 
01124                                    WN          *loop, 
01125                                    WN2F_CONTEXT context)
01126 {
01127    /* We if this is a DOACROSS, PDO or PARALLEL DO loop, then it will
01128     * already have been handled by the surrounding region, so we need
01129     * not emit anything here.  Otherwise, emit the prompf flags.
01130     */
01131    if (!WN2F_Is_Loop_Region(W2CF_Get_Parent(W2CF_Get_Parent(loop)), context))
01132       WN2F_Prompf_Construct_Start(tokens, loop);
01133 } /* WN2F_Start_Prompf_Transformed_Loop */
01134 
01135 
01136 static void
01137 WN2F_End_Prompf_Transformed_Loop(TOKEN_BUFFER tokens, 
01138                                  WN          *loop, 
01139                                  WN2F_CONTEXT context)
01140 {
01141    /* We if this is a DOACROSS, PDO or PARALLEL DO loop, then it will
01142     * already have been handled by the surrounding region, so we need
01143     * not emit anything here.  Otherwise, emit the prompf flags.
01144     */
01145    if (!WN2F_Is_Loop_Region(W2CF_Get_Parent(W2CF_Get_Parent(loop)), context))
01146       WN2F_Prompf_Construct_End(tokens, loop);
01147 } /* WN2F_End_Prompf_Transformed_Loop */
01148 
01149 
01150 static void
01151 WN2F_Start_Prompf_Transformed_Region(TOKEN_BUFFER tokens,
01152                                      WN          *region, 
01153                                      WN2F_CONTEXT context)
01154 {
01155    /* Handle a PARALLEL, PSECTION, SINGLE MASTER region, 
01156     * or a DOACROSS, PDO or PARALLEL DO loop enclosed in a region.
01157     * ie: print - "start" <n> 
01158     */
01159 
01160    if (WN2F_Is_Loop_Region(region, context) || 
01161        WN2F_Is_Parallel_Region(region, context))
01162       WN2F_Prompf_Construct_Start(tokens, region);
01163 
01164 } /* WN2F_Begin_Prompf_Transformed_Region */
01165 
01166 
01167 static void
01168 WN2F_End_Prompf_Transformed_Region(TOKEN_BUFFER tokens,
01169                                    WN          *region, 
01170                                    WN2F_CONTEXT context)
01171 {
01172    /* Finish up  a PARALLEL, PSECTION, SINGLE MASTER region, 
01173     * or a DOACROSS, PDO or PARALLEL DO loop enclosed in a region.
01174     * ie: print - "end" <n> 
01175     */
01176 
01177    if (WN2F_Is_Loop_Region(region, context) || 
01178        WN2F_Is_Parallel_Region(region, context))
01179       WN2F_Prompf_Construct_End(tokens, region);
01180 
01181 } /* WN2F_End_Prompf_Transformed_Region */
01182 
01183 
01184 /*--------------------- block processing utilities --------------------*/
01185 /*---------------------------------------------------------------------*/
01186 
01187 
01188 static void
01189 WN2F_Append_Symtab_Consts(TOKEN_BUFFER tokens,
01190                           SYMTAB_IDX    symtab,
01191                           UINT         lines_between_decls)
01192 {
01193    /* When "tokens" is NULL, we write the consts directly to the
01194     * Whirl2f_file; otherwise, append them to the given token-list.
01195     */
01196 #if 0   
01197    /* Declare static variables for symbolic constants */
01198    FOR_ALL_CONSTANTS(st, const_idx)
01199    {
01200       /* TODO: Full support for sym_consts */
01201 
01202          if (tokens != NULL)
01203          {
01204             Append_F77_Indented_Newline(tokens, 
01205                                        lines_between_decls, NULL/*label*/);
01206             ST2F_decl_translate(tokens, st);
01207          }
01208          else
01209          {
01210             tmp_tokens = New_Token_Buffer();
01211             Append_F77_Indented_Newline(tmp_tokens, 
01212                                        lines_between_decls, NULL/*label*/);
01213             ST2F_decl_translate(tmp_tokens, st);
01214             Write_And_Reclaim_Tokens(W2F_File[W2F_FTN_FILE],
01215                                      W2F_File[W2F_LOC_FILE],
01216                                      &tmp_tokens);
01217          }
01218       }
01219    }
01220 #endif
01221 
01222 } /* WN2F_Append_Symtab_Consts */
01223 
01224 
01225 struct write_st {
01226 private:
01227   TOKEN_BUFFER tokens;
01228   UINT         lines_between_decls;
01229   SYMTAB_IDX   symtab; 
01230 public:
01231   write_st(TOKEN_BUFFER tb,UINT lbd,SYMTAB_IDX symtab) : tokens(tb), lines_between_decls(lbd),symtab(symtab) {}
01232 
01233 // A function object to declare an identifier from the ST 
01234 // table, provided it represents a function, or a variable
01235 // referenced. Common elements are excluded, but emitted
01236 // as part of TY2F_Declare_Common_Flds. Ditto Formals.
01237 // This is called from WN2F_Append_Symtab_Vars.
01238 
01239 
01240   void operator() (UINT32 idx , ST* st) const 
01241     { 
01242      int testb = !BE_ST_w2fc_referenced(st);
01243      int testb1 = !ST_has_nested_ref(st);
01244      int testb2 = !ST_is_in_module(st);
01245      ST *sts = Scope_tab[Current_scope].st;
01246      ST *stbase = ST_base(st);
01247 
01248      INITO_IDX inito;
01249      char *scope_name = ST_name(sts);
01250      int  lens = strlen(scope_name);
01251      char *stbasename = ST_name(stbase);
01252      BOOL nomodulevar;
01253      PU_IDX current_PU=ST_pu(Scope_tab[Current_scope].st);
01254 
01255 
01256      char *stname = ST_name(st);
01257 
01258 //      std::cout << "JU: dealing with " << stname << std::endl; 
01259 
01260      BOOL variabledefinemodule = !strcmp(stbasename,scope_name);
01261 
01262        nomodulevar = !ST_is_in_module(st)||strcmp(stbasename,scope_name);
01263 
01264     if (ST_is_deleted(st)) /*CFC works on AST coulde delete some STs*/
01265           return;
01266  
01267      if (ST_class(st)==CLASS_PARAMETER)
01268        {
01269          if (tokens != NULL)
01270             {
01271               Append_F77_Indented_Newline(tokens,
01272                                           lines_between_decls, NULL/*label*/);
01273               ST2F_decl_translate(tokens,  st);
01274             }
01275           else
01276             {
01277               TOKEN_BUFFER tmp_tokens;
01278 
01279               tmp_tokens = New_Token_Buffer();
01280               Append_F77_Indented_Newline(tmp_tokens,
01281                                           lines_between_decls, NULL/*label*/);
01282               ST2F_decl_translate(tmp_tokens, st);
01283               Write_And_Reclaim_Tokens(W2F_File[W2F_FTN_FILE],
01284                                        W2F_File[W2F_LOC_FILE],
01285                                        &tmp_tokens);
01286             }
01287          return;
01288        }
01289   
01290      if (ST_class(st)==CLASS_TYPE) {
01291         if (ST_pu(ST_base(st)) == current_PU)
01292             ST2F_decl_translate(tokens,  st);
01293         else   
01294             Set_TY_is_translated_to_c(ST_type(st)); 
01295         return;
01296       }
01297      
01298 //      std::cout << "JU: decide:" 
01299 //             << "\n\tBE_ST_w2fc_referenced(st)=" << BE_ST_w2fc_referenced(st)
01300 //             << "\n\tST_is_in_module(st)=" << ST_is_in_module(st)
01301 //             << "\n\tnomodulevar=" << nomodulevar
01302 //             << "\n\tstrcmp(ST_name(st)="<< ST_name(st) << ",stbasename=" << stbasename << ")=" << strcmp(ST_name(st),stbasename) << std::endl; 
01303      if (!BE_ST_w2fc_referenced(st) 
01304          &&
01305          !(BE_ST_w2fc_referenced(stbase) 
01306            &&
01307            ST_is_equivalenced(st)
01308            && 
01309            ST_is_temp_var(stbase))
01310          && 
01311          !ST_has_nested_ref(st)
01312          && 
01313          !ST_is_in_module(st)   
01314          && 
01315          ST_sclass(st)!= SCLASS_DGLOBAL
01316          && 
01317          ST_sclass(st)!= SCLASS_PSTATIC
01318          &&
01319          (nomodulevar 
01320           || 
01321           !strcmp(ST_name(st),stbasename))
01322          && 
01323          ST_sclass(st) != SCLASS_EXTERN ) { 
01324 //        std::cout << "JU: return" << std::endl;  
01325        return ;
01326      }
01327 
01328 //      std::cout << "JU: keepgoing" << std::endl;  
01329 
01330      if (ST_sclass(st) == SCLASS_EXTERN &&
01331          symtab ==  GLOBAL_SYMTAB)
01332          return;
01333 
01334      if (ST_sclass(st) == SCLASS_EXTERN &&
01335           !BE_ST_w2fc_referenced(stbase) &&
01336           !ST_is_in_module(st))
01337              return;
01338 
01339      if (ST_is_in_module(st) && 
01340           nomodulevar && 
01341           ST_sclass(st) != SCLASS_EXTERN &&
01342            !Stab_Is_Common_Block(stbase))
01343           return;
01344 
01345      if (ST_is_in_module(st) &&
01346          !variabledefinemodule &&
01347           ST_sclass(st) != SCLASS_EXTERN)
01348           return;
01349      
01350  /* don't redeclare recuresive function's type in this PU
01351   * (recursive function) */
01352       if (ST_sclass(st)==SCLASS_TEXT && variabledefinemodule) 
01353           return;  
01354 
01355 
01356       if (ST_is_external(st))
01357          return;
01358           
01359     
01360       if (ST_sym_class(st) ==CLASS_FUNC)
01361           if ( ST_export(st) == EXPORT_LOCAL_INTERNAL) 
01362           return;
01363 
01364       if (ST_sym_class(st) ==CLASS_FUNC)
01365           if (!(ST_sclass(st) == SCLASS_EXTERN))
01366           return; 
01367 
01368 
01369       BOOL dop ;
01370 
01371       dop = ST_sclass(st) != SCLASS_FORMAL &&   
01372             ST_sclass(st) != SCLASS_FORMAL_REF ;
01373 
01374       dop &= ((ST_sym_class(st) == CLASS_VAR  && !ST_is_namelist(st)) ||
01375               (ST_sym_class(st) == CLASS_FUNC)) ;
01376     
01377 
01378      if ((ST_sclass(stbase) == SCLASS_DGLOBAL) && 
01379           ST_is_initialized(st)               &&
01380           !Stab_No_Linkage(st)                &&
01381            (!TY_Is_Structured(ST_type(st))      ||
01382            Stab_Is_Equivalence_Block(st)))
01383        {
01384            inito = Find_INITO_For_Symbol(st);
01385       if (inito != (INITO_IDX) 0)
01386          INITO2F_translate(Data_Stmt_Tokens, inito);
01387        }
01388       else
01389       if (dop)
01390         {
01391           if (tokens != NULL)
01392             {
01393               Append_F77_Indented_Newline(tokens, 
01394                                           lines_between_decls, NULL/*label*/);
01395               ST2F_decl_translate(tokens,  st);
01396             }
01397           else
01398             {
01399               TOKEN_BUFFER tmp_tokens;
01400 
01401               tmp_tokens = New_Token_Buffer();
01402               Append_F77_Indented_Newline(tmp_tokens, 
01403                                           lines_between_decls, NULL/*label*/);
01404               ST2F_decl_translate(tmp_tokens, st);
01405               Write_And_Reclaim_Tokens(W2F_File[W2F_FTN_FILE],
01406                                        W2F_File[W2F_LOC_FILE],
01407                                        &tmp_tokens);
01408             }
01409         } 
01410     } 
01411 } ;
01412 
01413 struct set_derived_ty_based_on_st {
01414 private:
01415   PU_IDX current_PU;
01416 
01417 public:
01418   set_derived_ty_based_on_st(PU_IDX c_PU):current_PU(c_PU) {}
01419   void operator()(UINT32, ST* st) const {
01420     if ((ST_class(st)==CLASS_TYPE) &&  //derived type
01421         (ST_pu(ST_base(st)) == current_PU) ) {
01422          Reset_TY_is_translated_to_c(ST_type(st));
01423        }
01424 
01425     if ((ST_sclass(st) == SCLASS_COMMON) &&   //common block
01426          (ST_pu(ST_base(st)) == current_PU) ) {
01427            Reset_TY_is_translated_to_c(ST_type(st));
01428            //Set_BE_ST_w2fc_referenced(st);
01429        }
01430   }
01431     
01432 };
01433 
01434 static void
01435 WN2F_Append_Symtab_Vars(TOKEN_BUFFER tokens,
01436                         SYMTAB_IDX   symtab,
01437                         UINT         lines_between_decls)
01438 {
01439    /* Declare identifiers from the new symbol table, provided they
01440     * represent functions or variables that are either common or
01441     * that have been referenced/used.
01442     */
01443 
01444    For_all(St_Table,symtab,write_st(tokens,lines_between_decls,symtab));
01445 
01446 
01447 } /* WN2F_Append_Symtab_Vars */
01448 
01449 static void
01450 WN2F_Enter_PU_Block(void)
01451 {
01452    WN2F_Next_ReturnSite = PUinfo_Get_ReturnSites();
01453    WN2F_Prev_CallSite = NULL;
01454 
01455    Data_Stmt_Tokens = New_Token_Buffer();
01456 
01457 } /* WN2F_Enter_PU_Block */
01458 
01459 
01460 // Emit declarations for a PU, ie: constants, extern/common/local 
01461 // variables. The declarations are built in a temporary buffer,
01462 // decl_tokens, then merged with the token buffer passed in.
01463 
01464 static void
01465 WN2F_Exit_PU_Block(TOKEN_BUFFER tokens, TOKEN_BUFFER *stmts)
01466 {
01467   SYMTAB_IDX   symtab;
01468   TOKEN_BUFFER decl_tokens;
01469   PU &    pu         = Get_Current_PU();
01470   PU_IDX  current_PU =  ST_pu(Scope_tab[CURRENT_SYMTAB].st);
01471 
01472   /* 
01473    * set all derived type entries with 
01474    *   Set_TY_is_translated_to_c()
01475    * ---FMZ
01476    */
01477    for (TY_IDX ty = 1; ty < TY_Table_Size(); ty++) {
01478        if (TY_kind(ty<<8)==KIND_STRUCT) 
01479             Set_TY_is_translated_to_c(ty<<8);
01480        }
01481    /*
01482     * reset the derived type table entry "translated_to_c(f)" 
01483     * defined in "this" PU.
01484     * ---FMZ 
01485     */
01486   For_all(St_Table,GLOBAL_SYMTAB,set_derived_ty_based_on_st(current_PU));
01487 
01488   /* Declare constants */
01489   decl_tokens = New_Token_Buffer();
01490   WN2F_Append_Symtab_Consts(decl_tokens, CURRENT_SYMTAB, 1/*Newlines*/);
01491   if (!W2F_Purple_Emission && !Is_Empty_Token_Buffer(decl_tokens)) {
01492     WHIRL2F_Append_Comment(tokens, "**** Constants ****", 1, 1);
01493   Append_And_Reclaim_Token_List(tokens, &decl_tokens);
01494    }
01495 
01496   /* Declare variables and reset the "referenced" flag */
01497 
01498   decl_tokens = New_Token_Buffer();
01499   symtab = PU_lexical_level(pu);
01500 
01501   WN2F_Append_Symtab_Vars(decl_tokens, GLOBAL_SYMTAB, 1); 
01502 
01503    if (!W2F_Purple_Emission && !Is_Empty_Token_Buffer(decl_tokens)) 
01504         WHIRL2F_Append_Comment(tokens,
01505                   "**** Global Variables & Derived Type Definitions ****", 1, 1);
01506   Append_And_Reclaim_Token_List(tokens, &decl_tokens);
01507 
01508   if (!W2F_Purple_Emission && !Is_Empty_Token_Buffer(param_tokens)) {
01509       WHIRL2F_Append_Comment(tokens,
01510                            "**** Parameters and Result ****", 1, 1);
01511 
01512      Append_And_Reclaim_Token_List(tokens, &param_tokens); 
01513    }
01514 
01515   decl_tokens = New_Token_Buffer();
01516   WN2F_Append_Symtab_Vars(decl_tokens, symtab, 1/*Newlines*/);
01517   Stab_Reset_Referenced_Flag(symtab);
01518 
01519   Stab_Reset_Referenced_Flag(GLOBAL_SYMTAB);
01520 
01521   if (!W2F_Purple_Emission && !Is_Empty_Token_Buffer(decl_tokens)) 
01522      {
01523         WHIRL2F_Append_Comment(tokens, 
01524                            "**** Local Variables and Functions ****", 1, 1);
01525     Append_And_Reclaim_Token_List(tokens, &decl_tokens); 
01526      }
01527   /* Declare pseudo registers and other temporary variables after
01528    * regular variables, since the declaration of these may create
01529    * more temporary variables (e.g. to handle implied do-loops
01530    * in initializers).
01531    */
01532 
01533   if (!W2F_Purple_Emission && !Is_Empty_Token_Buffer(PUinfo_local_decls))
01534     WHIRL2F_Append_Comment(tokens, "**** Temporary Variables ****",1,1);
01535   Append_And_Reclaim_Token_List(tokens, &PUinfo_local_decls);
01536 
01537 
01538   /* Emit DATA statements; i.e. initializers */
01539 
01540   if (!W2F_Purple_Emission && !Is_Empty_Token_Buffer(Data_Stmt_Tokens))
01541     WHIRL2F_Append_Comment(tokens, 
01542                            "**** Initializers ****", 1, 1);
01543   Append_And_Reclaim_Token_List(tokens, &Data_Stmt_Tokens);
01544 
01545   if (!W2F_Purple_Emission && !Is_Empty_Token_Buffer(PUinfo_pragmas))
01546     WHIRL2F_Append_Comment(tokens, 
01547                            "**** Top Level Pragmas ****", 1, 1);
01548   Append_And_Reclaim_Token_List(tokens, &PUinfo_pragmas);
01549 
01550 
01551   /* If this is a purple code-extraction, insert a placeholder
01552    * for purple-specific initialization.
01553    */
01554 
01555   if (W2F_Purple_Emission)
01556     {
01557       /* <#PRP_XSYM:INIT_DECL name, id, sclass, export#>
01558         */
01559       Append_F77_Indented_Newline(tokens, 1, NULL/*label*/);
01560       Append_Token_String(tokens, "<#PRP_XSYM:INIT_DECL");
01561       WN2F_Append_Purple_Funcinfo(tokens);
01562       Append_Token_String(tokens, "#>");
01563     }
01564 
01565   /* Append the statements to the tokens */
01566 
01567   if (!W2F_Purple_Emission)
01568     WHIRL2F_Append_Comment(tokens, "**** Statements ****", 1, 1);
01569   Append_And_Reclaim_Token_List(tokens, stmts);
01570 
01571   if (W2F_Purple_Emission && 
01572       strcmp(W2F_Object_Name(PUINFO_FUNC_ST), WN2F_Purple_Region_Name) == 0)
01573     {
01574       /* <#PRP_XSYM:TEST name, id, sclass, export#>
01575         */
01576       Append_F77_Indented_Newline(tokens, 1, NULL/*label*/);
01577       Append_Token_String(tokens, "<#PRP_XSYM:TEST");
01578       WN2F_Append_Purple_Funcinfo(tokens);
01579       Append_Token_String(tokens, "#>");
01580     }
01581 
01582   WN2F_Next_ReturnSite = NULL;
01583   WN2F_Prev_CallSite = NULL;
01584 } /* WN2F_Exit_PU_Block */
01585 
01586 /*-------- The initializers and handlers statement translation --------*/
01587 /*---------------------------------------------------------------------*/
01588 
01589 void
01590 WN2F_Stmt_initialize(void)
01591 {
01592    /* Nothing to do at the moment */
01593 } /* WN2F_Stmt_initialize */
01594 
01595 
01596 void
01597 WN2F_Stmt_finalize(void)
01598 {
01599    /* Nothing to do at the moment */
01600 } /* WN2F_Stmt_finalize */
01601 
01602 
01603 BOOL 
01604 WN2F_Skip_Stmt(WN *stmt)
01605 {
01606    return ((W2F_No_Pragmas && \
01607             (WN_operator(stmt) == OPR_PRAGMA || 
01608              WN_operator(stmt) == OPR_XPRAGMA) &&
01609             WN_pragma(stmt) != WN_PRAGMA_PREAMBLE_END) || /* For purple */\
01610 
01611            WN2F_Skip_Pragma_Stmt(stmt) ||
01612 
01613            (!W2F_Emit_Prefetch &&
01614             (WN_operator(stmt) == OPR_PREFETCH ||
01615              WN_operator(stmt) == OPR_PREFETCHX)) ||
01616 
01617            (WN2F_Next_ReturnSite != NULL &&
01618             (stmt == RETURNSITE_store1(WN2F_Next_ReturnSite) ||
01619              stmt == RETURNSITE_store2(WN2F_Next_ReturnSite))) ||
01620 
01621            (WN2F_Prev_CallSite != NULL &&
01622             (stmt == CALLSITE_store1(WN2F_Prev_CallSite) ||
01623              stmt == CALLSITE_store2(WN2F_Prev_CallSite)))
01624            );
01625 } /* WN2F_Skip_Stmt */
01626 
01627 
01628 // find and emit any COMMONS that are initialized.
01629 // used by WN2F_Append_Block_Data below.
01630 
01631 struct WN2F_emit_commons{
01632 private:
01633    TOKEN_BUFFER  tokens;
01634 
01635 public:
01636    WN2F_emit_commons(TOKEN_BUFFER tb) : tokens(tb) {}
01637  
01638   void operator() (UINT32,  ST* st) const {
01639     if (ST_sclass(st) == SCLASS_DGLOBAL)
01640       if(ST_is_initialized(st))  {
01641         if (!Has_Base_Block(st) || 
01642             ST_class(ST_base_idx(st)) == CLASS_BLOCK) {
01643           ST2F_decl_translate(tokens,st);
01644         }
01645        }
01646   }
01647 };
01648 
01649 // Create a BLOCK DATA if any COMMONs in the global symbol
01650 // table are initialized. BLOCK DATA names are lost, but
01651 // that's ok - all (global) initializations that appeared
01652 // in the file are here.
01653 
01654 void
01655 WN2F_Append_Block_Data(TOKEN_BUFFER  tokens)
01656 {
01657   TOKEN_BUFFER Decl_Stmt_Tokens ;
01658 
01659   Decl_Stmt_Tokens = New_Token_Buffer() ;
01660   Data_Stmt_Tokens = New_Token_Buffer() ;
01661   PUinfo_local_decls = New_Token_Buffer() ;
01662 
01663   For_all(St_Table,GLOBAL_SYMTAB,WN2F_emit_commons(Decl_Stmt_Tokens)) ;
01664 
01665   if (!Is_Empty_Token_Buffer(Decl_Stmt_Tokens)) 
01666     {
01667       Append_F77_Indented_Newline(tokens, 1, NULL);
01668       Append_Token_String(tokens, "BLOCK DATA");
01669 
01670 # if 0
01671       Append_F77_Indented_Newline(tokens, 1, NULL);
01672       Append_Token_String(tokens, "IMPLICIT NONE");
01673 # endif
01674 
01675       WHIRL2F_Append_Comment(tokens, "**** Variables ****", 1, 1);
01676       Append_F77_Indented_Newline(tokens, 1, NULL);
01677       Append_And_Reclaim_Token_List(tokens, &Decl_Stmt_Tokens);
01678 
01679       Append_And_Reclaim_Token_List(tokens,&PUinfo_local_decls);
01680   
01681       if (!Is_Empty_Token_Buffer(Data_Stmt_Tokens)) 
01682         {
01683 
01684           WHIRL2F_Append_Comment(tokens, "**** Statements ****", 1, 1);
01685           Append_And_Reclaim_Token_List(tokens, &Data_Stmt_Tokens);
01686         }
01687 
01688       Append_F77_Indented_Newline(tokens, 1, NULL) ;
01689       Append_Token_String(tokens, "END") ;
01690       Append_Token_Special(tokens, '\n');
01691     }
01692 
01693 }
01694 
01695 void
01696 WN2F_Append_Purple_Funcinfo(TOKEN_BUFFER tokens)
01697 {
01698    const char *name   = W2F_Object_Name(PUINFO_FUNC_ST);
01699    mUINT32     id     = ST_st_idx(PUINFO_FUNC_ST);
01700    ST_SCLASS   sclass = ST_sclass(PUINFO_FUNC_ST);
01701    ST_EXPORT   export_class = (ST_EXPORT) ST_export(PUINFO_FUNC_ST);
01702 
01703    Append_Token_String(tokens, name);
01704    Append_Token_Special(tokens, ',');
01705    if (strcmp(name, WN2F_Purple_Region_Name) == 0)
01706    {
01707       /* This must match the setting in PRP_TRACE_READER::_Read_Next()
01708        * when a region is entered.
01709        */
01710       id = 0xffffffff;
01711       sclass = SCLASS_TEXT;
01712       export_class = EXPORT_INTERNAL;
01713    }
01714    Append_Token_String(tokens, Number_as_String(id, "%llu"));
01715    Append_Token_Special(tokens, ',');
01716    Append_Token_String(tokens, Number_as_String(sclass, "%lld"));
01717    Append_Token_Special(tokens, ',');
01718    Append_Token_String(tokens, Number_as_String(export_class, "%lld"));
01719    Append_Token_Special(tokens, ',');
01720    Append_Token_String(tokens, "0"); /* Flags */
01721 } /* WN2F_Append_Purple_Funcinfo */
01722 
01723 
01724 WN2F_STATUS 
01725 WN2F_block(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
01726 {
01727    WN          *stmt;
01728    WN          *induction_step = NULL;
01729    TOKEN_BUFFER stmt_tokens;
01730    const BOOL   is_pu_block = WN2F_CONTEXT_new_pu(context);
01731    const BOOL   add_induction_step = WN2F_CONTEXT_insert_induction(context);
01732    
01733    ASSERT_DBG_FATAL(WN_operator(wn) == OPR_BLOCK, 
01734                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_block"));
01735        
01736 
01737    if (add_induction_step)
01738    {
01739       induction_step = WN2F_CONTEXT_induction_stmt(context);
01740       reset_WN2F_CONTEXT_induction_step(context);
01741    }
01742    
01743    if (is_pu_block)
01744    {
01745       WN2F_Enter_PU_Block();
01746       reset_WN2F_CONTEXT_new_pu(context);
01747    }
01748    
01749    /* Translate statements and determine variable usage */
01750    stmt_tokens = New_Token_Buffer();
01751    for (stmt = WN_first(wn); stmt != NULL; stmt = WN_next(stmt))
01752    {
01753       if (!WN2F_Skip_Stmt(stmt))
01754       {
01755          if (induction_step != NULL && 
01756              WN_next(stmt) == NULL  &&
01757              WN_operator(stmt) == OPR_LABEL)
01758          {
01759             /* Add induction step before loop-label */
01760             (void)WN2F_translate(stmt_tokens, induction_step, context);
01761             induction_step = NULL;
01762          }
01763          (void)WN2F_translate(stmt_tokens, stmt, context);
01764 
01765          /* Append frequency feedback info in a comment
01766           */
01767          if (W2F_Emit_Frequency                         && 
01768              W2F_Frequency_Map != WN_MAP_UNDEFINED      &&
01769              WN_MAP32_Get(W2F_Frequency_Map, stmt) >= 0 &&
01770              WN_operator(stmt) != OPR_REGION              &&
01771              WN_operator(stmt) != OPR_PRAGMA              &&
01772              WN_operator(stmt) != OPR_XPRAGMA             &&
01773              WN_operator(stmt) != OPR_TRAP                &&
01774              WN_operator(stmt) != OPR_ASSERT              &&
01775              WN_operator(stmt) != OPR_FORWARD_BARRIER     &&
01776              WN_operator(stmt) != OPR_BACKWARD_BARRIER)
01777          {
01778             INT32 freq = WN_MAP32_Get(W2F_Frequency_Map, stmt);
01779             Append_Token_String(tokens, "  !FREQ=");
01780             Append_Token_String(tokens, WHIRL2F_number_as_name(freq));
01781          }
01782       }
01783    }
01784 
01785    /* Append the induction-step as the last statement in the block */
01786    if (induction_step != NULL)
01787       (void)WN2F_translate(stmt_tokens, induction_step, context);
01788 
01789    if (is_pu_block)
01790       WN2F_Exit_PU_Block(tokens, &stmt_tokens);
01791    else
01792    {
01793       Append_And_Reclaim_Token_List(tokens, &stmt_tokens);
01794    }
01795    return EMPTY_WN2F_STATUS;
01796 } /* WN2F_block */
01797 
01798 
01799 WN2F_STATUS 
01800 WN2F_compgoto(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
01801 {
01802    WN         *goto_stmt;
01803    INT32       goto_entry;
01804    const char *label_num;
01805 
01806    ASSERT_DBG_FATAL(WN_operator(wn) == OPR_COMPGOTO, 
01807                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_compgoto"));
01808    ASSERT_DBG_FATAL(WN_operator(WN_compgoto_table(wn)) == OPR_BLOCK,
01809                     (DIAG_W2F_UNEXPECTED_OPC, "WN_compgoto_table"));
01810 
01811    /* Calculate the computed goto for the given cases */
01812    if (WN_compgoto_num_cases(wn) > 0)
01813    {
01814       WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
01815       Append_Token_String(tokens, "GO TO");
01816       Append_Token_Special(tokens, '(');
01817       goto_stmt = WN_first(WN_compgoto_table(wn));
01818       for (goto_entry = 0;
01819            goto_entry < WN_compgoto_num_cases(wn); 
01820            goto_entry++)
01821       {
01822          ASSERT_DBG_FATAL(WN_operator(goto_stmt) == OPR_GOTO,
01823                           (DIAG_W2F_UNEXPECTED_OPC, "COMPGOTO entry"));
01824          label_num = WHIRL2F_number_as_name(WN_label_number(goto_stmt));
01825          Append_Token_String(tokens, label_num);
01826          if (goto_entry+1 < WN_compgoto_num_cases(wn))
01827             Append_Token_Special(tokens, ',');
01828          goto_stmt = WN_next(goto_stmt);
01829       }
01830       Append_Token_Special(tokens, ')');
01831       Append_Token_Special(tokens, ',');
01832 
01833       /* Need to add one to the controlling expression, since it is
01834        * zero-based in WHIRL and 1-based in Fortran.
01835        */
01836       (void)WN2F_translate(tokens, WN_compgoto_idx(wn), context);
01837       Append_Token_Special(tokens, '+');
01838       Append_Token_String(tokens, "1");
01839    }
01840 
01841    /* Handle the default case as just a regular goto statement */
01842    if (WN_compgoto_has_default_case(wn))
01843       WN2F_goto(tokens, WN_kid(wn,2), context);
01844 
01845    return EMPTY_WN2F_STATUS;
01846 } /* WN2F_compgoto */
01847 
01848 
01849 WN2F_STATUS 
01850 WN2F_do_loop(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
01851 {
01852    /* It is somewhat complicated to always translate this correctly
01853     * back to Fortran, dependent on the form of the test-for-termination
01854     * and the idx-variable-increment expressions.  When we deem it too
01855     * complicated to be coped with, we generate a DO WHILE expression 
01856     * instead.  This is an area we can probably always improve with more
01857     * work.
01858     */
01859    STAB_OFFSET    idx_ofst;
01860    ST            *idx_var;
01861    WN            *step_size;
01862    DO_LOOP_BOUND *bound;
01863    WN            *loop_info;
01864    
01865    ASSERT_DBG_FATAL(WN_operator(wn) == OPR_DO_LOOP,
01866                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_do_loop"));
01867    ASSERT_DBG_FATAL(WN_operator(WN_start(wn)) == OPR_STID,
01868                     (DIAG_W2F_UNEXPECTED_OPC, "WN_start"));
01869    ASSERT_DBG_FATAL(WN_operator(WN_do_body(wn)) == OPR_BLOCK,
01870                     (DIAG_W2F_UNEXPECTED_OPC, "WN_do_body"));
01871 
01872    if (W2F_Prompf_Emission)
01873       WN2F_Start_Prompf_Transformed_Loop(tokens, wn, context);
01874 
01875    loop_info = WN_do_loop_info(wn);
01876    if (W2F_Emit_Cgtag && loop_info != NULL)
01877       WHIRL2F_Append_Comment(
01878          tokens, 
01879          Concat2_Strings("LOOPINFO #",
01880                          WHIRL2F_number_as_name((INT64)loop_info)),
01881          1,
01882          1);
01883 
01884    /* Whether or not we can generate a DO loop depends on the forms
01885     * of WN_end(wn) and WN_step(wn), so the first thing we need to
01886     * do is to accumulate some information about these.
01887     */
01888    idx_var = WN_st(WN_index(wn));
01889    idx_ofst = WN_idname_offset(WN_index(wn));
01890    step_size = WN2F_Get_DoLoop_StepSize(WN_step(wn), idx_var, idx_ofst);
01891    bound = WN2F_Get_DoLoop_Bound(WN_end(wn), idx_var, idx_ofst, step_size);
01892    
01893    if (bound != NULL)
01894    {
01895       /* Generate a DO LOOP statement */
01896       WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
01897       Append_Token_String(tokens, "DO");
01898       set_WN2F_CONTEXT_emit_stid(context);
01899       if (!WN2F_CONTEXT_no_newline(context))
01900       {
01901          set_WN2F_CONTEXT_no_newline(context);
01902          (void)WN2F_translate(tokens, WN_start(wn), context);
01903          reset_WN2F_CONTEXT_no_newline(context);
01904       }
01905       else
01906       {
01907          (void)WN2F_translate(tokens, WN_start(wn), context);
01908       }
01909       reset_WN2F_CONTEXT_emit_stid(context);
01910       Append_Token_Special(tokens, ',');
01911 
01912       (void)WN2F_Translate_DoLoop_Bound(tokens, bound, context);
01913       Append_Token_Special(tokens, ',');
01914 
01915       (void)WN2F_translate(tokens, step_size, context);
01916 
01917       Increment_Indentation();
01918       (void)WN2F_translate(tokens, WN_do_body(wn), context);
01919       Decrement_Indentation();
01920 
01921       WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
01922       Append_Token_String(tokens, "END DO");
01923    }
01924    else /* Generate a DO WHILE loop */
01925    {
01926       (void)WN2F_translate(tokens, WN_start(wn), context);
01927       WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
01928       Append_Token_String(tokens, "DO WHILE");
01929       Append_Token_Special(tokens, '(');
01930       set_WN2F_CONTEXT_has_logical_arg(context);
01931       set_WN2F_CONTEXT_no_parenthesis(context);
01932       (void)WN2F_translate(tokens, WN_end(wn), context);
01933       reset_WN2F_CONTEXT_no_parenthesis(context);
01934       reset_WN2F_CONTEXT_has_logical_arg(context);
01935       Append_Token_Special(tokens, ')');
01936       Increment_Indentation();
01937       set_WN2F_CONTEXT_induction_step(context, WN_step(wn));
01938       (void)WN2F_translate(tokens, WN_do_body(wn), context);
01939       Decrement_Indentation();
01940       WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
01941       Append_Token_String(tokens, "END DO");
01942    }
01943 
01944    if (W2F_Prompf_Emission)
01945       WN2F_End_Prompf_Transformed_Loop(tokens, wn, context);
01946 
01947    return EMPTY_WN2F_STATUS;
01948 } /* WN2F_do_loop */
01949 
01950 
01951 WN2F_STATUS 
01952 WN2F_implied_do(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
01953 {
01954    /* This is a fortran implied do_loop, which can only occur as an
01955     * an OPR_IO_ITEM.  We should always be able to regenerate
01956     * an implied do-loop from this WHIRL tree, and we should safely
01957     * be able to assert that WN2F_CONTEXT_io_stmt is TRUE.  Strictly
01958     * speaking this can be viewed as an expression, rather than as a
01959     * statement, but due to the commonality with regular do-loops
01960     * we handle it in this module.
01961     */
01962    INT   kid;
01963    BOOL  emitted;
01964    ST   *idx_name;
01965    
01966    ASSERT_DBG_FATAL(WN2F_CONTEXT_io_stmt(context) &&
01967                     WN2F_CONTEXT_no_newline(context),
01968                     (DIAG_W2F_UNEXPECTED_CONTEXT, "WN2F_implied_do"));
01969 
01970    /* Start an implied do-loop expression */
01971    Append_Token_Special(tokens, '(');
01972 
01973    /* Generate all the expression trees, separated by commas */
01974    for (kid = 4; kid < WN_kid_count(wn); kid++)
01975    {
01976       emitted = WN2F_io_item(tokens, WN_kid(wn, kid), context);
01977       if (emitted)
01978          Append_Token_Special(tokens, ',');
01979    }
01980 
01981    /* Generate the loop expression */
01982    idx_name = WN_st(WN_index(wn));
01983    WN2F_Offset_Symref(tokens, 
01984                       idx_name,                           /* base-symbol */
01985                       Stab_Pointer_To(ST_type(idx_name)), /* base-type */
01986                       ST_type(idx_name),                  /* object-type */
01987                       0,                                  /* object-ofst */
01988                       context);
01989    Append_Token_Special(tokens, '=');
01990    (void)WN2F_translate(tokens, WN_start(wn), context);
01991    Append_Token_Special(tokens, ',');
01992    (void)WN2F_translate(tokens, WN_end(wn), context);
01993    Append_Token_Special(tokens, ',');
01994    (void)WN2F_translate(tokens, WN_step(wn), context);
01995 
01996    /* Terminate the implied do-loop expression */
01997    Append_Token_Special(tokens, ')');
01998 
01999    return EMPTY_WN2F_STATUS;
02000 } /* WN2F_implied_do */
02001 
02002 
02003 WN2F_STATUS 
02004 WN2F_do_while(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
02005 {
02006    const char *tmpvar_name;
02007    UINT        tmpvar_idx;
02008    TY_IDX      logical_ty;
02009    
02010    ASSERT_DBG_FATAL(WN_operator(wn) == OPR_DO_WHILE,
02011                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_do_while"));
02012 
02013    /* The base-type of the logical expression.  Note that TY_is_logical()
02014     * will only hold true when the TY is resolved from a WN_ty or ST_ty
02015     * attribute, not when it is resolved from an MTYPE (descriptor or
02016     * result type).
02017     */
02018    logical_ty = WN_Tree_Type(WN_while_test(wn));
02019    
02020    if (W2F_Prompf_Emission)
02021       WN2F_Start_Prompf_Transformed_Loop(tokens, wn, context);
02022 
02023    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02024    WHIRL2F_Append_Comment(tokens, 
02025       "whirl2f:: DO loop with termination test after first iteration", 1, 1);
02026 
02027    /* termination test initialization (in temporary variable) */
02028    tmpvar_idx = Stab_Lock_Tmpvar(logical_ty, &ST2F_Declare_Tempvar);
02029    tmpvar_name = W2CF_Symtab_Nameof_Tempvar(tmpvar_idx);
02030    Append_Token_String(tokens, tmpvar_name);
02031    Append_Token_Special(tokens, '=');
02032    Append_Token_String(tokens, ".TRUE.");
02033    
02034    /* loop header */
02035    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02036    Append_Token_String(tokens, "DO WHILE");
02037    Append_Token_Special(tokens, '(');
02038    Append_Token_String(tokens, tmpvar_name);
02039    Append_Token_Special(tokens, ')');
02040 
02041    /* loop body and termination test initialization (in temporary variable) */
02042    Increment_Indentation();
02043    (void)WN2F_translate(tokens, WN_while_body(wn), context);
02044    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02045    Append_Token_String(tokens, tmpvar_name);
02046    Append_Token_Special(tokens, '=');
02047    set_WN2F_CONTEXT_has_logical_arg(context);
02048    (void)WN2F_translate(tokens, WN_while_test(wn), context);
02049    reset_WN2F_CONTEXT_has_logical_arg(context);
02050    Decrement_Indentation();
02051 
02052    /* Close the loop and allow reuse of the termination test 
02053     * temporary variable.
02054     */
02055    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02056    Append_Token_String(tokens, "END DO");
02057    Stab_Unlock_Tmpvar(tmpvar_idx);
02058 
02059    if (W2F_Prompf_Emission)
02060       WN2F_End_Prompf_Transformed_Loop(tokens, wn, context);
02061 
02062    return EMPTY_WN2F_STATUS;
02063 } /* WN2F_do_while */
02064 
02065 
02066 WN2F_STATUS 
02067 WN2F_while_do(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
02068 {
02069    ASSERT_DBG_FATAL(WN_operator(wn) == OPR_WHILE_DO,
02070                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_while_do"));
02071 
02072    if (W2F_Prompf_Emission)
02073       WN2F_Start_Prompf_Transformed_Loop(tokens, wn, context);
02074 
02075    /* Termination test */
02076    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02077    Append_Token_String(tokens, "DO WHILE");
02078    Append_Token_Special(tokens, '(');
02079    set_WN2F_CONTEXT_has_logical_arg(context);
02080    set_WN2F_CONTEXT_no_parenthesis(context);
02081    (void)WN2F_translate(tokens, WN_while_test(wn), context);
02082    reset_WN2F_CONTEXT_no_parenthesis(context);
02083    reset_WN2F_CONTEXT_has_logical_arg(context);
02084    Append_Token_Special(tokens, ')');
02085 
02086    /* loop body */
02087    Increment_Indentation();
02088    (void)WN2F_translate(tokens, WN_while_body(wn), context);
02089    Decrement_Indentation();
02090 
02091    /* close the loop */
02092    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02093    Append_Token_String(tokens, "END DO");
02094 
02095    if (W2F_Prompf_Emission)
02096       WN2F_End_Prompf_Transformed_Loop(tokens, wn, context);
02097 
02098    return EMPTY_WN2F_STATUS;
02099 } /* WN2F_while_do */
02100 
02101 
02102 WN2F_STATUS 
02103 WN2F_if(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
02104 {
02105    ASSERT_DBG_FATAL(WN_operator(wn) == OPR_IF,
02106                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_if"));
02107 
02108    /* Ignore if-guards inserted by lno, since these are redundant
02109     * in High WHIRL.
02110     */
02111    if (WN_Is_If_Guard(wn))
02112    {
02113       /* Emit only the THEN body, provided it is non-empty */
02114       if (WN_operator(WN_then(wn)) != OPR_BLOCK || 
02115           WN_first(WN_then(wn)) != NULL)
02116       {
02117          WN2F_translate(tokens, WN_then(wn), context);
02118       }
02119    }
02120    else /* Not a redundant guard (from whirl2f perspective) */
02121    {
02122       /* IF header */
02123       WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02124       Append_Token_String(tokens, "IF");
02125       Append_Token_Special(tokens, '(');
02126       set_WN2F_CONTEXT_has_logical_arg(context);
02127       set_WN2F_CONTEXT_no_parenthesis(context);
02128       (void)WN2F_translate(tokens, WN_if_test(wn), context);
02129       reset_WN2F_CONTEXT_no_parenthesis(context);
02130       reset_WN2F_CONTEXT_has_logical_arg(context);
02131       Append_Token_Special(tokens, ')');
02132       Append_Token_String(tokens, "THEN");
02133 
02134       /* THEN body */
02135       Increment_Indentation();
02136       (void)WN2F_translate(tokens, WN_then(wn), context);
02137       Decrement_Indentation();
02138 
02139       /* ELSE body */
02140       if (!WN_else_is_empty(wn))
02141       {
02142          WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02143          Append_Token_String(tokens, "ELSE");
02144          Increment_Indentation();
02145          (void)WN2F_translate(tokens, WN_else(wn), context);
02146          Decrement_Indentation();
02147       }
02148 
02149       /* if closing */
02150       WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02151       Append_Token_String(tokens, "ENDIF");
02152    } /* if WN_Is_If_Guard */
02153    
02154    return EMPTY_WN2F_STATUS;
02155 } /* WN2F_if */
02156 
02157 
02158 WN2F_STATUS 
02159 WN2F_goto(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
02160 {
02161    ASSERT_DBG_FATAL(WN_operator(wn) == OPR_GOTO || 
02162                     WN_operator(wn) == OPR_REGION_EXIT,
02163                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_goto"));
02164 
02165    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02166    Append_Token_String(tokens, "GO TO");
02167    Append_Token_String(tokens, WHIRL2F_number_as_name(WN_label_number(wn)));
02168    
02169    return EMPTY_WN2F_STATUS;
02170 } /* WN2F_goto */
02171 
02172 
02173 WN2F_STATUS 
02174 WN2F_agoto(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
02175 {
02176    ASSERT_DBG_FATAL(WN_operator(wn) == OPR_AGOTO,
02177                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_agoto"));
02178 
02179    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02180    Append_Token_String(tokens, "GO TO");
02181    (void)WN2F_translate(tokens, WN_kid0(wn), context);
02182    
02183    return EMPTY_WN2F_STATUS;
02184 } /* WN2F_agoto */
02185 
02186 
02187 WN2F_STATUS 
02188 WN2F_condbr(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
02189 {
02190    ASSERT_DBG_FATAL(WN_operator(wn) == OPR_TRUEBR || 
02191                     WN_operator(wn) == OPR_FALSEBR,
02192                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_condbr"));
02193 
02194    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02195    Append_Token_String(tokens, "IF");
02196    Append_Token_Special(tokens, '(');
02197    set_WN2F_CONTEXT_has_logical_arg(context);
02198    set_WN2F_CONTEXT_no_parenthesis(context);
02199    if (WN_operator(wn) == OPR_FALSEBR)
02200    {
02201       Append_Token_String(tokens, ".NOT.");
02202       Append_Token_Special(tokens, '(');
02203       (void)WN2F_translate(tokens, WN_condbr_cond(wn), context);
02204       Append_Token_Special(tokens, ')');
02205    }
02206    else /* WN_operator(wn) == OPR_TRUEBR */
02207    {
02208       (void)WN2F_translate(tokens, WN_condbr_cond(wn), context);
02209    }
02210    reset_WN2F_CONTEXT_no_parenthesis(context);
02211    reset_WN2F_CONTEXT_has_logical_arg(context);
02212    Append_Token_Special(tokens, ')');
02213    Append_Token_String(tokens, "GO TO");
02214    Append_Token_String(tokens, WHIRL2F_number_as_name(WN_label_number(wn)));
02215    
02216    return EMPTY_WN2F_STATUS;
02217 } /* WN2F_condbr */
02218 
02219 WN2F_STATUS 
02220 WN2F_return(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
02221 {
02222    /* Ensures that the return value resides in the implicit
02223     * return variable (PUINFO_FUNC_NAME), and returns control
02224     * from the current PU (PUinfo_current_func).
02225     */
02226 
02227    if (WN2F_Next_ReturnSite ==NULL) 
02228         return EMPTY_WN2F_STATUS;
02229 
02230    ST               *result_var =
02231                              (ST *)RETURNSITE_return_var(WN2F_Next_ReturnSite);
02232    const WN         *result_store = RETURNSITE_store1(WN2F_Next_ReturnSite);
02233    const STAB_OFFSET var_offset = RETURNSITE_var_offset(WN2F_Next_ReturnSite);
02234 
02235    ASSERT_DBG_FATAL(WN_operator(wn) == OPR_RETURN,
02236                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_return"));
02237 
02238    ASSERT_DBG_FATAL(RETURNSITE_return(WN2F_Next_ReturnSite) == wn,
02239                     (DIAG_W2F_UNEXPECTED_RETURNSITE, "WN2F_return()"));
02240    
02241    /* Do not emit a return statement for the main program unit.
02242     */
02243    if (PU_is_mainpu(Get_Current_PU()) || 
02244        strcmp(ST_name(WN_entry_name(PUinfo_current_func)), "MAIN__") == 0) 
02245    {
02246       WN2F_Next_ReturnSite = RETURNSITE_next(WN2F_Next_ReturnSite);
02247       return EMPTY_WN2F_STATUS;
02248    
02249    }
02250    // if this is called with the openad flag omit final returns
02251    if (W2F_OpenAD && // flag is set 
02252        WN_kid_count(wn) == 0 && // no kids 
02253        WN_last(WN_kid(PUinfo_current_func,WN_kid_count(PUinfo_current_func)-1))==wn) {  
02254        // it is the last statement in the last block directly under the FUNCENTRY
02255      WN2F_Next_ReturnSite = RETURNSITE_next(WN2F_Next_ReturnSite);
02256      return EMPTY_WN2F_STATUS;
02257    }
02258    /* Save off the return-value, unless there is no return-value or
02259     * it already resides where we expect it to be.
02260     */
02261    if (!PUINFO_RETURN_TO_PARAM                &&
02262        PUINFO_RETURN_TY != (TY_IDX) 0         &&
02263        TY_kind(PUINFO_RETURN_TY) != KIND_VOID &&
02264        RETURN_PREG_mtype(PUinfo_return_preg, 0) != MTYPE_V)
02265    {
02266       /* Note that we make more assumptions here than in the case
02267        * of whirl2c.  In particular, we always assume assignment
02268        * compatibility between the return-variable and the location
02269        * of the found return-value.
02270        */
02271       if (result_var != NULL)
02272       {
02273          if (ST_class(result_var) == CLASS_PREG || 
02274              !ST_is_return_var(result_var))
02275          {
02276             /* PUinfo_init_pu() revealed that the return value is present
02277              * in a variable or non-return-register.  Now, move the value to
02278              * this return location.
02279                      */
02280                     TY_IDX rv_ty = ST_type(result_var);
02281 
02282             if (TY_kind(rv_ty) != KIND_STRUCT) 
02283             {
02284               ASSERT_WARN(WN2F_Can_Assign_Types(rv_ty,
02285                                                 PUINFO_RETURN_TY),
02286                           (DIAG_W2F_INCOMPATIBLE_TYS, "WN2F_return"));
02287             }
02288 
02289             /* Assign the return value to PUINFO_FUNC_ST */
02290             WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02291             ST2F_use_translate(tokens, PUINFO_FUNC_ST);
02292             Append_Token_Special(tokens, '=');
02293             if (ST_class(result_var) == CLASS_PREG)
02294                ST2F_Use_Preg(tokens, ST_type(result_var),var_offset);
02295             else
02296                WN2F_Offset_Symref(tokens,
02297                                   result_var, /* base variable */
02298                                   Stab_Pointer_To(ST_type(result_var)),
02299                                      /* expected type of base address */
02300                                   PUINFO_RETURN_TY,
02301                                      /* type of object to be loaded */
02302                                   var_offset,
02303                                   context);
02304          }
02305       }
02306       else if (result_store != NULL)
02307       {
02308          /* We have a store (an STID) into the return register, so just
02309           * assign the rhs into PUINFO_FUNC_NAME.
02310           */
02311          ASSERT_DBG_FATAL(WN_operator(result_store) == OPR_STID,
02312                           (DIAG_W2F_UNEXPECTED_OPC, "WN2F_return"));
02313          ASSERT_WARN(WN2F_Can_Assign_Types(WN_Tree_Type(WN_kid0(result_store)),
02314                                            PUINFO_RETURN_TY),
02315                      (DIAG_W2F_INCOMPATIBLE_TYS, "WN2F_return"));
02316          
02317          /* Assign object being stored to PUINFO_FUNC_NAME */
02318          WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02319          ST2F_use_translate(tokens, PUINFO_FUNC_ST);
02320          Append_Token_Special(tokens, '=');
02321          (void)WN2F_translate(tokens, WN_kid0(result_store), context);
02322       }
02323       else if (RETURN_PREG_num_pregs(PUinfo_return_preg) == 1 &&
02324                TY_Is_Preg_Type(PUINFO_RETURN_TY))
02325       {
02326          /* There is a single return register holding the return value,
02327           * so return a reference to this register.
02328           */
02329          const MTYPE    preg_mtype = RETURN_PREG_mtype(PUinfo_return_preg, 0);
02330          TY_IDX const   preg_ty  = Stab_Mtype_To_Ty(preg_mtype);
02331          const PREG_IDX preg_num = RETURN_PREG_offset(PUinfo_return_preg, 0);
02332 
02333          ASSERT_WARN(WN2F_Can_Assign_Types(preg_ty, PUINFO_RETURN_TY),
02334                      (DIAG_W2F_INCOMPATIBLE_TYS, "WN2F_return"));
02335 
02336          WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02337          ST2F_use_translate(tokens, PUINFO_FUNC_ST);
02338          Append_Token_Special(tokens, '=');
02339          ST2F_Use_Preg(tokens, preg_ty, preg_num);
02340       }
02341       else /* Our most difficult case */
02342       {
02343          /* The return-value is in two registers and we have not been
02344           * able to determine that it also resides in a variable.  
02345           * TODO: 
02346           * This could be handled by equivalencing the return-variable with
02347           * a type corresponding to the two registers, for then to assign
02348           * the register-values to the components of this equivalent
02349           * return value.  For now, do nothing but warn about this case!
02350           */
02351 # if 0 
02352          ASSERT_WARN(FALSE,
02353                      (DIAG_UNIMPLEMENTED, "WN2F_return from two registers"));
02354 #endif
02355 
02356       } /* if */
02357    } /* if (need to store return value) */
02358            
02359    /* Return control */
02360    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02361    Append_Token_String(tokens, "RETURN");
02362 
02363    WN2F_Next_ReturnSite = RETURNSITE_next(WN2F_Next_ReturnSite);
02364    return EMPTY_WN2F_STATUS;
02365 } /* WN2F_return */
02366 
02367 WN2F_STATUS 
02368 WN2F_return_val(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
02369 {
02370 //   char buf[64];
02371    Is_True(WN_operator(wn) == OPR_RETURN_VAL,
02372       ("Invalid operator for WN2F_return_val()"));
02373    WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02374    if (WN_operator(WN_kid0(wn)) == OPR_LDID)   
02375        Append_Token_String(tokens, "RETURN");
02376    else {   
02377         Append_Token_String(tokens, "RETURN");
02378         (void) WN2F_translate(tokens, WN_kid0(wn), context);
02379          }
02380    return EMPTY_WN2F_STATUS;
02381 } /* WN2F_return_val */
02382 
02383 WN2F_STATUS 
02384 WN2F_label(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
02385 {
02386    const char *label_num;
02387 
02388    ASSERT_DBG_FATAL(WN_operator(wn) == OPR_LABEL, 
02389                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_label"));
02390 
02391    label_num = WHIRL2F_number_as_name(WN_label_number(wn));
02392    WN2F_Stmt_Newline(tokens, label_num, WN_Get_Linenum(wn), context);
02393    Append_Token_String(tokens, "CONTINUE");
02394    return EMPTY_WN2F_STATUS;
02395 } /* WN2F_label */
02396 
02397 
02398 WN2F_STATUS 
02399 WN2F_intrinsic_call(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
02400 {
02401    WN   *arg_expr;
02402    TY_IDX arg_ty;
02403    INT   str_kid, length_kid, first_length_kid;
02404    BOOL regular_call = FALSE; /* Specially treated intrinsic call? */
02405 
02406    ASSERT_DBG_FATAL(WN_operator(wn) == OPR_INTRINSIC_CALL, 
02407                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_intrinsic_call"));
02408 
02409    switch (WN_intrinsic(wn))
02410    {
02411    case INTRN_CONCATEXPR:
02412 
02413       /* In the context of an IO statement, emit the concatenation
02414        * but disregard the temporary result buffer.
02415        */
02416       
02417       /* Determine the range of kids denoting the base of the string-
02418        * arguments and the the length of these strings respectively.
02419        */
02420       str_kid = 1;
02421       length_kid = first_length_kid = (WN_kid_count(wn) + 2)/2;
02422 
02423       /* Emit the concatenation operations */
02424       WN2F_String_Argument(tokens, 
02425                            WN_kid(wn, str_kid),    /* base of string1 */
02426                            WN_kid(wn, length_kid), /* length of string1 */
02427                            context);
02428       while ((++str_kid) < first_length_kid)
02429       {
02430          length_kid++;
02431          Append_Token_String(tokens, "//");
02432          WN2F_String_Argument(tokens, 
02433                               WN_kid(wn, str_kid),    /* base of stringN */
02434                               WN_kid(wn, length_kid), /* length of stringN */
02435                               context);
02436       }
02437       break;
02438    case INTRN_CASSIGNSTMT:
02439       WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02440       WN2F_String_Argument(tokens,
02441                            WN_kid(wn,0), /* base of destination */
02442                            WN_kid(wn,2), /* length of base */
02443                            context);
02444       Append_Token_Special(tokens, '=');
02445       WN2F_String_Argument(tokens, 
02446                            WN_kid(wn,1), /* base of source */
02447                            WN_kid(wn,3), /* length of source */
02448                            context);
02449       break;
02450 
02451    case INTRN_STOP:
02452    case INTRN_STOP_F90:
02453       WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02454       // Since this could be either the F90 stop or the F77 stop output the STOP
02455       // explicitly
02456       Append_Token_String(tokens, "STOP");
02457 
02458       /* Get the string argument type, where the second argument is
02459        * expected to be the string-length.
02460        */
02461       arg_ty = WN_Tree_Type(WN_kid0(wn));
02462       arg_expr = WN_Skip_Parm(WN_kid1(wn));
02463       ASSERT_DBG_WARN(WN_operator(arg_expr) == OPR_INTCONST , 
02464                       (DIAG_W2F_UNEXPECTED_OPC, 
02465                        "for INTRN_STOP in WN2F_intrinsic_call"));
02466 
02467       /* Only emit the string argument if it is of length > 0 */
02468       if (WN_const_val(arg_expr) > 0LL)
02469       {
02470          fld_type_z = 0;
02471          WN2F_Offset_Memref(tokens, 
02472                             WN_kid0(wn),        /* address expression */
02473                             arg_ty,             /* address type */
02474                             TY_pointed(arg_ty), /* object type */
02475                             0,                  /* offset from address */
02476                             context);
02477       }
02478       break;
02479      
02480    default:
02481       regular_call = TRUE;
02482       WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02483       WN2F_call(tokens, wn, context);
02484       break;
02485    }
02486 
02487    if (!regular_call && !WN2F_CONTEXT_io_stmt(context))
02488    {   
02489       /* Update the call site information to denote this one */
02490       if (WN2F_Prev_CallSite == NULL)
02491          WN2F_Prev_CallSite = PUinfo_Get_CallSites();
02492       else
02493          WN2F_Prev_CallSite = CALLSITE_next(WN2F_Prev_CallSite);
02494 
02495       ASSERT_DBG_FATAL(CALLSITE_call(WN2F_Prev_CallSite) == wn,
02496                        (DIAG_W2F_UNEXPECTED_CALLSITE, 
02497                         "WN2F_intrinsic_call()"));
02498    }
02499 
02500    return EMPTY_WN2F_STATUS;
02501 } /* WN2F_intrinsic_call */
02502 
02503 
02504 WN2F_STATUS 
02505 WN2F_call(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
02506 {
02507    /* Generates a function-call and ensures that the return value
02508     * is returned into the appropriate context, be it a variable
02509     * or a register.  Note that intrinsic calls are dispatched to
02510     * this function from WN2F_intrinsic_call() when appropriate.
02511     * Make sure the handling of instrinsic ops in wn2f_expr.c is
02512     * kept up to date with changes that occur here.
02513     */
02514    INT          arg_idx, implicit_args, first_arg_idx, last_arg_idx;
02515    INT          total_implicit_args;
02516    TOKEN_BUFFER call_tokens = New_Token_Buffer();
02517    TY_IDX       return_ty = 0 ;
02518    TY_IDX       arg_ty;
02519    BOOL         return_to_param;
02520    BOOL         is_user_call = FALSE;
02521    BOOL has_stat = FALSE;
02522    BOOL is_allocate_stmt = FALSE; 
02523    WN *kidofparm;
02524    TY_IDX kid_ty;
02525    TY_IDX parm_ty;
02526    BOOL first_nonemptyarg = FALSE;
02527    
02528    /* Emit any relevant call-site directives
02529     */
02530    
02531    if (WN_operator(wn) == OPR_CALL || WN_operator(wn) == OPR_PICCALL) {
02532      is_user_call = TRUE;
02533      if (WN2F_CONTEXT_io_stmt(context))
02534        /* Emit directives before io stmt */
02535        WN2F_Callsite_Directives(WN2F_io_prefix_tokens(), wn, WN_st(wn));
02536      else
02537        /* Emit directives before this stmt */
02538        WN2F_Callsite_Directives(tokens, wn, WN_st(wn));
02539    }
02540    
02541    /* Begin the call statement on a new line, unless it is part of an io
02542     * statement.
02543     */
02544 
02545 
02546    /* Tokenize the function-value expression and gather information
02547     * about the function type and index range of arguments.
02548     */
02549    if (WN_operator(wn) == OPR_INTRINSIC_CALL) {
02550      /* Note that all intrinsics that return a CHARACTER string
02551       * will have been treated specially in WN2F_intrinsic_call(),
02552       * so we need only consider returns through a first non-
02553       * string parameter here.
02554       */
02555      switch (WN_intrinsic(wn)) {
02556      case INTRN_F4VACOS:
02557      case INTRN_F8VACOS:
02558      case INTRN_F4VASIN:
02559      case INTRN_F8VASIN:
02560      case INTRN_F4VATAN:
02561      case INTRN_F8VATAN:
02562      case INTRN_F4VCOS:
02563      case INTRN_F8VCOS:
02564      case INTRN_F4VEXP:
02565      case INTRN_F8VEXP:
02566      case INTRN_F4VLOG:
02567      case INTRN_F8VLOG:
02568      case INTRN_F4VLOG10:
02569      case INTRN_F8VLOG10:
02570      case INTRN_F4VSIN:
02571      case INTRN_F8VSIN:
02572      case INTRN_F4VSQRT:
02573      case INTRN_F8VSQRT:
02574      case INTRN_F4VTAN:
02575      case INTRN_F8VTAN:
02576        /* Use the run-time library name for the vector intrinsic functions.
02577         */
02578        Append_Token_String(call_tokens, 
02579                            Concat2_Strings(INTRN_rt_name(WN_intrinsic(wn)), 
02580                                            "$"));
02581        break;
02582        
02583      default:
02584        Append_Token_String(call_tokens, 
02585                            WN_intrinsic_name((INTRINSIC)WN_intrinsic(wn)));
02586        break;
02587      }
02588      return_ty = WN_intrinsic_return_ty(WN_opcode(wn), 
02589                                         (INTRINSIC) WN_intrinsic(wn), wn);
02590      return_to_param = WN_intrinsic_return_to_param(return_ty);
02591      first_arg_idx = (return_to_param? 1 : 0);
02592      last_arg_idx = WN_kid_count(wn) - 1;
02593    }
02594    else {
02595      /* Only two things vary for CALL, ICALL, and PICCALL nodes: the
02596       * method used to get the function type and the last_arg_idx.
02597       */
02598      TY_IDX func_ty;
02599      
02600      if (WN_operator(wn) == OPR_CALL) {
02601        if (strcmp(ST_name(WN_st(wn)),"_ALLOCATE") !=0 &&
02602            strcmp(ST_name(WN_st(wn)),"_END") !=0 &&      
02603            (strcmp(ST_name(WN_st(wn)),"_DEALLOCATE") !=0 ))
02604          
02605          ST2F_use_translate(call_tokens, WN_st(wn));
02606        else {
02607          if (strcmp(ST_name(WN_st(wn)),"_ALLOCATE")== 0 ) {
02608            is_allocate_stmt = TRUE;
02609            Append_Token_String(call_tokens,"ALLOCATE"); }
02610          else if (strcmp(ST_name(WN_st(wn)),"_DEALLOCATE")== 0) {
02611            Append_Token_String(call_tokens,"DEALLOCATE");
02612            set_WN2F_CONTEXT_has_no_arr_elmt(context);
02613            is_allocate_stmt = TRUE;
02614          } 
02615        }
02616        
02617        if (strcmp(ST_name(WN_st(wn)),"PRESENT")== 0 || 
02618            strcmp(ST_name(WN_st(wn)),"ASSOCIATED")==0 )
02619          set_WN2F_CONTEXT_has_no_arr_elmt(context);
02620        
02621        
02622        if (strcmp(ST_name(WN_st(wn)),"ALLOCATED")== 0) {
02623          Append_Token_Special(call_tokens,'(');
02624          /* Get the array name,it shoud be CALL->PARM->ARRSECTION->LDA->st_name
02625           * Is there any other possible?
02626           * JU: we have e.g. CALL->PARM->LDID->st_name or a "value" selector injected
02627           */
02628          // get PARM
02629          WN* kidWN_p=WN_kid0(wn);
02630          while(kidWN_p!=0) { 
02631            if WN_has_sym(kidWN_p) { 
02632              Append_Token_String(call_tokens,
02633                                  ST_name(WN_st(kidWN_p)));
02634              break; 
02635            }
02636            kidWN_p=WN_kid0(kidWN_p);
02637          }
02638          ASSERT_DBG_FATAL(kidWN_p!=0,
02639                           (DIAG_W2F_UNEXPECTED_CONTEXT, "no name found for ALLOCATED parameter"));
02640          Append_Token_Special(call_tokens,')');
02641          Append_And_Reclaim_Token_List(tokens, &call_tokens);
02642          return EMPTY_WN2F_STATUS;
02643        }    
02644        func_ty = ST_pu_type(WN_st(wn));
02645        last_arg_idx = WN_kid_count(wn) - 1;
02646      }
02647      else if (WN_operator(wn) == OPR_ICALL) {
02648        (void)WN2F_translate(call_tokens, 
02649                             WN_kid(wn, WN_kid_count(wn) - 1), 
02650                             context);
02651        func_ty = WN_ty(wn);
02652        last_arg_idx = WN_kid_count(wn) - 2;
02653      }
02654      else { /* (WN_operator(wn) == OPR_PICCALL) */
02655        ASSERT_DBG_FATAL(WN_operator(wn) == OPR_PICCALL, 
02656                         (DIAG_W2F_UNEXPECTED_OPC, "WN2F_call"));
02657        ST2F_use_translate(call_tokens, WN_st(wn));
02658        func_ty = ST_type(WN_st(wn));
02659        last_arg_idx = WN_kid_count(wn) - 2;
02660      } /* if OPR_CALL */
02661 
02662      return_ty = W2X_Unparse_Target->Func_Return_Type(func_ty);
02663      return_to_param = W2X_Unparse_Target->Func_Return_To_Param(func_ty);
02664      first_arg_idx = ST2F_FIRST_PARAM_IDX(func_ty);
02665    } /* if OPR_INTRINSIC_CALL */
02666    
02667    /* Determine the number of implicit arguments appended to the end
02668     * of the argument list (i.e. string lengths).
02669     */
02670    for (arg_idx = first_arg_idx, total_implicit_args = 0; 
02671         arg_idx <= last_arg_idx - total_implicit_args; 
02672         arg_idx++) {
02673      if (WN_kid(wn,arg_idx)==NULL)
02674        ;
02675      else {
02676        kidofparm = WN_kid0(WN_kid(wn, arg_idx));
02677        if (WN_operator(kidofparm) != OPR_CALL && 
02678            WN_operator(kidofparm) != OPR_INTRINSIC_CALL) {
02679          arg_ty = WN_Tree_Type(WN_kid(wn, arg_idx));
02680          parm_ty = WN_ty(WN_kid(wn,arg_idx));
02681 #if 0
02682          if ((TY_Is_Character_Reference(arg_ty) 
02683               || TY_Is_Chararray_Reference(arg_ty) 
02684               || (TY_Is_Pointer(arg_ty) 
02685                   && TY_mtype(TY_pointed(arg_ty))==MTYPE_M
02686                   && (TY_Is_Character_Reference(parm_ty) 
02687                       || TY_Is_Chararray_Reference(parm_ty))))
02688              && !is_allocate_stmt) {
02689                total_implicit_args++;
02690            }
02691 #else 
02692           if ( (TY_Is_Character_Reference(parm_ty) ||
02693                  TY_Is_Chararray_Reference(parm_ty)||
02694                   TY_is_character(parm_ty)            )  &&
02695                 !is_allocate_stmt)
02696                   total_implicit_args++; 
02697 #endif
02698        }
02699        else { /*the argument is function call
02700                * if the return value is Chararray or Character Reference:
02701                */
02702          if (WN_operator(kidofparm) == OPR_CALL) {
02703            kid_ty = PU_prototype (Pu_Table[ST_pu(WN_st(kidofparm))]);
02704            if (W2X_Unparse_Target->Func_Return_Character (kid_ty))
02705              total_implicit_args++; 
02706            
02707          }
02708          else {
02709            if (WN_operator(kidofparm) == OPR_INTRINSIC_CALL &&
02710                WN_intrinsic(kidofparm) == INTRN_CONCATEXPR)
02711              total_implicit_args++;
02712          }
02713        }
02714      }
02715    }
02716    
02717    /* Append the argument list to the function reference, skipping
02718     * implicit character-string-length arguments assumed to be the
02719     * last ones in the list (see also ST2F_func_header()).  Note
02720     * that we should not need to use any special-casing for 
02721     * ADRTMP or VALTMP OPR_INTRINSIC_OP nodes, as these should be
02722     * handled appropriately by WN2F_translate().
02723     */
02724    
02725    if ((WN_operator(wn) == OPR_CALL)  &&
02726        strcmp(ST_name(WN_st(wn)),"_END") ==0 ) {
02727      ;
02728    } else {
02729      
02730      Append_Token_Special(call_tokens, '(');
02731      set_WN2F_CONTEXT_no_parenthesis(context);
02732      
02733      //WARNING
02734      /* tempoarily add a piece of code for processiong optinal
02735       * arguments in intrinsic function "system_clock".  will change
02736       * later to process all intrinsic functions with optional
02737       * arguments ---FMZ
02738       */
02739 
02740      //     if (strcmp(ST_name(WN_st(wn)),"SYSTEM_CLOCK") != 0 || TRUE) { //don't need it anymore FMZ
02741        
02742        for (arg_idx = first_arg_idx, implicit_args = 0; 
02743             arg_idx <= last_arg_idx - implicit_args; 
02744             arg_idx++) {
02745          if (WN_kid(wn, arg_idx) == NULL)
02746            ;
02747          else {
02748            kidofparm = WN_kid0(WN_kid(wn, arg_idx));
02749            if (WN_operator(kidofparm) !=OPR_CALL) {
02750              arg_ty = WN_Tree_Type(WN_kid(wn, arg_idx));
02751              parm_ty = WN_ty(WN_kid(wn,arg_idx));
02752             }
02753            else {
02754              arg_ty = PU_prototype (Pu_Table[ST_pu(WN_st(kidofparm))]);
02755              parm_ty = PU_prototype (Pu_Table[ST_pu(WN_st(kidofparm))]);
02756             }
02757            
02758            if (WN_operator(wn) == OPR_INTRINSIC_CALL &&
02759                INTRN_by_value(WN_intrinsic(wn))) {
02760              /* Call-by value, but argument should be emitted without
02761               * the %val() qualifier.
02762               */
02763              if (WN_kid(wn, arg_idx)!=NULL) {
02764                first_nonemptyarg = TRUE;
02765                WN2F_translate(call_tokens, WN_kid(wn, arg_idx), context);
02766              }
02767            } 
02768            else if ((WN_operator(kidofparm) != OPR_CALL   &&
02769                      (TY_Is_Character_Reference(parm_ty) ||
02770                       TY_Is_Chararray_Reference(parm_ty) ||
02771                         TY_is_character(parm_ty) )           ||
02772                    WN_operator(kidofparm) == OPR_CALL   &&
02773                    W2X_Unparse_Target->Func_Return_Character(arg_ty) )   &&
02774                   !is_allocate_stmt) {
02775              /* Handle substring arguments here.  These are always assumed
02776               * to be passed by reference. For a function result, the length
02777               * follows the address - does this look like char fn result?
02778               * can't tell, but make good guess..
02779               */
02780              INT len_idx ;
02781              INT cur_idx = arg_idx ;
02782              implicit_args++;
02783              
02784              if ((is_user_call) &&
02785                  (cur_idx == first_arg_idx) &&
02786                  (cur_idx == first_arg_idx) && 
02787                  (WN_kid_count(wn) >= cur_idx + 2) &&
02788                  ( WN_kid(wn,cur_idx+1) != NULL) &&
02789                  (WN_Parm_By_Value(WN_kid(wn,cur_idx + 1))) &&
02790                  ((return_ty != 0) && (TY_kind(return_ty) == KIND_VOID))) {
02791                len_idx = cur_idx + 1 ;
02792              }
02793              else                
02794                len_idx = last_arg_idx - (total_implicit_args - implicit_args); 
02795              if (first_nonemptyarg && !has_stat )
02796                Append_Token_Special(call_tokens, ','); 
02797              else
02798                has_stat = FALSE;
02799              
02800              first_nonemptyarg = TRUE;
02801 
02802              if (WN_kid(wn, cur_idx)->u3.ty_fields.ty) {  //keyword  FMZ 
02803                 ST2F_output_keyword(call_tokens,
02804                      &St_Table[WN_kid(wn, cur_idx)->u3.ty_fields.ty]);
02805                 Append_Token_Special(call_tokens,'=');
02806                } 
02807 
02808              WN2F_String_Argument(call_tokens,
02809                                   WN_kid(wn, cur_idx), /* string base */
02810                                   WN_kid(wn, len_idx), /* string length */
02811                                   context);
02812            }
02813            else if (!TY_Is_Pointer(arg_ty) || 
02814                     (WN_operator(WN_kid(wn, arg_idx)) == OPR_INTRINSIC_OP &&
02815                      INTR_is_valtmp(WN_intrinsic(WN_kid(wn, arg_idx))))) {
02816              /* Need to explicitly note this as a value parameter.
02817               */
02818              
02819              if (WN_operator(kidofparm) == OPR_INTRINSIC_CALL &&
02820                  WN_intrinsic(kidofparm)==INTRN_CONCATEXPR)
02821                
02822                implicit_args++;
02823              /*parser always generate an extra arg for concat operator*/
02824              
02825              if (WN_kid(wn, arg_idx)!=NULL   && 
02826                  WN_kid0(WN_kid(wn,arg_idx)) &&
02827                  WN_operator(WN_kid0(WN_kid(wn,arg_idx)))!= OPR_IMPLICIT_BND) {
02828                if (first_nonemptyarg && !has_stat)
02829                  Append_Token_Special(call_tokens, ','); 
02830                else
02831                  has_stat=FALSE;
02832                first_nonemptyarg = TRUE;
02833                WN2F_translate(call_tokens, WN_kid(wn, arg_idx), context);
02834              }
02835              // Append_Token_Special(call_tokens, ')');
02836            }
02837            else { /* TY_Is_Pointer(arg_ty) */
02838              /* There is also an implicit string length when the argument
02839               * is an array of character strings.
02840               */
02841              if (TY_Is_Chararray_Reference(arg_ty) &&
02842                  !is_allocate_stmt)
02843                implicit_args++;
02844              
02845              /* Assume call-by-reference parameter passing */
02846              if (WN_kid(wn, arg_idx)!=NULL){
02847                if (first_nonemptyarg && !has_stat)
02848                  Append_Token_Special(call_tokens, ','); 
02849                else
02850                  has_stat = FALSE;
02851                
02852                first_nonemptyarg = TRUE;
02853                fld_type_z = 0;
02854                WN2F_Offset_Memref(call_tokens, 
02855                                   WN_kid(wn, arg_idx), /* address expression */
02856                                   arg_ty,              /* address type */
02857                                   TY_pointed(arg_ty),  /* object type */
02858                                   0,                   /* offset from address*/
02859                                   context);
02860              }
02861            }
02862            
02863            if ((arg_idx+implicit_args) < (last_arg_idx-1) && 
02864                WN_kid(wn, arg_idx)!=NULL)
02865              ;
02866            else 
02867              if ((arg_idx+implicit_args) == (last_arg_idx-1)) { 
02868                if (WN_operator(wn) == OPR_CALL &&
02869                    (strcmp(ST_name(WN_st(wn)),"_ALLOCATE")== 0  ||
02870                     strcmp(ST_name(WN_st(wn)),"_DEALLOCATE")== 0)) {
02871                  if ((WN_opc_operator(WN_kid0(WN_kid(wn, (last_arg_idx)))))
02872                      == OPR_LDA) {
02873                    Append_Token_Special(call_tokens, ',');
02874                    Append_Token_String(call_tokens,"STAT=");
02875                    has_stat=TRUE;
02876                  } else
02877                    arg_idx++;
02878                  ;
02879                  
02880                }
02881                else 
02882                  if (WN_kid(wn, arg_idx)!=NULL && WN_kid(wn,arg_idx+1)!=NULL)
02883                    ;
02884                
02885                /* argument could be "optional" argument,so there could
02886                   be NULL wn */
02887                // Append_Token_Special(call_tokens, ',');
02888              }
02889          }
02890        }
02891        //     } /*not system_clock*/
02892 #if 0 
02893      else { /* here for system clock*/
02894        arg_idx = 0;  
02895        if (WN_kid(wn, arg_idx)!=NULL) {
02896          first_nonemptyarg =TRUE;
02897          Append_Token_String(call_tokens,"count=");
02898          WN2F_translate(call_tokens, WN_kid(wn, arg_idx), context);
02899        }
02900        arg_idx++;
02901        if (WN_kid(wn, arg_idx)!=NULL) {
02902          if (first_nonemptyarg)
02903            Append_Token_Special(call_tokens, ',');
02904          else
02905            first_nonemptyarg = TRUE;
02906          Append_Token_String(call_tokens,"count_rate=");
02907          WN2F_translate(call_tokens, WN_kid(wn, arg_idx), context);
02908        }
02909        arg_idx++;
02910        if (WN_kid(wn, arg_idx)!=NULL) {
02911          if (first_nonemptyarg)
02912            Append_Token_Special(call_tokens, ',');
02913          else first_nonemptyarg =TRUE;
02914          Append_Token_String(call_tokens,"count_max=");
02915          WN2F_translate(call_tokens, WN_kid(wn, arg_idx), context);
02916        }
02917        
02918      }
02919 #endif
02920      
02921      reset_WN2F_CONTEXT_no_parenthesis(context);
02922      reset_WN2F_CONTEXT_has_no_arr_elmt(context);
02923      Append_Token_Special(call_tokens, ')');
02924    }
02925    
02926    /* Only save off return-values for calls outside io-statements.
02927     * I assume here that no call information inside io-statements
02928     * have been recorded, assuming such calls are not walked when
02929     * traversing the stetements of a PU in PUinfo.c.
02930     */
02931    if (!WN2F_CONTEXT_io_stmt(context)) {
02932      /* Update the call site information to denote this one */
02933      if (WN2F_Prev_CallSite == NULL)
02934        WN2F_Prev_CallSite = PUinfo_Get_CallSites();
02935      else
02936        WN2F_Prev_CallSite = CALLSITE_next(WN2F_Prev_CallSite);
02937      
02938      ASSERT_DBG_FATAL(CALLSITE_call(WN2F_Prev_CallSite) == wn,
02939                       (DIAG_W2F_UNEXPECTED_CALLSITE, "WN2F_call()"));
02940      
02941      /* Next, save off the function return value to a (temporary)
02942       * variable or a return-register, as is appropriate.
02943       */
02944      if (return_ty != (TY_IDX) 0 && TY_kind(return_ty) != KIND_VOID) {
02945        /* This is not a subroutine, so a CALL statement is not valid
02946         * Fortran.  We must assign the resultant value to some location.
02947         * We do that here!
02948         */
02949        ASSERT_DBG_WARN(return_to_param || first_arg_idx == 0,
02950                        (DIAG_A_STRING, 
02951                         "WN2F_call expects first argument as kid0 "
02952                         "when not returning through first argument"));
02953        
02954        if (return_to_param) {
02955          /* Return through a parameter:  Assign the call-value to
02956           * the dereferenced implicit argument expression (first_arg).
02957           */
02958          fld_type_z = 0;
02959          (void)WN2F_Offset_Memref(tokens, 
02960                                   WN_kid0(wn),  /* return addr expression */
02961                                   WN_Tree_Type(WN_kid0(wn)), /* addr type */
02962                                   return_ty,    /* object type */
02963                                   0,            /* offset from address */
02964                                   context);
02965          Append_Token_Special(tokens, '=');
02966        }
02967        else /* Do not return to a parameter */
02968          ;
02969      }
02970      else { /* No return value, i.e. a SUBROUTINE */
02971        if (!WN2F_CONTEXT_io_stmt(context)) 
02972          
02973          WN2F_Stmt_Newline(tokens, NULL/*label*/, WN_Get_Linenum(wn), context);
02974        
02975        if (WN_operator(wn)==OPR_ICALL || 
02976            strcmp(ST_name(WN_st(wn)),"_ALLOCATE") !=0 &&
02977            strcmp(ST_name(WN_st(wn)),"_END") !=0 &&
02978            (strcmp(ST_name(WN_st(wn)),"_DEALLOCATE") !=0 ))
02979          Prepend_Token_String(call_tokens, "CALL");
02980      }
02981    }
02982    Append_And_Reclaim_Token_List(tokens, &call_tokens);
02983    
02984    return EMPTY_WN2F_STATUS;
02985 } /* WN2F_call */
02986 
02987 
02988 WN2F_STATUS 
02989 WN2F_prefetch(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
02990 {
02991    /* Prefetch information is currently added in a comment */
02992    INT pflag;
02993 
02994    ASSERT_DBG_FATAL(WN_operator(wn) == OPR_PREFETCH ||
02995                     WN_operator(wn) == OPR_PREFETCHX, 
02996                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_prefetch"));
02997 
02998    /* Ensure array references are dereferenced and a comment line is begun */
02999    set_WN2F_CONTEXT_deref_addr(context);
03000    Append_F77_Comment_Newline(tokens, 1/*empty-lines*/, TRUE/*indent*/);
03001 
03002    /* Get the prefetch identifier and address expression */
03003    if (WN_operator(wn) == OPR_PREFETCH)
03004    {
03005       Append_Token_String(tokens, 
03006          Concat3_Strings("PREFETCH(", Ptr_as_String(wn), ")"));
03007 
03008       (void)WN2F_translate(tokens, WN_kid0(wn), context);
03009 
03010       Append_Token_String(tokens, 
03011          Concat2_Strings("OFFS=", WHIRL2F_number_as_name(WN_offset(wn))));
03012    }
03013    else /* (WN_operator(wn) == OPR_PREFETCHX) */
03014    {
03015       Append_Token_String(tokens, 
03016          Concat3_Strings("PREFETCH(", Ptr_as_String(wn),")"));
03017 
03018       (void)WN2F_translate(tokens, WN_kid0(wn), context);
03019       Append_Token_Special(tokens, '+');
03020       (void)WN2F_translate(tokens, WN_kid1(wn), context);
03021    }
03022       
03023    /* Emit the prefetch flags information (pf_cg.h) on a separate line */
03024    pflag = WN_prefetch_flag(wn);
03025    Set_Current_Indentation(Current_Indentation()+3);
03026    Append_F77_Comment_Newline(tokens, 1/*empty-lines*/, TRUE/*indent*/);
03027    Append_Token_String(tokens,
03028       Concat2_Strings(     PF_GET_READ(pflag)? "read" : "write",
03029        Concat2_Strings(    " strid1=", 
03030         Concat2_Strings(   WHIRL2F_number_as_name(PF_GET_STRIDE_1L(pflag)),
03031          Concat2_Strings(  " strid2=", 
03032           Concat2_Strings( WHIRL2F_number_as_name(PF_GET_STRIDE_2L(pflag)),
03033            Concat2_Strings(" conf=", 
03034                            WHIRL2F_number_as_name(PF_GET_CONFIDENCE(pflag))
03035                            )))))));
03036    Set_Current_Indentation(Current_Indentation()-3);
03037 
03038    return EMPTY_WN2F_STATUS;
03039 } /* WN2F_prefetch */
03040 
03041 
03042 WN2F_STATUS
03043 WN2F_eval(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
03044 {
03045    /* This generates code that will not recompile.  Short of
03046     * some kind of surrounding statement there is no way to do 
03047     * this in Fortran-77.
03048     */
03049    ASSERT_DBG_FATAL(WN_operator(wn) == OPR_EVAL, 
03050                     (DIAG_W2F_UNEXPECTED_OPC, "WN2F_eval"));
03051 
03052    Append_F77_Comment_Newline(tokens, 1/*empty-lines*/, TRUE/*indent*/);
03053    Append_Token_String(tokens, "CALL");
03054    Append_Token_String(tokens, "_EVAL");
03055    Append_Token_Special(tokens, '(');
03056    set_WN2F_CONTEXT_has_logical_arg(context);
03057    set_WN2F_CONTEXT_no_parenthesis(context);
03058    (void)WN2F_translate(tokens, WN_kid0(wn), context);
03059    Append_Token_Special(tokens, ')');
03060 
03061    return EMPTY_WN2F_STATUS;
03062 } /* WN2F_eval */
03063 
03064 //**********************************************
03065 WN2F_STATUS
03066 WN2F_use_stmt(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
03067  {
03068      return EMPTY_WN2F_STATUS;
03069  } //WN2F_use_stmt
03070 //**********************************************
03071 WN2F_STATUS
03072 WN2F_namelist_stmt(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
03073  {
03074    int k ;
03075 
03076    const char *st_name =  W2CF_Symtab_Nameof_St(WN_st(wn));
03077     ASSERT_DBG_FATAL(WN_operator(wn) == OPR_NAMELIST,
03078                      (DIAG_W2F_UNEXPECTED_OPC, "WN2F_namelist_stmt"));
03079    if (ST_is_external(WN_st(wn)))
03080     {
03081       ;
03082      } else {
03083 
03084      Append_F77_Indented_Newline(tokens, 1/*empty-lines*/, NULL/*label*/);
03085      Append_Token_String(tokens, "NAMELIST /");
03086      Append_Token_String(tokens, st_name);
03087      Append_Token_String(tokens, " /");
03088 
03089      for(k=0;k< WN_kid_count(wn);k++ )
03090 
03091        { st_name = W2CF_Symtab_Nameof_St(WN_st(WN_kid(wn,k)));
03092         Set_BE_ST_w2fc_referenced(WN_st(WN_kid(wn,k)));
03093         if (k==0)
03094            ;
03095         else
03096           Append_Token_String(tokens,",");
03097           Append_Token_String(tokens,st_name);
03098 
03099        }
03100    }
03101 
03102      return EMPTY_WN2F_STATUS;
03103  } //WN2F_namelist_stmt
03104 
03105 //**********************************************
03106 WN2F_STATUS
03107 WN2F_implicit_bnd(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
03108  {
03109      Append_Token_Special(tokens, ' ');
03110   return EMPTY_WN2F_STATUS;
03111  }
03112 
03113 // OPC_SWITCH only appears in very high level whirl
03114 
03115 WN2F_STATUS
03116 WN2F_switch(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
03117  {
03118   WN *stmt;
03119   WN *kid1wn;
03120 
03121 //Append_F77_Indented_Newline(tokens, 1/*empty-lines*/, NULL/*label*/);
03122 //  Append_Token_String(tokens,"SELECT CASE (");
03123 //(void)WN2F_translate(tokens, WN_condbr_cond(wn), context);
03124 // Append_Token_Special(tokens, ')');
03125 
03126    kid1wn = WN_kid1(wn);
03127 
03128    for (stmt = WN_first(kid1wn); stmt != NULL; stmt = WN_next(stmt))
03129    {
03130       if (!WN2F_Skip_Stmt(stmt))
03131       {
03132          if (WN_operator(stmt) == OPR_CASEGOTO)
03133            WN_st_idx(stmt) = WN_st_idx(WN_kid0(wn));
03134       }
03135    }
03136 
03137 (void)WN2F_translate(tokens, WN_kid1(wn), context);
03138 if (WN_kid_count(wn) == 3)
03139 (void)WN2F_translate(tokens, WN_kid2(wn), context);
03140 //  Append_F77_Indented_Newline(tokens, 1/*empty-lines*/, NULL/*label*/);
03141 //  Append_Token_String(tokens,"END SELECT ");
03142 
03143    return EMPTY_WN2F_STATUS;
03144  }
03145 
03146 
03147 WN2F_STATUS
03148 WN2F_casegoto(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
03149  {
03150   ST *st;
03151   st = WN_st(wn);
03152 
03153   Append_F77_Indented_Newline(tokens, 1/*empty-lines*/, NULL/*label*/);
03154 //  Append_Token_String(tokens,"CASE");
03155   Append_Token_String(tokens,"IF (");
03156   ST2F_use_translate(tokens,st);
03157   Append_Token_String(tokens," .EQ. ");
03158   TCON2F_translate(tokens,Host_To_Targ(MTYPE_I4,WN_const_val(wn)),FALSE);
03159   Append_Token_Special(tokens,')');
03160   Append_Token_String(tokens," GO TO ");
03161   Append_Token_String(tokens, WHIRL2F_number_as_name(WN_label_number(wn)));
03162    return EMPTY_WN2F_STATUS;
03163  }
03164 
03165 
03166 //**********************************************
03167 WN2F_STATUS
03168 WN2F_nullify_stmt(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
03169  {
03170    int k ;
03171    WN* kidwn;
03172 
03173    const char *st_name;
03174 
03175     ASSERT_DBG_FATAL(WN_operator(wn) == OPR_NULLIFY,
03176                      (DIAG_W2F_UNEXPECTED_OPC, "WN2F_nullify_stmt"));
03177 
03178      Append_F77_Indented_Newline(tokens, 1/*empty-lines*/, NULL/*label*/);
03179      Append_Token_String(tokens, "NULLIFY (");
03180 
03181      for(k=0;k< WN_kid_count(wn);k++ ) {
03182         if (k==0)
03183            ;
03184         else
03185           Append_Token_String(tokens,",");
03186 
03187         kidwn=WN_kid(wn,k);
03188 
03189         while (( WN_operator(kidwn)==OPR_ARRAY) ||
03190               (WN_operator(kidwn)==OPR_ARRSECTION)) {
03191             kidwn = WN_kid0(kidwn); //skip array scripts part
03192          }
03193 
03194         (void)WN2F_translate(tokens,kidwn,context);
03195 
03196        }
03197 
03198       Append_Token_Special(tokens,')' );
03199 
03200      return EMPTY_WN2F_STATUS;
03201  } //WN2F_nullify_stmt
03202 
03203 //**********************************************
03204 WN2F_STATUS
03205 WN2F_interface_blk(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
03206  {
03207    int           k ;
03208    ST            **param_st;
03209    ST            *st = WN_st(wn);
03210    ST            *rslt = NULL;
03211    INT           param,num_params;
03212    INT           first_param;
03213    TY_IDX        return_ty;
03214    TOKEN_BUFFER  header_tokens;
03215    INT           implicit  ;
03216    BOOL          add_rsl_decl = 0;
03217 
03218 
03219 
03220     
03221    const char *intface_name = ST_name(st);
03222 
03223     ASSERT_DBG_FATAL(WN_operator(wn) == OPR_INTERFACE,
03224                      (DIAG_W2F_UNEXPECTED_OPC, "WN2F_interface_blk"));
03225 
03226      if (ST_is_external(WN_st(wn)))
03227          return EMPTY_WN2F_STATUS;
03228 
03229      Append_F77_Indented_Newline(tokens, 1/*empty-lines*/, NULL/*label*/);
03230      Append_Token_String(tokens, "interface ");
03231      
03232      if (ST_is_assign_interface(st))
03233        {
03234          Append_Token_String(tokens,"assignment ");
03235          Append_Token_Special(tokens,'(');
03236        }
03237 
03238      if (ST_is_operator_interface(st) || ST_is_u_operator_interface(st)){
03239         Append_Token_String(tokens,"operator");
03240         Append_Token_Special(tokens,'(');
03241       }
03242 
03243      if (ST_is_u_operator_interface(st)) 
03244         Append_Token_Special(tokens,'.');
03245 
03246      if (strcmp(intface_name,unnamed_interface)) 
03247          Append_Token_String(tokens, intface_name);
03248 
03249      if (ST_is_u_operator_interface(st))
03250          Append_Token_Special(tokens,'.');
03251  
03252      if (ST_is_assign_interface(st) ||
03253          ST_is_operator_interface(st) ||
03254          ST_is_u_operator_interface(st))
03255          Append_Token_Special(tokens,')');
03256  
03257      Append_Token_Special(tokens, '\n');
03258      Increment_Indentation();
03259 
03260      for(k=0;k< WN_kid_count(wn);k++ ) 
03261                  /* each kid is a WN with "OPR_FUNC_ENTRY" */
03262       {
03263         implicit = 0;
03264         add_rsl_decl = 0;
03265         header_tokens =  New_Token_Buffer();
03266         num_params = WN_kid_count(WN_kid(wn,k));
03267         param_st = (ST **)alloca((num_params + 1) * sizeof(ST *));
03268         for (param = 0; param < num_params; param++)
03269           {
03270                  param_st[param] = WN_st(WN_formal(WN_kid(wn,k), param)); 
03271 // if a type of a dummy argument is user defined type "mtype"
03272 // get the ST entry of the module "m1", add "use m1"
03273            }
03274         param_st[num_params]=NULL; /* terminate the list with NULL */
03275         st = &St_Table[WN_entry_name(WN_kid(wn,k))];
03276         TY_IDX       funtype = ST_pu_type(st);
03277 
03278         return_ty = W2X_Unparse_Target->Func_Return_Type(funtype);
03279 
03280         if (ST_is_in_module(st) ) {
03281              Append_Token_String(header_tokens,"module procedure ");
03282              Append_Token_String(header_tokens, W2CF_Symtab_Nameof_St(st));     
03283           }
03284         else {
03285          if (return_ty != (TY_IDX) 0 && TY_kind(return_ty) != KIND_VOID)
03286                         /* function */
03287            {
03288              Append_Token_String(header_tokens, "FUNCTION");
03289    
03290              if (PU_recursive(Get_Current_PU())) 
03291                  Prepend_Token_String(header_tokens, "RECURSIVE");
03292              add_rsl_decl = 1;
03293              }
03294           else         /* subroutine */
03295             {
03296               Append_Token_String(header_tokens, "SUBROUTINE");
03297             }
03298    
03299            Append_Token_String(header_tokens, W2CF_Symtab_Nameof_St(st));
03300 
03301 
03302       /* Emit the parameter name-list, if one is present, and skip any
03303        * implicit "length" parameters associated with character strings.
03304        * Such implicit parameters should be at the end of the parameter list.
03305        */
03306    
03307           first_param = ST2F_FIRST_PARAM_IDX(funtype);
03308           BOOL isFirstArg = TRUE; 
03309                 /* become FALSE after first argument has been emitted */
03310                                   /* (radu@par.univie.ac.at) */
03311          if (param_st[first_param] != NULL)
03312             {
03313              Append_Token_Special(header_tokens, '(');
03314              for (param = first_param;
03315                   param < num_params-implicit;
03316                   param++)
03317                 {
03318                   if (STAB_PARAM_HAS_IMPLICIT_LENGTH(param_st[param])) 
03319                           implicit++;
03320                   if (!ST_is_return_var(param_st[param])) {
03321                       /* separate argument with a comma, if not the first one */
03322                       /* (radu@par.univie.ac.at) */
03323                           if(isFirstArg == FALSE)
03324                                Append_Token_Special(header_tokens, ',');
03325                           else
03326                                isFirstArg = FALSE;
03327                           Append_Token_String(header_tokens,
03328                                               W2CF_Symtab_Nameof_St(param_st[param]));
03329    
03330                           /* Bug: next and last param may be implicit */
03331                           /* this causes the argument list to end with a comma */
03332                           /* (radu@par.univie.ac.at) */
03333                      }else
03334                          rslt = param_st[param];
03335    
03336               }
03337               Append_Token_Special(header_tokens, ')');
03338            }
03339          else 
03340            {
03341              /* Use the "()" notation for "no parameters" */
03342             Append_Token_Special(header_tokens, '(');
03343             Append_Token_Special(header_tokens, ')');
03344             }
03345       
03346         if (rslt !=NULL     && 
03347              strcasecmp(W2CF_Symtab_Nameof_St(st), W2CF_Symtab_Nameof_St(rslt)) != 0)
03348          {
03349            /* append the RESULT option only if it is different from the function name */
03350            /* (radu@par.univie.ac.at) */
03351            Append_Token_String(header_tokens,"result(");
03352            Append_Token_String( header_tokens,
03353                                 W2CF_Symtab_Nameof_St(rslt));
03354            Append_Token_Special(header_tokens, ')');
03355           }
03356    
03357         Append_F77_Indented_Newline(header_tokens, 1/*empty-lines*/, NULL/*label*/);
03358         Append_Token_String(header_tokens, "use w2f__types");
03359 
03360       // add "use mm" 
03361       TyIdxToStIdxMap::iterator currpos;
03362 
03363       // set "module st " with "BE_ST_w2fc_referenced" 
03364       // to prevent multiple "use" stmt
03365       for (currpos=tyidx_modidx.begin();
03366            currpos != tyidx_modidx.end();
03367            currpos++)
03368             Set_BE_ST_w2fc_referenced(currpos->second);
03369 
03370       for (param = 0; param < num_params; param++){
03371             TY_IDX parmty= ST_type(param_st[param]);
03372             ST_IDX currmod;
03373             if (TY_kind(parmty) == KIND_STRUCT) { 
03374                 currpos=tyidx_modidx.find(parmty);
03375                 if (currpos !=tyidx_modidx.end()) {
03376                    currmod = currpos->second;
03377                    if (BE_ST_w2fc_referenced(currmod)) {
03378                       Clear_BE_ST_w2fc_referenced(currmod);
03379                       Append_F77_Indented_Newline(header_tokens, 1/*empty-lines*/, NULL/*label*/);
03380                       Append_Token_String(header_tokens,"use ");
03381                       Append_Token_String(header_tokens, 
03382                             W2CF_Symtab_Nameof_St(&St_Table[currmod]));
03383                     }
03384                 }
03385            }
03386       }   
03387 
03388    
03389         if (add_rsl_decl){
03390            TOKEN_BUFFER temp_tokens = New_Token_Buffer();
03391            Append_F77_Indented_Newline(header_tokens, 1/*empty-lines*/, NULL/*label*/);
03392            if (TY_Is_Pointer(return_ty))
03393                TY2F_translate(temp_tokens,
03394                         Stab_Mtype_To_Ty(TY_mtype(return_ty)));
03395             else {
03396                  if (TY_kind(return_ty)==KIND_ARRAY && !TY_is_character(return_ty))
03397                   TY2F_translate(temp_tokens,TY_AR_etype(return_ty));
03398                 else
03399                   TY2F_translate(temp_tokens, return_ty);
03400                  }
03401             Append_Token_String(temp_tokens, W2CF_Symtab_Nameof_St(st));
03402             Append_And_Reclaim_Token_List(header_tokens, &temp_tokens);
03403           }
03404      
03405         if (num_params) 
03406               ReorderParms(param_st,num_params-implicit);
03407 
03408         for (param = first_param; param < num_params-implicit ; param++)
03409              if (param_st[param] != NULL) {
03410                 Append_F77_Indented_Newline(header_tokens, 1, NULL/*label*/);
03411                 ST2F_decl_translate(header_tokens, param_st[param]);
03412                 if (ST_is_optional_argument(param_st[param])) {
03413                    Append_F77_Indented_Newline(header_tokens, 1, NULL/*label*/);
03414                    Append_Token_String(header_tokens,"OPTIONAL ");
03415                    Append_Token_String(header_tokens,
03416                                      W2CF_Symtab_Nameof_St(param_st[param]));
03417                   }
03418                 if (ST_is_intent_in_argument(param_st[param])) {
03419                    Append_F77_Indented_Newline(header_tokens, 1, NULL/*label*/);
03420                    Append_Token_String(header_tokens,"INTENT(in) ");
03421                    Append_Token_String(header_tokens,
03422                                       W2CF_Symtab_Nameof_St(param_st[param]));
03423                   }
03424                 if (ST_is_intent_out_argument(param_st[param])) {
03425                    Append_F77_Indented_Newline(header_tokens, 1, NULL/*label*/);
03426                    Append_Token_String(header_tokens,"INTENT(out) ");
03427                    Append_Token_String(header_tokens,
03428                                       W2CF_Symtab_Nameof_St(param_st[param]));
03429                   }
03430                }
03431 
03432         Append_Token_Special(header_tokens, '\n');
03433         Append_F77_Indented_Newline(header_tokens, 0, NULL);
03434    
03435         if (return_ty != (TY_IDX) 0 && TY_kind(return_ty) != KIND_VOID)
03436              /* function */
03437              Append_Token_String(header_tokens, "END FUNCTION");
03438         else /* subroutine */
03439                 Append_Token_String(header_tokens, "END SUBROUTINE");
03440          }
03441   
03442         Append_Token_Special(header_tokens, '\n');
03443         Append_F77_Indented_Newline(tokens, 0, NULL);
03444         Append_And_Reclaim_Token_List(tokens, &header_tokens);
03445        }
03446      Decrement_Indentation();
03447      Append_F77_Indented_Newline(tokens, 1/*empty-lines*/, NULL/*label*/);
03448      Append_Token_String(tokens, "end interface ");
03449      Append_F77_Indented_Newline(tokens, 1/*empty-lines*/, NULL/*label*/);
03450      return EMPTY_WN2F_STATUS;
03451 
03452 } //WN2F_interface_blk
03453 
03454 
03455 
03456 WN2F_STATUS
03457 WN2F_ar_construct(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
03458 {
03459   INT kid;
03460   
03461    Append_Token_Special(tokens,'(');
03462    Append_Token_Special(tokens,'/');
03463    for (kid = 0; kid < WN_kid_count(wn); kid++) {
03464 
03465       (void)WN2F_translate(tokens,WN_kid(wn,kid), context);
03466       if (kid < WN_kid_count(wn)-1)
03467          Append_Token_Special(tokens,',');
03468     }
03469 
03470 
03471    Append_Token_Special(tokens,'/');
03472    Append_Token_Special(tokens,')');
03473 
03474    return EMPTY_WN2F_STATUS;
03475  
03476 }
03477 
03478 WN2F_STATUS
03479 WN2F_noio_implied_do(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
03480 {
03481    INT kid;
03482    INT numkids = 5;
03483    Append_Token_Special(tokens,'(');
03484    (void)WN2F_translate(tokens,WN_kid0(wn),context);
03485    Append_Token_Special(tokens,',');
03486    (void)WN2F_translate(tokens,WN_kid1(wn),context);
03487    Append_Token_Special(tokens,'=');
03488    
03489    for (kid = 2;kid<numkids; kid++) {
03490       (void)WN2F_translate(tokens,WN_kid(wn,kid),context);
03491      if (kid < numkids-1)
03492        Append_Token_Special(tokens,',');
03493     }
03494 
03495    Append_Token_Special(tokens,')');
03496    return EMPTY_WN2F_STATUS;
03497 } //WN2F_noio_implied_do
03498 
03499 WN2F_STATUS
03500 WN2F_idname(TOKEN_BUFFER tokens, WN *wn, WN2F_CONTEXT context)
03501 { 
03502   const char *st_name;
03503   ASSERT_DBG_FATAL(WN_operator(wn) == OPR_IDNAME,
03504                  (DIAG_W2F_UNEXPECTED_OPC, "WN2F_idname"));
03505    st_name = W2CF_Symtab_Nameof_St(WN_st(wn));
03506    Append_Token_String(tokens,st_name);
03507    Set_BE_ST_w2fc_referenced(WN_st(wn));
03508    return EMPTY_WN2F_STATUS;
03509 
03510 } //WN2F_idname
03511 
03512 
03513