• Main Page
  • Modules
  • Data Types
  • Files

osprey/be/com/wn_mp.cxx

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2007. QLogic Corporation. All Rights Reserved.
00003  */
00004 
00005 /*
00006  * Copyright 2003, 2004, 2005, 2006 PathScale, Inc.  All Rights Reserved.
00007  */
00008 
00009 /*
00010 
00011   Copyright (C) 2000, 2001 Silicon Graphics, Inc.  All Rights Reserved.
00012 
00013   This program is free software; you can redistribute it and/or modify it
00014   under the terms of version 2 of the GNU General Public License as
00015   published by the Free Software Foundation.
00016 
00017   This program is distributed in the hope that it would be useful, but
00018   WITHOUT ANY WARRANTY; without even the implied warranty of
00019   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00020 
00021   Further, this software is distributed without any warranty that it is
00022   free of the rightful claim of any third person regarding infringement 
00023   or the like.  Any license provided herein, whether implied or 
00024   otherwise, applies only to this software file.  Patent licenses, if 
00025   any, provided herein do not apply to combinations of this program with 
00026   other software, or any other product whatsoever.  
00027 
00028   You should have received a copy of the GNU General Public License along
00029   with this program; if not, write the Free Software Foundation, Inc., 59
00030   Temple Place - Suite 330, Boston MA 02111-1307, USA.
00031 
00032   Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pky,
00033   Mountain View, CA 94043, or:
00034 
00035   http://www.sgi.com
00036 
00037   For further information regarding this notice, see:
00038 
00039   http://oss.sgi.com/projects/GenInfo/NoticeExplan
00040 
00041 */
00042 
00043 #define __STDC_LIMIT_MACROS
00044 #include <stdint.h>
00045 #ifdef USE_PCH
00046 #include "be_com_pch.h"
00047 #endif /* USE_PCH */
00048 #pragma hdrstop
00049 
00050 /* Header of wn_mp_dg.cxx
00051 *  csc.
00052 */
00053 #include <sys/types.h>
00054 #if defined(BUILD_OS_DARWIN)
00055 #include <darwin_elf.h>
00056 #else /* defined(BUILD_OS_DARWIN) */
00057 #include <elf.h>
00058 #endif /* defined(BUILD_OS_DARWIN) */
00059 
00060 #define USE_STANDARD_TYPES          /* override unwanted defines in "defs.h" */
00061 
00062 #include <bstring.h>
00063 #include "wn.h"
00064 #include "wn_util.h"
00065 #include "erglob.h"
00066 #include "errors.h"
00067 #include "strtab.h"                 /* for strtab */
00068 #include "symtab.h"                 /* for symtab */
00069 #include "irbdata.h"                /* for inito */
00070 #include "dwarf_DST_mem.h"          /* for DST */
00071 #include "pu_info.h"
00072 #ifdef __MINGW32__
00073 #include <WINDOWS.h>
00074 #endif /* __MINGW32__ */
00075 #include "ir_bwrite.h"
00076 #include "ir_reader.h"
00077 #include "ir_bcom.h"
00078 #include "region_util.h"            /* for RID */
00079 #include "dep_graph.h"
00080 #include "cxx_hash.h"
00081 #include "wn_mp.h"        /* for wn_mp_dg.cxx's extern functions */
00082 
00083 /* wn_mp_dg.cxx header end.
00084 *  csc.
00085 */
00086 
00087 #include <string.h>
00088 
00089 #if ! defined(BUILD_OS_DARWIN)
00090 #include <elf.h>
00091 #endif /* ! defined(BUILD_OS_DARWIN) */
00092 #include "alloca.h"
00093 #include "cxx_template.h"
00094 #include "defs.h"
00095 #include "glob.h"
00096 #include "errors.h"
00097 #include "erglob.h"
00098 #include "erbe.h"
00099 #include "tracing.h"
00100 #include "strtab.h"
00101 
00102 #include "symtab.h"
00103 
00104 #include "wn.h"
00105 #include "wn_util.h"
00106 #include "wn_simp.h"
00107 #include "stblock.h"
00108 #include "data_layout.h"
00109 #include "targ_sim.h"
00110 #include "targ_const.h"
00111 #include "config_targ.h"
00112 #include "config_asm.h"
00113 #include "const.h"
00114 #include "ttype.h"
00115 #include "wn_pragmas.h"
00116 #include "wn_lower.h"
00117 #include "region_util.h"
00118 #include "wutil.h"
00119 #include "wn_map.h"
00120 #include "pu_info.h"
00121 #include "dwarf_DST.h"
00122 #include "dwarf_DST_producer.h"
00123 #include "dwarf_DST_mem.h"
00124 #include "config.h"
00125 #include "standardize.h"
00126 #include "irbdata.h"
00127 #include "omp_lower.h"
00128 #include "privatize_common.h"
00129 #include "cxx_hash.h"
00130 #include "wn_mp.h"
00131 #include "mempool.h"
00132 #include "parmodel.h" // for NOMINAL_PROCS
00133 #include "fb_info.h"
00134 #include "fb_whirl.h"
00135 #include "be_symtab.h"
00136 #ifdef KEY
00137 #include "wn_lower.h"
00138 #include "config_opt.h"
00139 #endif
00140 
00141 /*
00142 MP lowerer cleanup TODO by DRK:
00143 
00144 1.  Convert all the tables (LABEL, VAR, etc.) to BOUNDSCHECKED_VECTOR's,
00145 put BOUNDSCHECKED_VECTOR into cxx_template.h
00146 
00147 2.  Define class for entering/exiting a PU's scope such that global
00148 vars CURRENT_SYMTAB, Current_pu, Current_Map_Tab, and Current_PU_Info
00149 are managed automatically (stack discipline seems appropriate)
00150 
00151 3.  New global utility function for defining function prototype TY's
00152 
00153 4.  Delete "unused function"'s when debugging is done
00154 
00155 5.  Make sure we use ST * and TY * instead of IDX's where possible
00156 
00157 6.  MP_Reduction_Combine_Cycles() should use targ_info or something for
00158 machine cycle time and runtime costs.
00159 */
00160 
00161 
00162 #define WN_Compare_Trees(x,y) (WN_Simp_Compare_Trees(x,y))
00163 
00164 static DST_INFO_IDX  nested_dst;
00165 #ifdef KEY
00166 static void
00167 Transfer_Maps ( WN_MAP_TAB * parent, WN_MAP_TAB * child, WN * tree,
00168                 RID * root_rid );
00169 #endif
00170 /*
00171 * Add csc debug support
00172 */
00173 void csc_printf(const char *what, INT line)
00174 {
00175      printf("csc: %s at wn_mp.cxx: %d .\n", what, line );
00176 }
00177 
00178 #define csc_debug(x) csc_printf(x,__LINE__)
00179 
00180 inline WN_OFFSET WN_offsetx ( WN *wn )
00181 {
00182   OPERATOR opr;
00183   opr = WN_operator(wn);
00184   if ((opr == OPR_PRAGMA) || (opr == OPR_XPRAGMA)) {
00185     return (WN_pragma_arg1(wn));
00186   } else {
00187     return (WN_offset(wn));
00188   }
00189 }
00190 
00191 inline void WN_set_offsetx ( WN *wn, WN_OFFSET ofst )
00192 {
00193   OPERATOR opr;
00194   opr = WN_operator(wn);
00195   if ((opr == OPR_PRAGMA) || (opr == OPR_XPRAGMA)) {
00196     WN_pragma_arg1(wn) = ofst;
00197   } else {
00198     WN_offset(wn) = ofst;
00199   }
00200 }
00201 
00202 static inline TYPE_ID Promote_Type(TYPE_ID mtype)
00203 {
00204   switch (mtype) {
00205     case MTYPE_I1 : case MTYPE_I2: return(MTYPE_I4);
00206     case MTYPE_U1 : case MTYPE_U2: return(MTYPE_U4);
00207     default: return mtype;
00208   }
00209 }
00210 
00211 static void
00212 my_Get_Return_Pregs(PREG_NUM *rreg1, PREG_NUM *rreg2, mTYPE_ID type,
00213                     const char *file, INT line)
00214 {
00215   if (WHIRL_Return_Info_On) {
00216     RETURN_INFO return_info = Get_Return_Info(Be_Type_Tbl(type),
00217                                               Use_Simulated);
00218     if (RETURN_INFO_count(return_info) <= 2) {
00219       *rreg1 = RETURN_INFO_preg(return_info, 0);
00220       *rreg2 = RETURN_INFO_preg(return_info, 1);
00221     } else
00222       Fail_FmtAssertion("file %s, line %d: more than 2 return registers",
00223                         file, line);
00224 
00225   } else
00226     Get_Return_Pregs(type, MTYPE_UNKNOWN, rreg1, rreg2);
00227 
00228   FmtAssert(*rreg1 != 0 && *rreg2 == 0, ("bad return pregs"));
00229 } // my_Get_Return_Pregs()
00230 
00231 #define GET_RETURN_PREGS(rreg1, rreg2, type) \
00232   my_Get_Return_Pregs(&rreg1, &rreg2, type, __FILE__, __LINE__)
00233 
00234 typedef enum {
00235 
00236   MPRUNTIME_NONE = 0,
00237   MPRUNTIME_FIRST = 1,
00238 
00239     MPR_SETUP                = 1,
00240     MPR_CLEANUP              = 2,
00241 
00242     MPR_GETLOCK              = 3,
00243     MPR_UNLOCK               = 4,
00244     MPR_BARRIER              = 5,
00245     MPR_SETLOCK              = 6,
00246     MPR_UNSETLOCK            = 7,
00247 
00248     MPR_COPYIN               = 8,
00249 
00250     MPR_PARALLEL_DO_32       = 9,
00251     MPR_PARALLEL_DO_64       = 10,
00252     MPR_PARALLEL_REGION      = 11,
00253 
00254     MPR_BEGIN_PDO_32         = 12,
00255     MPR_BEGIN_PDO_64         = 13,
00256     MPR_NEXT_ITERS_32        = 14,
00257     MPR_NEXT_ITERS_64        = 15,
00258     MPR_END_PDO              = 16,
00259 
00260     MPR_BEGIN_SINGLE_PROCESS = 17,
00261     MPR_END_SINGLE_PROCESS   = 18,
00262 
00263     MPR_ENTER_GATE           = 19,
00264     MPR_EXIT_GATE            = 20,
00265 
00266     MPR_BEGIN_INDEPENDENT    = 21,
00267     MPR_END_INDEPENDENT      = 22,
00268 
00269     MPR_MY_THREADNUM         = 23,
00270 
00271   MPR_OMP_PARALLEL_REGION    = 24,
00272   MPR_OMP_BEGIN_SPR          = 25,      /* serialized parallel region */
00273   MPR_OMP_END_SPR            = 26,
00274   MPR_OMP_PARALLEL_DO_32     = 27,
00275   MPR_OMP_PARALLEL_DO_64     = 28,
00276   
00277   MPR_OMP_BEGIN_PDO_64         = 29,
00278   MPR_OMP_NEXT_ITERS_64        = 30,
00279   MPR_OMP_END_PDO              = 31,
00280 
00281   MPR_OMP_BEGIN_SINGLE_PROCESS = 32,
00282   MPR_OMP_END_SINGLE_PROCESS   = 33,
00283   MPR_OMP_BARRIER_OLD          = 34, /* conflict with new API */
00284 
00285   MPR_OMP_PDO_ORDERED_BEGIN    = 35,
00286   MPR_OMP_PDO_ORDERED_END      = 36,
00287   MPR_OMP_ORDERED_BEGIN_OLD    = 37, /* conflict with new API */
00288   MPR_OMP_ORDERED_END_OLD      = 38, /* conflict with new API */
00289 
00290   MPR_OMP_COPYIN               = 39,
00291   MPR_OMP_NONPOD_COPYIN        = 40,
00292   MPR_OMP_NONPOD_ARRAY_COPYIN  = 41,
00293 
00294   // Begin KMPC RTL calls.
00295   MPR_OMP_IN_PARALLEL     = 42, /* test if in parallel region */
00296   MPR_OMP_CAN_FORK      = 43, /* test fork, to be eliminated*/
00297   MPR_OMP_SET_NUM_THREADS   = 44, /* for threadnum setting, not used*/
00298   MPR_OMP_INIT_RTL      = 45, /* obsoleted */
00299   MPR_OMP_FINI_RTL      = 46, /* obsoleted */
00300   
00301   MPR_OMP_SERIALIZED_PARALLEL     = 47, /* para-region serialized, can delete */
00302   MPR_OMP_END_SERIALIZED_PARALLEL = 48, /* Can be deleted */
00303   MPR_OMP_GET_THREAD_NUM    = 49,
00304   MPR_OMP_GET_NUM_THREADS   = 50, 
00305 
00306   MPR_OMP_FORK        = 51,
00307 
00308   MPR_OMP_STATIC_INIT_4    = 52,
00309   MPR_OMP_STATIC_INIT_8    = 53,
00310   MPR_OMP_STATIC_FINI      = 54, /* Can be deleted */
00311 
00312   MPR_OMP_SCHEDULER_INIT_4    = 55,
00313   MPR_OMP_SCHEDULER_INIT_8    = 56,
00314   MPR_OMP_SCHEDULER_NEXT_4    = 57,
00315   MPR_OMP_SCHEDULER_NEXT_8    = 58,
00316   
00317   MPR_OMP_SINGLE      = 59,
00318   MPR_OMP_END_SINGLE      = 60,
00319 
00320   MPR_OMP_MASTER      = 61,
00321   MPR_OMP_END_MASTER      = 62,
00322   
00323   MPR_OMP_BARRIER     = 63,
00324 
00325   MPR_OMP_CRITICAL    = 64,
00326   MPR_OMP_END_CRITICAL    = 65,
00327   MPR_OMP_ORDERED   = 66,
00328   MPR_OMP_END_ORDERED   = 67,
00329 
00330   MPR_OMP_FLUSH     = 68, /* Not really needed? to be deleted*/
00331 #ifdef KEY
00332   MPR_OMP_GET_THDPRV            = 69,
00333   MPR_OMP_COPYIN_THDPRV         = 70,
00334   MPR_OMP_COPYPRIVATE           = 71,
00335 
00336   MPRUNTIME_LAST = MPR_OMP_COPYPRIVATE
00337 #else
00338   MPRUNTIME_LAST = MPR_OMP_FLUSH
00339 #endif
00340 
00341 } MPRUNTIME;
00342 
00343 
00344   // Schedule type
00345 typedef enum {
00346   OMP_SCHED_UNKNOWN     = 0,
00347   OMP_SCHED_STATIC      = 1,
00348   OMP_SCHED_STATIC_EVEN     = 2,
00349   OMP_SCHED_DYNAMIC     = 3,
00350   OMP_SCHED_GUIDED      = 4,
00351   OMP_SCHED_RUNTIME     = 5,
00352     // Ordered schedule type
00353   OMP_SCHED_ORDERED_STATIC    = 33,
00354   OMP_SCHED_ORDERED_STATIC_EVEN   = 34,
00355   OMP_SCHED_ORDERED_DYNAMIC   = 35,
00356   OMP_SCHED_ORDERED_GUIDED    = 36,
00357   OMP_SCHED_ORDERED_RUNTIME   = 37,
00358  
00359   OMP_SCHED_NORMAL_FIRST  = OMP_SCHED_STATIC,
00360   OMP_SCHED_NORMAL_LAST   = OMP_SCHED_RUNTIME,
00361   OMP_SCHED_ORDERED_FIRST = OMP_SCHED_ORDERED_STATIC,
00362   OMP_SCHED_ORDERED_LAST  = OMP_SCHED_ORDERED_RUNTIME
00363 } SCHEDULE_TYPE;
00364 
00365   // kinds of nested functions generated for parallel constructs
00366 typedef enum {
00367   PAR_FUNC_NONE = 0,
00368   PAR_FUNC_DO32,
00369   PAR_FUNC_DO64,
00370   PAR_FUNC_REGION,
00371   PAR_FUNC_LAST = PAR_FUNC_REGION
00372 } PAR_FUNC_TYPE;
00373 
00374 typedef enum {
00375   VAR_NONE             = 0,
00376   VAR_LASTLOCAL        = 1,
00377   VAR_LOCAL            = 2,
00378     /* FIRSTPRIVATE implies LOCAL for all purposes in MP lowering */
00379   VAR_FIRSTPRIVATE     = 3,
00380   VAR_REDUCTION_SCALAR = 4,
00381   VAR_REDUCTION_ARRAY  = 5,
00382     /* It seems VAR_REDUCTION_ARRAY is used for other 
00383      * usage in original implementation,
00384      * so I define a new one for OpenMP array reduction.
00385      */
00386   VAR_REDUCTION_ARRAY_OMP  = 6
00387 } VAR_TYPE;
00388 
00389 typedef struct {
00390   VAR_TYPE   vtype;
00391   TYPE_ID    mtype;
00392   BOOL       has_offset;
00393   BOOL       is_static_array;
00394   BOOL       is_dynamic_array;
00395     // TRUE iff (vtype == VAR_LASTLOCAL) and variable is also FIRSTPRIVATE
00396   BOOL       is_last_and_firstprivate;
00397   BOOL       is_non_pod;  // C++ object or array of objects
00398                           // "pod" stands for "plain old data"
00399   TY_IDX     ty;
00400   WN        *vtree;
00401   WN        *vtreex;
00402   ST        *orig_st;
00403   WN_OFFSET  orig_offset;
00404   ST        *new_st;
00405   WN_OFFSET  new_offset;
00406   OPERATOR   reduction_opr; /* specified in REDUCTION pragma */
00407   OPCODE     reduction_opc; /* computed from reduction_opr and its operands */
00408 } VAR_TABLE;
00409 
00410 typedef enum {
00411   PCLASS_UNKNOWN        = 0,
00412   PCLASS_DEADIN_DEADOUT = 1,
00413   PCLASS_COPYIN_DEADOUT = 2,
00414   PCLASS_DEADIN_COPYOUT = 3,
00415   PCLASS_COPYIN_COPYOUT = 4,
00416   PCLASS_LIVEIN_DEADOUT = 5,
00417   PCLASS_DEADIN_LIVEOUT = 6,
00418   PCLASS_LIVEIN_LIVEOUT = 7 
00419 } PREG_CLASS;
00420 
00421 typedef struct {
00422   PREG_CLASS  pclass;
00423   TYPE_ID     type;
00424   BOOL        preamble_store;
00425   BOOL        lastlocal_list;
00426   BOOL        local_list;
00427   BOOL        reduction_list;
00428   BOOL        shared_list;
00429   INT32       shared_flags;
00430   ST          *temp;
00431 } PREG_INFO;
00432 
00433 typedef LABEL_IDX LABEL_INFO_TABLE;
00434 
00435 typedef ST * SHARED_TABLE;
00436 
00437 typedef INT32 MPID_TABLE;
00438 
00439 typedef HASH_TABLE<WN *, BOOL> WN_TO_BOOL_HASH;
00440 static const mINT32 NUM_HASH_ELEMENTS = 1021;
00441 
00442 /*
00443 Template for simple fixed-size vector with bounds-checking (if compiled for
00444 debugging).  Why did we have to re-invent the wheel here?  Because neither
00445 the old classes in cxx_template.cxx nor the new STL classes have precisely
00446 this functionality.
00447 */
00448 
00449 template<class T>
00450 class BOUNDSCHECKED_VECTOR {
00451   T *array;
00452   mUINT32 size;
00453   MEM_POOL *mempool;
00454   typedef BOUNDSCHECKED_VECTOR<T> *PV;
00455   BOOL zero_is_invalid; // index 0 is invalid (for e.g. PREG_IDX)
00456   PV *ppv;  // external pointer to "this"; invalidate upon destruction
00457 public:
00458   BOUNDSCHECKED_VECTOR(MEM_POOL *_mempool, mUINT32 _size,
00459                        BOOL _zero_is_invalid = FALSE, PV *_ppv = NULL)
00460     : mempool(_mempool), size(_size), zero_is_invalid(_zero_is_invalid),
00461       ppv(_ppv) {
00462       array = CXX_NEW_ARRAY(T, size, mempool);
00463       if (ppv)
00464         *ppv = this;
00465   }
00466   T &operator[](mINT32 idx) {
00467 #ifdef Is_True_On
00468     if (idx < 0)
00469       Fail_FmtAssertion("BOUNDSCHECKED_VECTOR::operator[] : negative index "
00470                         "%d", idx);
00471     if (idx == 0 && zero_is_invalid)
00472       Fail_FmtAssertion("BOUNDSCHECKED_VECTOR::operator[] : invalid zero "
00473                         "index");
00474     if (idx >= size)
00475       Fail_FmtAssertion("BOUNDSCHECKED_VECTOR::operator[] : out-of-bounds "
00476                         "index %d (array size is %d)", idx, size);
00477 #endif
00478     return array[idx];
00479   }
00480     // so we can say: pv->at(idx)
00481   T &at(mINT32 idx) { return (*this)[idx]; }
00482   mUINT32 Size() const { return size; }
00483   ~BOUNDSCHECKED_VECTOR() {
00484     CXX_DELETE_ARRAY(array, mempool);
00485     if (ppv)
00486       *ppv = NULL;
00487   }
00488 };
00489 
00490 static BOOL first_call = TRUE;  // first call to wn_lower()
00491 static MEM_POOL mp_lower_pool;  // for lower_mp() temporaries
00492 
00493 static WN *stmt_block;    /* Original statement nodes */
00494 static WN *serial_stmt_block; /* Serial statement nodes */
00495 static WN *cont_nodes;    /* Statement nodes after mp code */
00496 static WN *do_node;   /* Do loop node for parallel do */
00497 static WN *replace_block; /* Replacement nodes to be returned */
00498 static WN *ntrip_calc;    /* Ntrip calculation code */
00499 static WN *livein_block;  /* Livein code for mp call */
00500 static WN *alloca_block;  /* Alloca code for mp routine */
00501 static WN *copyin_block;  /* Copyin code for mp call */
00502 static WN *copyout_block; /* Copyout code for mp call */
00503 static WN *firstprivate_block;  /* FIRSTPRIVATE code for mp call */
00504 static WN *liveout_block; /* Liveout code for mp call */
00505 static WN *do_prefix;   /* Prefix code for do loop */
00506 static WN *do_suffix;   /* Suffix code for do loop */
00507 static WN *if_preamble_block; /* MP if preamble block */
00508 static WN *if_postamble_block;  /* MP if postamble block */
00509 static WN *do_preamble_block; /* Do preamble block */
00510 static INT64 line_number; /* Line number of parallel do/region */
00511 
00512 static ST *parallel_proc; /* Extracted parallel process */
00513 static ST *local_start;   /* Parallel Do local start, obsolete */
00514 static ST *local_ntrip;   /* Parallel Do local ntrip, obsolete */
00515 static ST *thread_info;   /* Parallel Do thread info, obsolete */
00516 static ST *local_upper = NULL;   /* Parallel Do local upper bound */
00517 static ST *local_lower = NULL;   /* Parallel Do local lower bound */
00518 static ST *local_stride = NULL;  /* Parallel Do local stride for next chunk */
00519 static ST *last_iter;      /* Is local execute last iteration? */
00520 static ST *local_limit;   /* Parallel Do local limit */
00521 static ST *limit_st;      /* Temp var to store do_limit. can be preg. */
00522 static WN_OFFSET limit_ofst;
00523 static ST *local_gtid;    /* Microtask local gtid */
00524 static ST *local_btid;    /* Microtask local btid */
00525 static WN *base_node;     /* Parallel do base */
00526 static WN *limit_node = NULL;   /* Parallel do limit */
00527 static WN *ntrip_node;    /* Parallel do trip count */
00528 static WN *stride_node;   /* Parallel do stride */
00529 static WN *parallel_func; /* Parallel do function */
00530 static FEEDBACK *parallel_pu_fb;  /* Feedback for parallel function */
00531 static WN *reference_block; /* Parallel funciton reference block */
00532 static INT32 func_level;  /* Parallel function stab level */
00533 static ST *do_index_st;   /* User do index variable ST */
00534 static TYPE_ID do_index_type; /* User do index variable type */
00535 static BOOL fast_doacross;  /* Flag if doacross meets fastpath requirement*/
00536 
00537 static INT32 copyin_count;  /* Count of copyins */
00538 static INT32 local_count; /* Count of lastlocals, locals, firstprivates
00539            & reductions */
00540 static INT32 reduction_count; /* Count of reductions */
00541 static INT32 shared_count;  /* Count of shareds, lastlocals & reductions */
00542 static WN *affinity_nodes;  /* Points to (optional) affinity nodes */
00543 static WN *affinity_d_nodes;  /* Points to (optional) affinity data nodes */
00544 static WN *affinity_t_nodes;  /* Points to (optional) affinity thread nodes */
00545 static WN *chunk_node;    /* Points to (optional) chunk node */
00546 static WN *copyin_nodes;  /* Points to (optional) copyin nodes */
00547 static WN *copyin_nodes_end;  /* Points to (optional) copyin nodes end */
00548 static WN *if_node;   /* Points to (optional) if node */
00549 static WN *lastlocal_nodes; /* Points to (optional) lastlocal nodes */
00550 static WN *lastthread_node; /* Points to (optional) lastthread node */
00551 static WN *local_nodes;   /* Points to (optional) local nodes */
00552 static WN *firstprivate_nodes;  /* Points to (optional) firstprivate nodes */
00553                                 // frontend-generated finalization code for
00554                                 // non-POD lastlocals
00555 static WN *non_pod_finalization_nodes;
00556                                 // firstprivate and lastprivate appear on same
00557                                 // non-POD ST
00558 static BOOL non_pod_first_and_lastprivate;
00559 static WN *mpnum_node;    /* Points to (optional) mpnum node */
00560 static WN *mpsched_node;  /* Points to (optional) mpsched node */
00561 static WN *numthreads_node; /* Points to (optional) numthreads node */
00562 static WN *ordered_node;  /* Points to (optional) ordered node */
00563 static WN *do_order_lb = NULL; /* store lb and stride of an ordered parallel */
00564 static WN *do_order_stride = NULL; /* loop, passed to omp-pdo-ordered calls */
00565 static WN *reduction_nodes; /* Points to (optional) reduction nodes */
00566 static WN *shared_nodes;  /* Points to (optional) shared nodes */
00567 
00568 static INT32 num_constructs;     /* Number of parallel constructs */
00569 static INT32 nested_local_count;   /* Nested count of lastlocals, locals, &
00570               firstprivates */
00571 static INT32 nested_reduction_count; /* Nested count of reductions */
00572 static WN *nested_affinity_nodes;  /* Points to (nested) affinity nodes */
00573 static WN *nested_affinity_d_nodes;/* Points to (nested) affin. data nodes */
00574 static WN *nested_affinity_t_nodes;/* Points to (nested) affin. thread nodes */
00575 static WN *nested_chunk_node;    /* Points to (nested) chunk node */
00576 static WN *nested_lastlocal_nodes; /* Points to (nested) lastlocal nodes */
00577 static WN *nested_lastthread_node; /* Points to (nested) lastthread node */
00578 static WN *nested_local_nodes;     /* Points to (nested) local nodes */
00579 static WN *nested_firstprivate_nodes; /* Points to (nested) firstprivate
00580            nodes */
00581 static WN *nested_mpsched_node;    /* Points to (nested) mpsched node */
00582 static WN *nested_nowait_node;     /* Points to (nested) nowait node */
00583 static WN *nested_ordered_node;    /* Points to (nested) ordered node */
00584 static WN *nested_do_order_lb = NULL; /* store lb and stride of an ordered */
00585 static WN *nested_do_order_stride = NULL; /* parallel loop */
00586 static WN *nested_reduction_nodes; /* Points to (nested) reduction nodes */
00587 static WN *nested_shared_nodes;    /* Points to (nested) shared nodes */
00588 
00589 static VAR_TABLE *var_table;      /* Table of variable substitutions */
00590 static VAR_TABLE *nested_var_table; /* Table of nested variable substitutions */
00591 
00592 typedef BOUNDSCHECKED_VECTOR<PREG_INFO> PREG_INFO_TABLE;
00593 PREG_INFO_TABLE *preg_info_table;   /* Table of preg information */
00594 
00595 static LABEL_INFO_TABLE *label_info_table;    /* Mapping from parent to
00596                                                  nested PU labels */
00597 static SHARED_TABLE *shared_table;  /* Table of shared ST's */
00598 static MPID_TABLE *mpid_table;      /* Table of assigned mpid's */
00599 
00600 static INT32 mpid_size = 0;     /* Size of mpid_table */
00601 
00602   // Generic types for nested parallel functions
00603 static TY_IDX mpdo32_ty = TY_IDX_ZERO;
00604 static TY_IDX mpdo64_ty = TY_IDX_ZERO;
00605 static TY_IDX mpregion_ty = TY_IDX_ZERO;
00606   // Generic type for parallel runtime routines
00607 static TY_IDX mpruntime_ty = TY_IDX_ZERO;
00608 
00609 static ST_IDX last_pu_proc_sym = ST_IDX_ZERO; // last PU we compiled
00610 static INT32 do_id = 0;     // Unique do number within PU
00611 static INT32 region_id = 0;   // Unique region number within PU
00612 static INT32 lock_id = 0;   // Unique lock number within PU
00613 static WN *pu_chunk_node = NULL;        // (optional) PU chunk node
00614 static WN *pu_mpsched_node = NULL;      // (optional) PU mpsched node
00615 
00616   // ST's for compiler-generated temporaries
00617 static ST *mpbase_st = NULL;    /* ST for local iteration base */
00618 static ST *mptrips_st = NULL;   /* ST for local iteration trips */
00619 static ST *mpflags_st = NULL;   /* ST for local iteration flags */
00620 
00621 static BOOL pu_has_eh = FALSE;    /* Parent PU contains EH region */
00622 
00623 static SYMTAB_IDX psymtab;  /* Parent symbol table */
00624 static SYMTAB_IDX csymtab;  /* Child symbol table */
00625 static PU_Info *ppuinfo;  /* Parent PU info structure */
00626 static WN_MAP_TAB *pmaptab; /* Parent map table */
00627 static WN_MAP_TAB *cmaptab; /* Child map table */
00628 
00629 static BOOL pu_has_alloca;  /* PU contains alloca */
00630 static BOOL pu_has_region;  /* PU contains region */
00631 
00632 static BOOL inside_versioning_if; /* root node of tree being lowered is the
00633                                      MP_IF test for LNO versioning */
00634 
00635   // TRUE if MP region we're currently processing has the compiler-
00636   // generated flag set on its first pragma (the one that identifies it
00637   // as a PARALLEL_REGION, PDO, etc.), FALSE otherwise
00638 static BOOL comp_gen_construct;
00639 
00640   // What kind of construct we're lowering.  We don't distinguish among
00641   // most of the simpler types. Note that mpt is set according to the
00642   // outermost construct by lower_mp (say, to MPP_PARALLEL_REGION), and
00643   // when we reach an inner construct (say, MPP_PDO) we save the old value
00644   // of mpt, set it to something appropriate for the inner construct until
00645   // we're done processing that construct, then restore the old value of mpt.
00646 static MP_process_type mpt;
00647 
00648   // Type and ST for intel openmp runtime library calls
00649   // csc.
00650 static ST * gtid_st = NULL;     /* ST for global thread number */
00651 static TY_IDX lock_ty_idx = TY_IDX_ZERO;  /* Type index for lock */
00652 static ST *old_gtid_st = NULL;
00653 
00654   // To add unnamed_lock_st for unnamed lock and critical_lock_not_init (lg)
00655 static ST *unnamed_lock_st = NULL;         /* ST for unnamed lock */
00656 static BOOL critical_lock_not_init = TRUE; /* for uninitialized critical lock */
00657 
00658 /*  This table contains the external names of all MP runtime routines.  */
00659 
00660 static const char *mpr_names [MPRUNTIME_LAST + 1] = {
00661   "",       /* MPRUNTIME_NONE */
00662   "__mp_setup",     /* MPR_SETUP */
00663   "__mp_cleanup",   /* MPR_CLEANUP */
00664   "__mp_getlock",   /* MPR_GETLOCK */
00665   "__mp_unlock",    /* MPR_UNLOCK */
00666   "__mp_barrier",   /* MPR_BARRIER */
00667   "mp_setlock",     /* MPR_SETLOCK */
00668   "mp_unsetlock",   /* MPR_UNSETLOCK */
00669   "__mp_copyin",    /* MPR_COPYIN */
00670   "__mp_parallel_do",   /* MPR_PARALLEL_DO_32 */
00671   "__mp_parallel_do_64",  /* MPR_PARALLEL_DO_64 */
00672   "__mp_region",    /* MPR_PARALLEL_REGION */
00673   "__mp_begin_pdo",   /* MPR_BEGIN_PDO_32 */
00674   "__mp_begin_pdo_64",    /* MPR_BEGIN_PDO_64 */
00675   "__mp_next_iters",    /* MPR_NEXT_ITERS_32 */
00676   "__mp_next_iters_64",   /* MPR_NEXT_ITERS_64 */
00677   "__mp_end_pdo",   /* MPR_END_PDO */
00678   "__mp_begin_single_process",  /* MPR_BEGIN_SINGLE_PROCESS */
00679   "__mp_end_single_process",  /* MPR_END_SINGLE_PROCESS */
00680   "__mp_enter_gate_new",  /* MPR_ENTER_GATE */
00681   "__mp_exit_gate_new",   /* MPR_EXIT_GATE */
00682   "__mp_begin_single_process",  /* MPR_BEGIN_INDEPENDENT */
00683   NULL,                       /* MPR_END_INDEPENDENT */
00684   "mp_my_threadnum",            /* MPR_MY_THREADNUM */
00685   "__omp_region",               /* MPR_OMP_PARALLEL_REGION */
00686   "__omp_begin_spr",            /* MPR_OMP_BEGIN_SPR */
00687   "__omp_end_spr",              /* MPR_OMP_END_SPR */
00688   "__omp_parallel_do",          /* MPR_OMP_PARALLEL_DO_32 */
00689   "__omp_parallel_do_64",       /* MPR_OMP_PARALLEL_DO_64 */
00690   "__omp_begin_pdo_64",   /* MPR_OMP_BEGIN_PDO_64 */
00691   "__omp_next_iters_64",  /* MPR_OMP_NEXT_ITERS_64 */
00692   "__omp_end_pdo",    /* MPR_OMP_END_PDO */
00693   "__omp_begin_single_process", /* MPR_OMP_BEGIN_SINGLE_PROCESS */
00694   "__omp_end_single_process", /* MPR_OMP_END_SINGLE_PROCESS */
00695   "__omp_barrier",    /* MPR_OMP_BARRIER_OLD */
00696   "__omp_pdo_ordered_begin",  /* MPR_OMP_PDO_ORDERED_BEGIN */
00697   "__omp_pdo_ordered_end",  /* MPR_OMP_PDO_ORDERED_END */
00698   "__omp_begin_ordered",  /* MPR_OMP_ORDERED_BEGIN_OLD */
00699   "__omp_end_ordered",          /* MPR_OMP_ORDERED_END_OLD */
00700   "__omp_copyin",   /* MPR_OMP_COPYIN */
00701   "__omp_nonpod_copyin",  /* MPR_OMP_COPYIN */
00702   "__omp_nonpod_array_copyin",  /* MPR_OMP_COPYIN */
00703   "__ompc_in_parallel",   /* ORC-OpenMP API: MPR_OMP_IN_PARALLEL */
00704   "__ompc_can_fork",    /* MPR_OMP_CAN_FORK */
00705   "__ompc_set_num_threads",   /* MPR_OMP_SET_NUM_THREADS */
00706   "__ompc_init_rtl",    /* MPR_OMP_INIT_RTL */
00707   "__ompc_fini_rtl",    /* MPR_OMP_FINI_RTL */
00708   "__ompc_serialized_parallel", /* MPR_OMP_SERIALIZED_PARALLEL */
00709   "__ompc_end_serialized_parallel", /* MPR_OMP_END_SERIALIZED_PARALLEL */
00710   "__ompc_get_local_thread_num",    /* MPR_OMP_GET_THREAD_NUM */
00711   "__ompc_get_num_threads",   /* MPR_OMP_GET_NUM_THREADS */
00712   "__ompc_fork",      /* MPR_OMP_FORK */
00713   "__ompc_static_init_4",     /* MPR_OMP_STATIC_INIT_4 */
00714   "__ompc_static_init_8",     /* MPR_OMP_STATIC_INIT_8 */
00715   "__ompc_static_fini",       /* MPR_OMP_STATIC_FINI */
00716   "__ompc_scheduler_init_4",     /* MPR_OMP_SCHEDULER_INIT_4 */
00717   "__ompc_scheduler_init_8",     /* MPR_OMP_SCHEDULER_INIT_8 */
00718   "__ompc_schedule_next_4",     /* MPR_OMP_SCHEDULER_NEXT_4 */
00719   "__ompc_schedule_next_8",     /* MPR_OMP_SCHEDULER_NEXT_8 */  
00720   "__ompc_single",              /* MPR_OMP_SINGLE */
00721   "__ompc_end_single",          /* MPR_OMP_END_SINGLE */
00722   "__ompc_master",              /* MPR_OMP_MASTER */
00723   "__ompc_end_master",          /* MPR_OMP_END_MASTER */
00724   "__ompc_barrier",             /* MPR_OMP_BARRIER */
00725   "__ompc_critical",            /* MPR_OMP_CRITICAL */
00726   "__ompc_end_critical",        /* MPR_OMP_END_CRITICAL */
00727   "__ompc_ordered",             /* MPR_OMP_ORDERED */
00728   "__ompc_end_ordered",         /* MPR_OMP_ORDERED */
00729   "__ompc_flush",               /* MPR_OMP_FLUSH  */
00730 #ifdef KEY
00731   "__ompc_get_thdprv",          /* MPR_OMP_GET_THDPRV */
00732   "__ompc_copyin_thdprv",       /* MPR_OMP_COPYIN_THDPRV */
00733   "__ompc_copyprivate",         /* MPR_OMP_COPYPRIVATE */
00734 #endif
00735 };
00736 
00737 
00738 /*  This table contains ST_IDX entries entries for each of the MP
00739     runtime routines.  These entries allow efficient sharing of all
00740     calls to a particular runtime routine. */
00741 
00742 static ST_IDX mpr_sts [MPRUNTIME_LAST + 1] = {
00743   ST_IDX_ZERO,   /* MPRUNTIME_NONE */
00744   ST_IDX_ZERO,   /* MPR_SETUP */
00745   ST_IDX_ZERO,   /* MPR_CLEANUP */
00746   ST_IDX_ZERO,   /* MPR_GETLOCK */
00747   ST_IDX_ZERO,   /* MPR_UNLOCK */
00748   ST_IDX_ZERO,   /* MPR_BARRIER */
00749   ST_IDX_ZERO,   /* MPR_SETLOCK */
00750   ST_IDX_ZERO,   /* MPR_UNSETLOCK */
00751   ST_IDX_ZERO,   /* MPR_COPYIN */
00752   ST_IDX_ZERO,   /* MPR_PARALLEL_DO_32 */
00753   ST_IDX_ZERO,   /* MPR_PARALLEL_DO_64 */
00754   ST_IDX_ZERO,   /* MPR_PARALLEL_REGION */
00755   ST_IDX_ZERO,   /* MPR_BEGIN_PDO_32 */
00756   ST_IDX_ZERO,   /* MPR_BEGIN_PDO_64 */
00757   ST_IDX_ZERO,   /* MPR_NEXT_ITERS_32 */
00758   ST_IDX_ZERO,   /* MPR_NEXT_ITERS_64 */
00759   ST_IDX_ZERO,   /* MPR_END_PDO */
00760   ST_IDX_ZERO,   /* MPR_BEGIN_SINGLE_PROCESS */
00761   ST_IDX_ZERO,   /* MPR_END_SINGLE_PROCESS */
00762   ST_IDX_ZERO,   /* MPR_ENTER_GATE */
00763   ST_IDX_ZERO,   /* MPR_EXIT_GATE */
00764   ST_IDX_ZERO,   /* MPR_BEGIN_INDEPENDENT */
00765   ST_IDX_ZERO,   /* MPR_END_INDEPENDENT */
00766   ST_IDX_ZERO,   /* MPR_MY_THREADNUM */
00767   ST_IDX_ZERO,   /* MPR_OMP_PARALLEL_REGION */
00768   ST_IDX_ZERO,   /* MPR_OMP_BEGIN_SPR */
00769   ST_IDX_ZERO,   /* MPR_OMP_END_SPR */
00770   ST_IDX_ZERO,   /* MPR_OMP_PARALLEL_DO_32 */
00771   ST_IDX_ZERO,   /* MPR_OMP_PARALLEL_DO_64 */
00772   ST_IDX_ZERO,   /* MPR_OMP_BEGIN_PDO_64 */
00773   ST_IDX_ZERO,   /* MPR_OMP_NEXT_ITERS_64 */
00774   ST_IDX_ZERO,   /* MPR_OMP_END_PDO */
00775   ST_IDX_ZERO,   /* MPR_OMP_BEGIN_SINGLE_PROCESS */
00776   ST_IDX_ZERO,   /* MPR_OMP_END_SINGLE_PROCESS */
00777   ST_IDX_ZERO,   /* MPR_OMP_BARRIER_OLD */
00778   ST_IDX_ZERO,   /* MPR_OMP_PDO_ORDERED_BEGIN */
00779   ST_IDX_ZERO,   /* MPR_OMP_PDO_ORDERED_END */
00780   ST_IDX_ZERO,   /* MPR_OMP_ORDERED_BEGIN_OLD */
00781   ST_IDX_ZERO,   /* MPR_OMP_ORDERED_END_OLD */
00782   ST_IDX_ZERO,   /* MPR_OMP_COPYIN */
00783   ST_IDX_ZERO,   /* MPR_OMP_NONPOD_COPYIN */
00784   ST_IDX_ZERO,   /* MPR_OMP_NONPOD_ARRAY_COPYIN */
00785   ST_IDX_ZERO,   /* MPR_OMP_IN_PARALLEL */
00786   ST_IDX_ZERO,   /* MPR_OMP_CAN_FORK */
00787   ST_IDX_ZERO,   /* MPR_OMP_SET_NUM_THREADS */
00788   ST_IDX_ZERO,   /* MPR_OMP_INIT_RTL */
00789   ST_IDX_ZERO,   /* MPR_OMP_FINI_RTL */
00790   ST_IDX_ZERO,   /* MPR_OMP_SERIALIZED_PARALLEL */
00791   ST_IDX_ZERO,   /* MPR_OMP_END_SERIALIZED_PARALLEL */
00792   ST_IDX_ZERO,   /* MPR_OMP_GET_THREAD_NUM */
00793   ST_IDX_ZERO,   /* MPR_OMP_GET_NUM_THREADS */
00794   ST_IDX_ZERO,   /* MPR_OMP_FORK */
00795   ST_IDX_ZERO,   /* MPR_OMP_STATIC_INIT_4 */
00796   ST_IDX_ZERO,   /* MPR_OMP_STATIC_INIT_8 */
00797   ST_IDX_ZERO,   /* MPR_OMP_STATIC_FINI */
00798   ST_IDX_ZERO,   /* MPR_OMP_SCHEDULER_INIT_4 */
00799   ST_IDX_ZERO,   /* MPR_OMP_SCHEDULER_INIT_8 */
00800   ST_IDX_ZERO,   /* MPR_OMP_SCHEDULER_NEXT_4 */
00801   ST_IDX_ZERO,   /* MPR_OMP_SCHEDULER_NEXT_8 */
00802   ST_IDX_ZERO,   /* MPR_OMP_SINGLE */
00803   ST_IDX_ZERO,   /* MPR_OMP_END_SINGLE */
00804   ST_IDX_ZERO,   /* MPR_OMP_MASTER */
00805   ST_IDX_ZERO,   /* MPR_OMP_END_MASTER */
00806   ST_IDX_ZERO,   /* MPR_OMP_BARRIER */
00807   ST_IDX_ZERO,   /* MPR_OMP_CRITICAL */
00808   ST_IDX_ZERO,   /* MPR_OMP_END_CRITICAL */
00809   ST_IDX_ZERO,   /* MPR_OMP_ORDERED */
00810   ST_IDX_ZERO,   /* MPR_OMP_END_ORDERED */
00811   ST_IDX_ZERO,   /* MPR_OMP_FLUSH */
00812 #ifdef KEY
00813   ST_IDX_ZERO,   /* MPR_OMP_GET_THDPRV */
00814   ST_IDX_ZERO,   /* MPR_OMP_COPYIN_THDPRV */
00815   ST_IDX_ZERO,   /* MPR_OMP_COPYPRIVATE */
00816 #endif
00817 };
00818 
00819 #define MPSP_STATUS_PREG_NAME "mpsp_status"
00820 #define IS_MASTER_PREG_NAME  "mp_is_master"
00821 
00822 
00823 /*
00824 After returning from lower_mp(), all MP constructs should have been lowered
00825 in both the Whirl tree passed to lower_mp() and the nested PU (if one was
00826 created).  If all MP constructs have been lowered in a Whirl tree, the tree
00827 will contain no MP pragmas, MP IF's, or non-POD finalization IF's.  This
00828 class verifies this post- condition just before returning from lower_mp().
00829 
00830 This class could easily be extended to perform additional verification on
00831 the lowered Whirl.
00832 */
00833 
00834 class Verify_MP_Lowered {
00835   BOOL replace_block_set;
00836   WN *replace_block_start;
00837     // i.e. WN_next() of last node in replace_block
00838   WN *replace_block_sibling;
00839   BOOL nested_pu_set;
00840   WN *nested_pu;
00841 
00842   static void Verify_No_MP(WN *tree);
00843 
00844 public:
00845   Verify_MP_Lowered() : replace_block_set(FALSE), nested_pu_set(FALSE) { }
00846 
00847   void Set_replace_block(WN *replace, WN *sibling) {
00848     Is_True(!replace_block_set, ("Set_replace_block() called already"));
00849     replace_block_set = TRUE;
00850     replace_block_start = replace;
00851     replace_block_sibling = sibling;
00852   }
00853 
00854   void Set_nested_pu_tree(WN *pu) {
00855     Is_True(!nested_pu_set, ("Set_nested_pu_tree() called already"));
00856     nested_pu_set = TRUE;
00857     nested_pu = pu;
00858   }
00859 
00860   void Set_replace_block_and_nested_pu(WN *replace, WN *sibling, WN *pu) {
00861     Is_True(!replace_block_set && !nested_pu_set,
00862             ("replace_block_start and/or nested_pu set already"));
00863     replace_block_set = TRUE;
00864     replace_block_start = replace;
00865     replace_block_sibling = sibling;
00866     nested_pu_set = TRUE;
00867     nested_pu = pu;
00868   }
00869 
00870   ~Verify_MP_Lowered();
00871 };
00872 
00873 /*
00874 Destructor verifies that both the replace_block and nested PU have been set
00875 (either may be NULL), then verifies that neither contains any MP pragmas,
00876 MP IF's, or non-POD finalization IF's.  If compiled without debugging
00877 support, it does nothing.
00878 */
00879 
00880 Verify_MP_Lowered::~Verify_MP_Lowered()
00881 {
00882   Is_True(replace_block_set, ("replace_block_start not set"));
00883   Is_True(nested_pu_set, ("nested_pu not set"));
00884 
00885 #ifdef Is_True_On
00886   for (WN *wn = replace_block_start; wn && wn != replace_block_sibling;
00887        wn = WN_next(wn))
00888     Verify_No_MP(wn);
00889 
00890   if (nested_pu)
00891     Verify_No_MP(nested_pu);
00892 #endif
00893 }
00894 
00895   // Verify that tree contains no MP pragmas or IF's
00896 void Verify_MP_Lowered::Verify_No_MP(WN *tree)
00897 {
00898   WN_ITER *wni = WN_WALK_TreeIter(tree);
00899 
00900   for ( ; wni; wni = WN_WALK_TreeNext(wni)) {
00901     WN *wn = WN_ITER_wn(wni);
00902     OPERATOR opr = WN_operator(wn);
00903 
00904     if ((opr == OPR_PRAGMA || opr == OPR_XPRAGMA) &&
00905         WN_pragmas[WN_pragma(wn)].users & PUSER_MP)
00906       Fail_FmtAssertion("Verify_MP_Lowered: unlowered MP pragma %d, "
00907           "node %#lx, tree %#lx", WN_pragma(wn), (unsigned long) wn,
00908           (unsigned long) tree);
00909 
00910     if (opr == OPR_IF && WN_Is_If_MpVersion(wn))
00911       Fail_FmtAssertion("Verify_MP_Lowered: unlowered MP IF, node %#lx, "
00912           "tree %#lx", (unsigned long) wn, (unsigned long) tree);
00913 
00914     BOOL first_and_last;
00915     if (Is_Nonpod_Finalization_IF(wn, &first_and_last))
00916       Fail_FmtAssertion("Verify_MP_Lowered: unlowered non-POD finalization "
00917                         "IF, node %#lx, tree %#lx",
00918       (unsigned long) wn, (unsigned long) tree);
00919   }
00920 }
00921 
00922 Verify_MP_Lowered *verify_mp_lowered_ptr; // set upon entry to lower_mp()
00923 
00924 
00925 /* Forward function declarations. */
00926 
00927 static WN * Gen_MP_Load_Store ( ST * from_st, WN_OFFSET from_offset,
00928         ST * to_st,   WN_OFFSET to_offset,
00929         BOOL is_dynamic );
00930 
00931 static BOOL Is_NameLock_ST(ST *st);
00932 
00933 ST_IDX Make_MPRuntime_ST ( MPRUNTIME rop );
00934 
00935 #define GET_MPRUNTIME_ST(x) (mpr_sts[x] == ST_IDX_ZERO ? \
00936                              Make_MPRuntime_ST(x) : mpr_sts[x])
00937 
00938 
00939 /*
00940 Utility class for temporarily changing the line_number global variable.
00941 When an object of this class is created, line_number is set to the value
00942 given in the constructor; when the object is destroyed, line_number is
00943 restored to the value it had before the object was created.
00944 */
00945 
00946 class Linenum_Pusher {
00947   INT64 old_line_number;
00948 public:
00949   Linenum_Pusher(INT64 new_line_number) {
00950     if (new_line_number <= 0)
00951       Fail_FmtAssertion(
00952         "Linenum_Pusher::Linenum_Pusher() : invalid line number %lld",
00953         new_line_number);
00954     old_line_number = line_number;
00955     line_number = new_line_number;
00956 //    DevWarn("setting line_number to %ld", new_line_number);
00957   }
00958   ~Linenum_Pusher() { line_number = old_line_number; }
00959 };
00960 
00961 /*
00962 A parameter of Gtid is needed by most function calls to RTL, so the 
00963 calls to get global thread number is needed right after __omp_begin.
00964 The use of gtid is not only meaningful for nested OMP regions. For every
00965 working thread, the gtid is passed by RTL as a parameter at the entrance
00966 of thread function.
00967 So, currently, all gtid out of threads' scope is set to 0, for currently
00968 nested parallelism is not supported. This should be fixed in the future.
00969 now, use local_gtid instead of gtid_st, for the reason of unification of
00970 Transform_Do.
00971 */
00972 static ST *
00973 Create_Gtid_ST( void )
00974 {
00975   if( local_gtid != NULL)
00976     return local_gtid;
00977       // the usage of gtid is not so frequently, so create it as a global var
00978   local_gtid = New_ST(CURRENT_SYMTAB);
00979   ST_Init(local_gtid, Save_Str("__ompv_gtid_s1"), CLASS_VAR, SCLASS_AUTO, 
00980                    EXPORT_LOCAL, MTYPE_To_TY(MTYPE_I4));
00981   return local_gtid;
00982 }
00983 
00984 /*
00985 Create code to get gtid
00986 */
00987 static WN *
00988 Get_Gtid(ST * gtid)
00989 {
00990      // if gtid == NULL, then set gtid = 0, else load the var gtid
00991      // Some RT calls do require a true gtid rather than 0. e.g., barrier.
00992   if( gtid == NULL)
00993   {
00994      return  WN_CreateIntconst( OPC_I4INTCONST, 0); 
00995   }
00996   else
00997   {
00998      return  WN_Ldid( MTYPE_I4, 0, gtid, ST_type( gtid ));
00999   }
01000 }
01001 
01002 /*
01003 The lock type of Intel RTL is an I4 array of size 8. But where to put it?
01004 Does every named lock need a different lock? Remained to be tested.
01005 */
01006 #ifdef TARG_MIPS
01007 #if defined(TARG_SL)
01008 BOOL Is_Target_32bit()
01009 {
01010   return TRUE;
01011 }
01012 #else
01013 BOOL Is_Target_32bit () 
01014 { 
01015   return (Target_ABI == ABI_N32); 
01016  }
01017 #endif
01018 #endif
01019 
01020 static void 
01021 Create_Lock_Type()
01022 {
01023     if( lock_ty_idx != TY_IDX_ZERO )
01024       return;
01025 #ifdef KEY
01026 #ifdef TARG_X8664
01027     if (Is_Target_32bit())
01028       lock_ty_idx = MTYPE_To_TY(MTYPE_I4);
01029     else
01030 #endif
01031       lock_ty_idx = MTYPE_To_TY(MTYPE_I8);
01032 #else
01033        // define lock_ty_idx as an I4 array of size 8
01034     TY& ty = New_TY(lock_ty_idx);
01035     TY_Init(ty, 8*TY_size(MTYPE_To_TY(MTYPE_I4)), KIND_ARRAY,
01036                    MTYPE_UNKNOWN, Save_Str("NAME_LOCK_TY"));
01037     Set_TY_etype(ty, Be_Type_Tbl(MTYPE_I4));
01038 
01039     ARB_HANDLE arb = New_ARB();
01040     ARB_Init(arb, 0, 7, 1);
01041     Set_ARB_dimension(arb,1);
01042     Set_ARB_first_dimen(arb);
01043     Set_ARB_last_dimen(arb);
01044     Set_ARB_const_lbnd(arb);
01045     Set_ARB_lbnd_val(arb, 0);
01046     Set_ARB_const_ubnd(arb);
01047     Set_ARB_ubnd_val(arb, 7);
01048     Set_ARB_const_stride(arb);
01049     Set_ARB_stride_val(arb, 1);
01050 
01051     Set_TY_arb(ty, arb);
01052     Set_TY_align(lock_ty_idx, 8*TY_size(MTYPE_To_TY(MTYPE_I4)));
01053 #endif 
01054 }
01055 
01056 
01057 /*
01058 Generate RT calls to judge if current threads in a parallel region, 
01059 replace original calls to intrisic function mp_in_parallel_region.
01060 */
01061 static WN *
01062 Gen_In_Parallel(void)
01063 {
01064   WN *wn = WN_Create(OPC_I4CALL, 0);
01065   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_IN_PARALLEL);
01066   
01067   WN_Set_Call_Non_Data_Mod(wn);
01068   WN_Set_Call_Non_Data_Ref(wn);
01069   WN_Set_Call_Non_Parm_Mod(wn);
01070   WN_Set_Call_Parm_Ref(wn);
01071   WN_linenum(wn) = line_number;
01072   
01073   return wn;
01074 }
01075 
01076 /*
01077 Generate RT calls to judge if OK to fork. This call should be invocated 
01078 before real fork calls. Original calls to __omp_region do both the judge
01079 and fork job.
01080 */
01081 static WN *
01082 Gen_Can_Fork(void)
01083 {
01084   WN *wn = WN_Create(OPC_I4CALL, 0);
01085   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_CAN_FORK);
01086 
01087   WN_Set_Call_Non_Data_Mod(wn);
01088   WN_Set_Call_Non_Data_Ref(wn);
01089   WN_Set_Call_Non_Parm_Mod(wn);
01090   WN_Set_Call_Parm_Ref(wn);
01091   WN_linenum(wn) = line_number;
01092 
01093   return wn;
01094 }
01095 
01096 /*
01097 Generate RT calls to set thread number, obsoleted, function
01098 Move to fork.
01099 */
01100 static WN *
01101 Gen_Set_Num_Threads( ST * gtid, WN *nThreads)
01102 {
01103   WN *wn = WN_Create(OPC_VCALL, 2);
01104   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_SET_NUM_THREADS);
01105 
01106   WN_Set_Call_Non_Data_Mod(wn);
01107   WN_Set_Call_Non_Data_Ref(wn);
01108   WN_Set_Call_Non_Parm_Mod(wn);
01109   WN_Set_Call_Parm_Ref(wn);
01110   WN_linenum(wn) = line_number;
01111 
01112   WN_kid(wn, 0) = WN_CreateParm(MTYPE_I4, Get_Gtid( gtid ),
01113       Be_Type_Tbl(MTYPE_I4), WN_PARM_BY_VALUE);
01114   WN_kid(wn, 1) = WN_CreateParm(MTYPE_I4, nThreads, Be_Type_Tbl(MTYPE_I4), 
01115                         WN_PARM_BY_VALUE);
01116 
01117   return wn;
01118 }
01119 
01120 /*
01121 Generate RT calls to fork working threads. All fork jobs is done in
01122 the same way. Original implementation uses different strategy
01123 for forking of Parallel region and Parallel DO.
01124 */
01125 static WN *
01126 Gen_Fork (ST *proc, WN *nThreads) 
01127 {
01128   WN * wn;
01129   WN * wnx;
01130   wn = WN_Create(OPC_VCALL, 3 );
01131   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_FORK);
01132 
01133   WN_Set_Call_Non_Data_Mod(wn);
01134   WN_Set_Call_Non_Data_Ref(wn);
01135   WN_Set_Call_Non_Parm_Mod(wn);
01136   WN_Set_Call_Non_Parm_Ref(wn);
01137   WN_Set_Call_Parm_Ref(wn);
01138   WN_linenum(wn) = line_number;
01139 
01140   if (nThreads != NULL)
01141   {
01142     /* num_threads subclause exist for parallel */
01143     WN_kid(wn, 0) = WN_CreateParm(MTYPE_I4, nThreads, 
01144         Be_Type_Tbl(MTYPE_I4), WN_PARM_BY_VALUE);
01145   }
01146   else
01147   {
01148     /* should be set to 0 */
01149     WN_kid(wn, 0) = WN_CreateParm(MTYPE_I4, WN_Intconst (MTYPE_I4, 0),
01150         Be_Type_Tbl(MTYPE_I4), WN_PARM_BY_VALUE);
01151   }
01152 
01153   wnx = WN_Lda( Pointer_type, 0, proc);
01154   WN_kid(wn, 1) = WN_CreateParm(Pointer_type, wnx, 
01155                        WN_ty(wnx), WN_PARM_BY_REFERENCE);
01156   WN *link = WN_LdidPreg( Pointer_type, Frame_Pointer_Preg_Offset);
01157   WN_kid(wn, 2) = WN_CreateParm(Pointer_type, link, WN_ty(link),
01158                      WN_PARM_BY_REFERENCE);
01159 
01160   return wn;
01161 }
01162 
01163 /*
01164 Generate RT calls to initialize RTL. This call should be invocated at the 
01165 beginning of the program. For Profiling only. obsoleted.
01166 */
01167 static WN *
01168 Gen_Init_RTL ()
01169 {
01170   WN *wn = WN_Create(OPC_VCALL, 0);
01171   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_INIT_RTL);
01172 
01173   WN_Set_Call_Non_Data_Mod(wn);
01174   WN_Set_Call_Non_Data_Ref(wn);
01175   WN_Set_Call_Non_Parm_Mod(wn);
01176   WN_Set_Call_Parm_Ref(wn);
01177     //maybe it's not a proper linenum setting
01178   WN_linenum(wn) = line_number;
01179 
01180   return wn;
01181 }
01182  
01183 /*
01184 Generate RT calls to finalize RTL. This call should be invocated at the end
01185 of the program. For Profiling only. obsoleted.
01186 */
01187 static WN *
01188 Gen_Fini_RTL ()
01189 {
01190   WN *wn = WN_Create(OPC_VCALL, 0);
01191   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_FINI_RTL);
01192 
01193   WN_Set_Call_Non_Data_Mod(wn);
01194   WN_Set_Call_Non_Data_Ref(wn);
01195   WN_Set_Call_Non_Parm_Mod(wn);
01196   WN_Set_Call_Parm_Ref(wn);
01197     //maybe it's not a proper linenum setting
01198   WN_linenum(wn) = line_number;
01199 
01200   return wn;
01201 }
01202 
01203 /*
01204 Generate RT calls to get thread no.
01205 */
01206 static WN *
01207 Gen_Get_Thread_Num ()
01208 {
01209   WN *wn = WN_Create(OPC_I4CALL, 0);
01210   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_GET_THREAD_NUM);
01211 
01212   WN_Set_Call_Non_Data_Mod(wn);
01213   WN_Set_Call_Non_Data_Ref(wn);
01214   WN_Set_Call_Non_Parm_Mod(wn);
01215   WN_Set_Call_Parm_Ref(wn);
01216   WN_linenum(wn) = line_number;
01217 
01218   return wn;
01219 }
01220 
01221 /*
01222  * Fill the gtid variable with proper thread no.
01223  * Ideally, this gtid should be in TLS. csc.
01224  */
01225  
01226 static WN *
01227 Gen_Store_Gtid ()
01228 {
01229   WN *block = WN_CreateBlock( );
01230   if( local_gtid == NULL )
01231   {
01232     Create_Gtid_ST( );
01233   }
01234   WN *wn = Gen_Get_Thread_Num();
01235   WN_INSERT_BlockLast( block, wn );
01236   PREG_NUM   rreg1, rreg2;
01237   GET_RETURN_PREGS(rreg1, rreg2, MTYPE_I4);
01238   wn = WN_Stid( MTYPE_I4, 0, local_gtid, ST_type( local_gtid ),
01239              WN_LdidPreg ( MTYPE_I4, rreg1 ));
01240   WN_linenum(wn) = line_number;
01241   WN_INSERT_BlockLast( block, wn );
01242   
01243   return block;
01244 }
01245 
01246 /*
01247 * The usable version of Set number of threads. obsoleted.
01248 */
01249 static WN *
01250 Set_Thread_Num( WN *nThreads )
01251 {
01252   WN *block = WN_CreateBlock();
01253   WN_INSERT_BlockLast( block, Gen_Store_Gtid());
01254   WN_INSERT_BlockLast( block, 
01255       Gen_Set_Num_Threads( local_gtid, nThreads ));
01256 
01257   return block;
01258 }
01259 
01260 /*
01261 Generate RT calls to get number of total threads.
01262 */
01263 static WN *
01264 Gen_Get_Num_Threads()
01265 {
01266   WN *wn = WN_Create(OPC_I4CALL, 0);
01267   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_GET_NUM_THREADS);
01268 
01269   WN_Set_Call_Non_Data_Mod(wn);
01270   WN_Set_Call_Non_Data_Ref(wn);
01271   WN_Set_Call_Non_Parm_Mod(wn);
01272   WN_Set_Call_Parm_Ref(wn);
01273   WN_linenum(wn) = line_number;
01274 
01275   return wn;
01276 }
01277 
01278 /*
01279 Generate RT calls to serialize parallel region
01280 KEY: gtid is not used, the function call does not take any argument
01281 
01282 The OMP_SERIALIZED library calls are made to inform the runtime library
01283 that we are "inside" a parallel region although we are executing the 
01284 optimized serial version of the parallel region. Do this if we are really
01285 "inside" the parallel region and not if "if (false)" prohibits parallel
01286 execution (bug 5467).
01287 */
01288 
01289 #if defined(KEY) && defined(Is_True_On)
01290 // debug variable
01291 static BOOL serialized_parallel_in_cond = FALSE;
01292 #endif // KEY && Is_True_On
01293 
01294 #ifdef KEY
01295 static WN * serial_test;
01296 #endif // KEY
01297 
01298 static WN *
01299 Gen_Serialized_Parallel (ST *gtid)
01300 {
01301 #ifdef KEY
01302   WN *wn = WN_Create(OPC_VCALL, 0);
01303 #else
01304   WN *wn = WN_Create(OPC_VCALL, 1);
01305 #endif
01306   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_SERIALIZED_PARALLEL);
01307   
01308   WN_Set_Call_Non_Data_Mod(wn);
01309   WN_Set_Call_Non_Data_Ref(wn);
01310   WN_Set_Call_Non_Parm_Mod(wn);
01311   WN_Set_Call_Parm_Ref(wn);
01312   WN_linenum(wn) = line_number;
01313 
01314 #ifdef KEY
01315   serial_test = NULL;
01316 
01317   if (if_node) // if_node is an XPRAGMA
01318   {
01319 #ifdef Is_True_On
01320     Is_True (!serialized_parallel_in_cond, 
01321              ("Did we forget to end our previous serialized_parallel?"));
01322 
01323     serialized_parallel_in_cond = TRUE;
01324 #endif // Is_True_On
01325 
01326     // clone if-compare tree
01327     WN * if_test = WN_COPY_Tree (WN_kid0 (if_node));
01328 
01329     // temporary symbol to store if-compare test
01330     ST * cmp = Gen_Temp_Symbol (MTYPE_TO_TY_array[WN_rtype (if_test)],
01331                                   "test_serial");
01332     
01333     WN * blk = WN_CreateBlock ();
01334 
01335     // Store compare result
01336     WN_INSERT_BlockLast (blk, WN_Stid (WN_rtype (if_test),
01337                                        0,
01338                cmp,
01339                ST_type (cmp),
01340                if_test));
01341 
01342     // Load from temp var
01343     serial_test = WN_Ldid (WN_rtype (if_test), 0, cmp, ST_type (cmp));
01344 
01345     if_test = WN_COPY_Tree (serial_test);
01346     WN * if_then = WN_CreateBlock ();
01347     WN * if_else = WN_CreateBlock ();
01348 
01349     // Insert call node in then-part
01350     WN_INSERT_BlockLast (if_then, wn);
01351 
01352     WN * if_wn = WN_CreateIf (if_test, if_then, if_else);
01353     WN_linenum (if_wn) = line_number;
01354 
01355     WN_INSERT_BlockLast (blk, if_wn);
01356     return blk;
01357   }
01358 #endif // KEY
01359 
01360 #ifndef KEY
01361   WN_kid(wn, 0) = WN_CreateParm(MTYPE_I4, Get_Gtid( gtid ),
01362                      Be_Type_Tbl(MTYPE_I4), WN_PARM_BY_VALUE);
01363 #endif // !KEY
01364 
01365   return wn;
01366 }
01367   
01368 /*
01369 Generate RT calls to end serialize parallel region
01370 KEY: gtid is not used, the function call does not take any argument
01371 See comments before Gen_Serialized_Parallel.
01372 */
01373 static WN *
01374 Gen_End_Serialized_Parallel( ST *gtid )
01375 {
01376 #ifdef KEY
01377   WN *wn = WN_Create(OPC_VCALL, 0);
01378 #else
01379   WN *wn = WN_Create(OPC_VCALL, 1);
01380 #endif
01381   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_END_SERIALIZED_PARALLEL);
01382   
01383   WN_Set_Call_Non_Data_Mod(wn);
01384   WN_Set_Call_Non_Data_Ref(wn);
01385   WN_Set_Call_Non_Parm_Mod(wn);
01386   WN_Set_Call_Parm_Ref(wn);
01387   WN_linenum(wn) = line_number;
01388 
01389 #ifdef KEY
01390   if (if_node) // if_node is an XPRAGMA
01391   {
01392 #ifdef Is_True_On
01393     Is_True (serialized_parallel_in_cond, 
01394              ("Did we forget to start a serialized_parallel?"));
01395 
01396     serialized_parallel_in_cond = FALSE;
01397 #endif // Is_True_On
01398 
01399     FmtAssert (serial_test, ("NULL compare statement"));
01400 
01401     WN * if_test = WN_COPY_Tree (serial_test);
01402     WN_Delete (serial_test);
01403     serial_test = NULL;
01404 
01405     WN * if_then = WN_CreateBlock ();
01406     WN * if_else = WN_CreateBlock ();
01407 
01408     WN_INSERT_BlockLast (if_then, wn);
01409 
01410     WN * if_wn = WN_CreateIf (if_test, if_then, if_else);
01411     WN_linenum (if_wn) = line_number;
01412     return if_wn;
01413   }
01414 #endif // KEY
01415 
01416 #ifndef KEY
01417   WN_kid(wn, 0) = WN_CreateParm(MTYPE_I4, Get_Gtid( gtid ),
01418                      Be_Type_Tbl(MTYPE_I4), WN_PARM_BY_VALUE); 
01419 #endif // !KEY
01420 
01421   return wn;
01422 }
01423 
01424 static WN *Gen_Master( ST *gtid );
01425 static void Create_Preg_or_Temp ( TYPE_ID mtype, char *name, ST **st,
01426                                   WN_OFFSET *ofst );
01427 static WN * Gen_MP_Load ( ST * st, WN_OFFSET offset, BOOL scalar_only = FALSE );
01428 static WN * Gen_Barrier ( ST* gtid );
01429 
01430 /*
01431 * Generate RT calls to start critical section
01432 */
01433 static WN *
01434 Gen_Critical (ST *gtid, ST *lck)
01435 {
01436   WN *wn = WN_Create(OPC_VCALL, 2);
01437   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_CRITICAL);
01438   
01439   WN_Set_Call_Non_Data_Mod(wn);
01440   WN_Set_Call_Non_Data_Ref(wn);
01441   WN_Set_Call_Parm_Ref(wn);
01442   WN_Set_Call_Parm_Mod(wn);
01443   WN_linenum(wn) = line_number;
01444   
01445   WN_kid(wn, 0) = WN_CreateParm( MTYPE_I4, Get_Gtid( gtid ),
01446                      Be_Type_Tbl( MTYPE_I4 ), WN_PARM_BY_VALUE ); 
01447 
01448   WN_kid(wn, 1) = WN_CreateParm( Pointer_type, 
01449                      WN_Lda( Pointer_type, 0, lck ),
01450                      Be_Type_Tbl( Pointer_type ), WN_PARM_BY_REFERENCE );
01451 
01452   WN *return_wn = NULL;
01453 
01454 #ifndef KEY
01455   if( critical_lock_not_init == TRUE )
01456   {
01457     return_wn = WN_CreateBlock( );
01458     
01459     //initial lock = 0;
01460 
01461     WN *wn_master = Gen_Master( gtid);
01462     WN_linenum( wn_master ) = line_number;
01463     WN_INSERT_BlockLast( return_wn, wn_master );
01464     ST *return_st;
01465     WN_OFFSET return_ofst;
01466     PREG_NUM rreg1, rreg2;
01467     Create_Preg_or_Temp ( MTYPE_I4, "is_master", &return_st, &return_ofst );
01468     GET_RETURN_PREGS(rreg1, rreg2, MTYPE_I4);
01469     WN *wn_temp = WN_Stid (MTYPE_I4, return_ofst, return_st, ST_type(return_st),
01470                            WN_LdidPreg ( MTYPE_I4, rreg1 ));
01471     WN_linenum(wn_temp) = line_number;
01472     WN_INSERT_BlockLast( return_wn, wn_temp );
01473     
01474     //Create_IF    
01475     WN *test = WN_EQ(MTYPE_I4,
01476                      Gen_MP_Load( return_st, return_ofst ),
01477                      WN_CreateIntconst ( OPC_I4INTCONST, 1 ));
01478     WN *if_wn = WN_CreateIf(test,WN_CreateBlock(),WN_CreateBlock());
01479     WN_linenum( if_wn ) = line_number;
01480 
01481     //Init lock to 0
01482     //The following statement maybe wrong.
01483     //It does cause problem in compiling.
01484     Create_Lock_Type( );
01485     TY_IDX ptr_lck = Make_Pointer_Type( lock_ty_idx, FALSE );
01486     WN *lck_addr = WN_Lda( Pointer_type, 0, lck );
01487 
01488     WN *init_wn = WN_CreateMstore( 0, ptr_lck, 
01489                         WN_Intconst( MTYPE_I4, 0 ),
01490                         lck_addr,
01491                         WN_Intconst( MTYPE_I4, 32 ));
01492 
01493     WN_linenum( init_wn ) = line_number;
01494     WN_INSERT_BlockLast( WN_then( if_wn ), init_wn );
01495 
01496     WN_INSERT_BlockLast( return_wn, if_wn );
01497     WN_INSERT_BlockLast( return_wn, Gen_Barrier( gtid )); 
01498     WN_INSERT_BlockLast( return_wn, wn );
01499   }
01500   else
01501 #endif
01502     return_wn = wn;
01503 
01504   return return_wn;
01505 }
01506 
01507 /*
01508 * Generate RT calls to end critical section
01509 */
01510 static WN *
01511 Gen_End_Critical (ST *gtid, ST *lck)
01512 {
01513   WN *wn = WN_Create(OPC_VCALL, 2);
01514   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_END_CRITICAL);
01515   
01516   WN_Set_Call_Non_Data_Mod(wn);
01517   WN_Set_Call_Non_Data_Ref(wn);
01518   WN_Set_Call_Parm_Mod(wn);
01519   WN_Set_Call_Parm_Ref(wn);
01520   WN_linenum(wn) = line_number;
01521   
01522   WN_kid(wn, 0) = WN_CreateParm(MTYPE_I4, Get_Gtid( gtid ),
01523                      Be_Type_Tbl(MTYPE_I4), WN_PARM_BY_VALUE); 
01524   WN_kid(wn, 1) = WN_CreateParm( Pointer_type, 
01525                      WN_Lda( Pointer_type, 0, lck ),
01526                      Be_Type_Tbl( Pointer_type ), WN_PARM_BY_REFERENCE );
01527 
01528   return wn;
01529 }
01530 
01531 /*
01532 * Generate RT calls to start ordered
01533 */
01534 static WN *
01535 Gen_Ordered( ST *gtid )
01536 {
01537   WN *wn = WN_Create(OPC_VCALL, 1);
01538   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_ORDERED);
01539   
01540   WN_Set_Call_Non_Data_Mod(wn);
01541   WN_Set_Call_Non_Data_Ref(wn);
01542   WN_Set_Call_Non_Parm_Mod(wn);
01543   WN_Set_Call_Parm_Ref(wn);
01544   WN_linenum(wn) = line_number;
01545   
01546   WN_kid(wn, 0) = WN_CreateParm(MTYPE_I4, Get_Gtid( gtid ),
01547                      Be_Type_Tbl(MTYPE_I4), WN_PARM_BY_VALUE); 
01548   
01549   return wn;
01550 }
01551 
01552 /*
01553 * Generate RT calls to end ordered
01554 */
01555 static WN *
01556 Gen_End_Ordered( ST *gtid )
01557 {
01558   WN *wn = WN_Create(OPC_VCALL, 1);
01559   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_END_ORDERED);
01560   
01561   WN_Set_Call_Non_Data_Mod(wn);
01562   WN_Set_Call_Non_Data_Ref(wn);
01563   WN_Set_Call_Non_Parm_Mod(wn);
01564   WN_Set_Call_Parm_Ref(wn);
01565   WN_linenum(wn) = line_number;
01566   
01567   WN_kid(wn, 0) = WN_CreateParm(MTYPE_I4, Get_Gtid( gtid ),
01568                      Be_Type_Tbl(MTYPE_I4), WN_PARM_BY_VALUE); 
01569   
01570   return wn;
01571 }
01572 
01573 /*
01574 * Generate RT calls to begin master
01575 */
01576 static WN *
01577 Gen_Master (ST *gtid)
01578 {
01579   WN *wn = WN_Create(OPC_I4CALL, 1);
01580   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_MASTER);
01581   
01582   WN_Set_Call_Non_Data_Mod(wn);
01583   WN_Set_Call_Non_Data_Ref(wn);
01584   WN_Set_Call_Non_Parm_Mod(wn);
01585   WN_Set_Call_Parm_Ref(wn);
01586   WN_linenum(wn) = line_number;
01587   
01588   WN_kid(wn, 0) = WN_CreateParm(MTYPE_I4, Get_Gtid( gtid ),
01589                      Be_Type_Tbl(MTYPE_I4), WN_PARM_BY_VALUE); 
01590   
01591   return wn;
01592 }
01593 
01594 /*
01595 * Generate RT calls to begin master
01596 */
01597 static WN *
01598 Gen_End_Master (ST *gtid)
01599 {
01600   WN *wn = WN_Create(OPC_VCALL, 1);
01601   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_END_MASTER);
01602   
01603   WN_Set_Call_Non_Data_Mod(wn);
01604   WN_Set_Call_Non_Data_Ref(wn);
01605   WN_Set_Call_Non_Parm_Mod(wn);
01606   WN_Set_Call_Parm_Ref(wn);
01607   WN_linenum(wn) = line_number;
01608   
01609   WN_kid(wn, 0) = WN_CreateParm(MTYPE_I4, Get_Gtid( gtid ),
01610                      Be_Type_Tbl(MTYPE_I4), WN_PARM_BY_VALUE); 
01611   
01612   return wn;
01613 }
01614 
01615 /*
01616 * Generate a begin single RTL call.
01617 * The first argument is only for compatibility usage.
01618 * Remove it later.
01619 * */
01620 static WN * 
01621 Gen_Single (WN * constructnum, 
01622             ST * gtid,
01623             BOOL is_omp)
01624 {
01625   WN *wn;
01626 
01627 #ifndef KEY
01628   if (is_omp) 
01629 #else
01630   if (TRUE) 
01631 #endif
01632   {
01633     wn = WN_Create ( OPC_I4CALL, 1 );
01634     WN_st_idx(wn) = GET_MPRUNTIME_ST ( MPR_OMP_SINGLE );
01635 
01636     WN_kid(wn, 0) = WN_CreateParm(MTYPE_I4, Get_Gtid( gtid ),
01637                      Be_Type_Tbl(MTYPE_I4), WN_PARM_BY_VALUE); 
01638   } else {
01639     wn = WN_Create ( OPC_I4CALL, 1 );
01640     WN_st_idx(wn) = GET_MPRUNTIME_ST ( MPR_BEGIN_SINGLE_PROCESS );
01641 
01642     WN_kid(wn, 0) = WN_CreateParm (MTYPE_I4, constructnum, 
01643         Be_Type_Tbl(MTYPE_I4), WN_PARM_BY_VALUE);
01644   }
01645   WN_Set_Call_Non_Data_Mod ( wn );
01646   WN_Set_Call_Non_Data_Ref ( wn );
01647   WN_Set_Call_Non_Parm_Mod ( wn );
01648   WN_Set_Call_Non_Parm_Ref ( wn );
01649   WN_Set_Call_Parm_Ref ( wn );
01650   WN_linenum(wn) = line_number;
01651 
01652   return ( wn );
01653 }
01654 
01655 /*
01656 * End_Single. not totally compliant with original one.
01657 * I don't know the right way for Intel's RTL to handle nowait,
01658 * Is it also to ignore the end calls? csc.
01659 */
01660 
01661 static WN *
01662 Gen_End_Single (WN * constructnum, 
01663                 ST * gtid,
01664                 BOOL is_omp, BOOL nowait)
01665 {
01666   Is_True( is_omp || !nowait, ("no need for END_SINGLE_PROCESS runtime call"));
01667 
01668   WN *return_wn = WN_CreateBlock( );
01669   WN *wn;
01670 
01671 #ifndef KEY
01672   if (is_omp) 
01673 #else
01674   if (TRUE)
01675 #endif
01676   {
01677     wn = WN_Create ( OPC_VCALL, 1 );
01678     WN_st_idx(wn) = GET_MPRUNTIME_ST ( MPR_OMP_END_SINGLE );
01679 
01680     WN_kid(wn, 0) = WN_CreateParm(MTYPE_I4, Get_Gtid( gtid ),
01681                      Be_Type_Tbl(MTYPE_I4), WN_PARM_BY_VALUE); 
01682   } else {
01683     wn = WN_Create ( OPC_VCALL, 1 );
01684     WN_st_idx(wn) = GET_MPRUNTIME_ST ( MPR_END_SINGLE_PROCESS );
01685     WN_kid0(wn) = WN_CreateParm (MTYPE_I4, constructnum, Be_Type_Tbl(MTYPE_I4),
01686                                  WN_PARM_BY_VALUE);
01687   }
01688   WN_Set_Call_Non_Data_Mod ( wn );
01689   WN_Set_Call_Non_Data_Ref ( wn );
01690   WN_Set_Call_Non_Parm_Mod ( wn );
01691   WN_Set_Call_Non_Parm_Ref ( wn );
01692   WN_Set_Call_Parm_Ref ( wn );
01693   WN_linenum(wn) = line_number;
01694 
01695   WN_INSERT_BlockLast( return_wn, wn );
01696 
01697   if( is_omp && !nowait )
01698   {
01699     // I don't know whether the end_single call implies a barrier,
01700     // to ensure the correctness, I insert one here.
01701     // csc.
01702     WN_INSERT_BlockLast( return_wn, Gen_Barrier( gtid ));
01703   }
01704 
01705   return ( return_wn );
01706 }
01707 
01708 /*
01709 * Flush thread modified data. envision it to the global scope.
01710 * Currently, the f90fe and cfe translate FLUSH directives directly
01711 * into VINTRINSIC_CALL<SYNCHRONIZE>, and the cg smooth this call
01712 * away. So the OMP programs with FLUSH will not cause compilation
01713 * error anyway, but the standard-required behavior may be biased,
01714 * and for that, I've not observed and verified. So this part is
01715 * remained untouched. A few more test is needed.
01716 * TODO: rewrite the whole FLUSH framework. maybe we can simply
01717 * translate the intrinsic call into the RTL one, but for the ZERO-
01718 * ARG form of FLUSH, the FE should be adapted to a proper generation
01719 * of the call. 2002.12.20
01720 * csc.
01721 * currently, all RTL calls to flush are generated for other constructs
01722 */
01723 static WN *
01724 Gen_Flush( ST *flush_var, WN_OFFSET flush_offset)
01725 {
01726   WN *wn = WN_Create(OPC_VCALL, 1);
01727   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_FLUSH);
01728   
01729   WN_Set_Call_Non_Data_Mod(wn);
01730   WN_Set_Call_Non_Data_Ref(wn);
01731   WN_Set_Call_Parm_Mod(wn);
01732   WN_Set_Call_Parm_Ref(wn);
01733   WN_linenum(wn) = line_number;
01734   
01735   WN_kid(wn, 0) = WN_CreateParm( Pointer_type, 
01736                      WN_Lda( Pointer_type, flush_offset, flush_var ),
01737                      Be_Type_Tbl( Pointer_type ), WN_PARM_BY_REFERENCE );
01738   // TODO: finish the flush call.
01739   return wn;
01740 }
01741 #ifdef KEY
01742 static WN* 
01743 Get_First_Stmt_in_Block(WN *block)
01744 {
01745   WN *first = WN_first(block);
01746   OPERATOR opr = WN_operator( first );
01747   if ( opr == OPR_ALTENTRY ){
01748     while (opr != OPR_PRAGMA ||
01749            WN_pragma( first ) != WN_PRAGMA_PREAMBLE_END)
01750       first = WN_next(first);
01751     opr = WN_operator(first);
01752   }
01753   if (opr == OPR_PRAGMA &&
01754       WN_pragma( first ) == WN_PRAGMA_PREAMBLE_END){
01755     first = WN_next(first);
01756     opr = WN_operator(first);
01757   }
01758   if (opr == OPR_PRAGMA &&
01759       WN_pragma( first ) == WN_PRAGMA_START_STMT_CLUMP)
01760     first = WN_next(first);
01761 
01762   return first;
01763 }
01764 static ST*
01765 Extract_Gtid_ST(WN *block)
01766 {
01767   WN *wn = WN_first(block);
01768   while (wn){
01769     OPERATOR opr = WN_operator(wn);
01770     if (opr == OPR_STID){
01771       if (strcmp( ST_name(WN_st(wn)), "__ompv_temp_gtid") == 0)
01772         return WN_st(wn);
01773     }
01774     wn = WN_next(wn);
01775   }
01776   return NULL;
01777 }
01778 
01779 void 
01780 Gen_Threadpriv_Func(WN* prags, WN* block, BOOL prepend)
01781 {
01782   WN *blck = prags;
01783   WN *keep_prags; 
01784   WN *thrprv_assign;
01785   WN *wn;
01786   ST *gtid_st = NULL;
01787   BOOL need_thread_num = FALSE;
01788 
01789   BOOL target_32bit = Is_Target_32bit();
01790 
01791   const OPCODE uint_opc = (Pointer_Size == 4) ? OPC_U4INTCONST :
01792                          (Pointer_Size == 8) ? OPC_U8INTCONST : OPCODE_UNKNOWN;
01793   const mTYPE_ID uint_mtype = (uint_opc == OPC_U4INTCONST) ? MTYPE_U4 : MTYPE_U8;
01794 
01795   prags = WN_first(prags);
01796 
01797   while (prags) { 
01798     keep_prags = WN_next(prags);
01799     if (WN_opcode(prags) != OPC_PRAGMA ||
01800         WN_pragma(prags) != WN_PRAGMA_THREADPRIVATE) {
01801       prags = keep_prags;
01802       continue;
01803     }
01804     WN *stmt = WN_first(block);
01805     BOOL match = FALSE;
01806     while (WN_opcode(stmt) == OPC_VCALL &&
01807            WN_kid_count(stmt) == 4){
01808       if (WN_operator(WN_kid0(WN_kid2(stmt))) == OPR_LDA &&
01809           WN_st(WN_kid0(WN_kid2(stmt))) == WN_st(prags)) {
01810         match = TRUE;
01811         break;
01812       }
01813       stmt = WN_next(stmt);
01814     }
01815     if (match){
01816       prags = keep_prags;
01817       continue;
01818     }
01819 
01820     wn = WN_Create(OPC_VCALL, 4);
01821     WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_GET_THDPRV);
01822   
01823     WN_Set_Call_Non_Data_Mod(wn);
01824     WN_Set_Call_Non_Data_Ref(wn);
01825     WN_Set_Call_Parm_Mod(wn);
01826     WN_Set_Call_Parm_Ref(wn);
01827     WN_linenum(wn) = line_number;
01828 
01829     if (ST_is_not_used(ST_ptr(WN_pragma_arg2(prags))))
01830       Clear_ST_is_not_used(ST_ptr(WN_pragma_arg2(prags)));
01831     WN_kid(wn, 0) = WN_CreateParm( Pointer_type, 
01832                      WN_Lda( Pointer_type, 0, ST_ptr(WN_pragma_arg2(prags)) ),
01833                      Be_Type_Tbl( Pointer_type ), WN_PARM_BY_REFERENCE );
01834 
01835     WN_kid(wn, 1) = WN_CreateParm(MTYPE_I8, 
01836                      WN_Intconst (MTYPE_I8, ST_size(ST_ptr(WN_st_idx(prags)))),
01837                      Be_Type_Tbl(MTYPE_I8), WN_PARM_BY_VALUE); 
01838 
01839     if (ST_is_not_used(WN_st(prags)))
01840       Clear_ST_is_not_used(WN_st(prags));
01841     WN_kid(wn, 2) = WN_CreateParm( Pointer_type, 
01842                      WN_Lda( Pointer_type, 0, ST_ptr(WN_st_idx(prags)) ),
01843                      Be_Type_Tbl( Pointer_type ), WN_PARM_BY_REFERENCE );
01844 
01845 //    if (prepend != TRUE)
01846 //      gtid_st = Extract_Gtid_ST(block);
01847 
01848     if (!gtid_st){
01849       gtid_st = New_ST(CURRENT_SYMTAB);
01850       ST_Init(gtid_st, Save_Str("__ompv_gtid_s1"), CLASS_VAR, SCLASS_AUTO, 
01851                    EXPORT_LOCAL, MTYPE_To_TY(MTYPE_I4));
01852       need_thread_num = TRUE;
01853     }
01854 
01855     WN_kid(wn, 3) = WN_CreateParm( uint_mtype , 
01856                      Gen_MP_Load(gtid_st, 0),
01857                      Be_Type_Tbl( uint_mtype ), WN_PARM_BY_REFERENCE );
01858 
01859     WN *thrprv_block = WN_CreateBlock ();
01860     WN_INSERT_BlockLast(thrprv_block, wn);
01861 
01862     WN_OFFSET return_ofst = 0;
01863 
01864     ST *local_st = ST_ptr(WN_pragma_arg1(prags));
01865     ST *global_st = ST_ptr(WN_pragma_arg2(prags));
01866     TYPE_ID type = TY_mtype(TY_pointed(ST_type(global_st)));
01867     OPCODE load_opc = OPCODE_make_op(OPR_ILOAD,Pointer_type, Pointer_type);
01868 
01869     WN *test = WN_CIOR(WN_EQ(MTYPE_I4,
01870                              Gen_MP_Load( ST_ptr(WN_pragma_arg2(prags)), return_ofst ),
01871                              WN_CreateIntconst (target_32bit?OPC_U4INTCONST:OPC_U8INTCONST, 0)),
01872                        WN_EQ(MTYPE_I4,
01873                              WN_CreateIload(load_opc, 0,
01874                                             Be_Type_Tbl(Pointer_type),
01875                                             Make_Pointer_Type(Be_Type_Tbl(type),FALSE),
01876                                             WN_Add (uint_mtype,
01877                                                     WN_Ldid(Pointer_type, 0,
01878                                                             global_st,
01879                                                             ST_type(global_st)),
01880                                                     WN_Mpy (uint_mtype,
01881                                                             WN_Ldid(MTYPE_I4, 0,
01882                                                                     gtid_st,
01883                                                                     ST_type(gtid_st)),
01884                                                             WN_CreateIntconst (uint_opc,
01885                                                                                target_32bit?4:8)
01886                                                             )
01887                                                     )
01888                                              ),
01889                              WN_CreateIntconst (target_32bit?OPC_U4INTCONST:OPC_U8INTCONST, 0)
01890                              )
01891                        );
01892     WN *thrprv_test = WN_CreateIf( test, thrprv_block, WN_CreateBlock());
01893 
01894 
01895 
01896     thrprv_assign = WN_Stid(Pointer_type, 0, 
01897                             ST_ptr(WN_pragma_arg1(prags)), 
01898                             ST_type(local_st), 
01899                             WN_CreateIload(load_opc, 0,
01900                                            Be_Type_Tbl(Pointer_type),
01901                                            Make_Pointer_Type(Be_Type_Tbl(type),FALSE),
01902                                            WN_Add (uint_mtype, 
01903                                                    WN_Ldid(Pointer_type, 0, 
01904                                                            global_st, 
01905                                                            ST_type(global_st)),
01906                                                    WN_Mpy (uint_mtype,
01907                                                            WN_Ldid(MTYPE_I4, 0,
01908                                                                    gtid_st,
01909                                                                    ST_type(gtid_st)),
01910                                                            WN_CreateIntconst (uint_opc, 
01911                                                                               target_32bit?4:8)))));
01912                                      
01913     if (prepend != TRUE) {
01914       WN_INSERT_BlockLast(block, thrprv_test);
01915       WN_INSERT_BlockLast(block, thrprv_assign);
01916       wn = NULL;
01917     }
01918     else{
01919       wn = Get_First_Stmt_in_Block(block);
01920       WN_INSERT_BlockBefore(block, wn, thrprv_test);
01921       WN_INSERT_BlockBefore(block, wn, thrprv_assign);
01922     }
01923     WN_DELETE_FromBlock(blck, prags);
01924 
01925     prags = keep_prags;
01926   }
01927   if (need_thread_num){
01928     if (prepend == TRUE){
01929       if (!wn || !WN_prev(wn) || !WN_prev(WN_prev(wn)))
01930         Fail_FmtAssertion("cannot find a place to insert threadprivate");
01931       wn = WN_prev(WN_prev(wn));
01932     }
01933     else{
01934       wn = Get_First_Stmt_in_Block(block);
01935       wn = WN_next(WN_next(wn));
01936     }
01937     WN_INSERT_BlockBefore( block, wn,  Gen_Get_Thread_Num() );
01938     PREG_NUM   rreg1, rreg2;
01939     GET_RETURN_PREGS(rreg1, rreg2, MTYPE_I4);
01940     WN* wnx = WN_Stid( MTYPE_I4, 0, gtid_st, ST_type( gtid_st ),
01941              WN_LdidPreg ( MTYPE_I4, rreg1 ));
01942     WN_INSERT_BlockBefore( block, wn, wnx );
01943   }
01944     
01945 }
01946 #endif
01947 
01948 /*
01949 * When switching scope, use this call to save some global vars.
01950 * When the scope is switched back, use Pop_Some_Globals to restore them.
01951 * csc.
01952 */
01953 static void 
01954 Push_Some_Globals( )
01955 {
01956 
01957   old_gtid_st = local_gtid;
01958 
01959 }
01960 
01961 /*
01962 * Restore globals.
01963 * csc.
01964 */
01965 static void 
01966 Pop_Some_Globals( )
01967 {
01968 
01969   // TODO: when enable true nested-parallelism, 
01970   // a stack style pop/push should be implemented.
01971   local_gtid = old_gtid_st;
01972   old_gtid_st = NULL;
01973 
01974 }
01975 
01976 /*
01977 * Initial PU-wise Globals. need to be called in LowerMP_PU_Init.
01978 * csc.
01979 */
01980 static void 
01981 Init_PU_Globals( )
01982 {
01983 
01984   local_gtid = NULL;
01985 }
01986 
01987 /*
01988 Create a DST entry for a local variable in either the parent subprogram or
01989 the nested subprogram.
01990 */
01991 
01992 static void 
01993 Add_DST_variable ( ST *st, DST_INFO_IDX parent_dst, 
01994              INT64 line_number, DST_INFO_IDX type_idx )
01995 {
01996   DST_INFO      *info;
01997   DST_INFO_IDX  dst, child_idx;
01998   DST_ATTR_IDX attr_idx;
01999   DST_ASSOC_INFO *assoc;
02000   DST_BASETYPE *attr;
02001   USRCPOS       srcpos;
02002   INT32         typesize;
02003   static DST_INFO_IDX int32_idx = {DST_INVALID_BLOCK_IDX, DST_INVALID_BYTE_IDX};
02004   static DST_INFO_IDX int64_idx = {DST_INVALID_BLOCK_IDX, DST_INVALID_BYTE_IDX};
02005   DST_INFO_IDX  int_idx;
02006   DST_IDX cmp;
02007   char         *name;
02008 
02009   /* don't do anything if without -g option */
02010   if (Debug_Level == 0)
02011     return;
02012 
02013   if (DST_IS_NULL( type_idx )) {
02014     /* For variables which do not exist in the original program, there
02015     ** are no type information for them.  We need to search in the DST
02016     ** tree for the corresponding type entry
02017     */
02018     if (TY_kind(ST_type(st)) == KIND_POINTER) {
02019       typesize = TY_size(TY_pointed(ST_type(st)));
02020     } else {
02021       typesize = TY_size(ST_type(st));
02022     }
02023 
02024     const char *int_name1, *int_name2, *int_name3;
02025     DST_INFO_IDX *int_idx_p;
02026 
02027     switch (typesize) {
02028     case 4:
02029       int_name1 = "int"; int_name2 = "INTEGER*4"; int_name3 = "INTEGER_4";
02030       int_idx_p = &int32_idx;
02031       break;
02032     case 8:
02033 #ifndef KEY
02034       int_name1 = "long long"; 
02035 #else
02036       // Bug 7287 - C and C++ programs have "long long int" and 
02037       // "long long unsigned int" as basetype, but no "long long".
02038       int_name1 = "long long int";
02039 #endif
02040       int_name2 = "INTEGER*8"; int_name3 = "INTEGER_8";
02041       int_idx_p = &int64_idx;
02042       break;
02043     default:
02044       Fail_FmtAssertion("can't handle typesize == %d", (INT) typesize);
02045     }
02046 
02047     if (DST_IS_NULL(*int_idx_p) ) {
02048       cmp = DST_get_compile_unit();
02049       info = DST_INFO_IDX_TO_PTR( cmp );
02050       attr_idx = DST_INFO_attributes( info );
02051       child_idx = DST_COMPILE_UNIT_first_child(
02052                   DST_ATTR_IDX_TO_PTR(attr_idx, DST_COMPILE_UNIT));
02053       while (!DST_IS_NULL(child_idx)) {
02054         info = DST_INFO_IDX_TO_PTR( child_idx );
02055         if (DST_INFO_tag( info ) == DW_TAG_base_type) {
02056           attr = DST_ATTR_IDX_TO_PTR(DST_INFO_attributes(info), DST_BASETYPE);
02057           name = DST_STR_IDX_TO_PTR( DST_FORMAL_PARAMETER_name(attr));
02058 #ifdef KEY //bug 11848: name can not be null
02059          if(name == NULL)
02060             Is_True(0, ("Base type should have a name in a DST entry"));
02061           else
02062 #endif
02063           if (!strcmp(name, int_name1) || !strcmp(name, int_name2) ||
02064               !strcmp(name, int_name3)) {
02065             *int_idx_p = child_idx;
02066             break;
02067           }
02068         }
02069         child_idx = DST_INFO_sibling(DST_INFO_IDX_TO_PTR(child_idx));
02070       }
02071       if (DST_IS_NULL(child_idx)) {
02072           // type not emitted by frontend, so we have to insert it
02073         *int_idx_p = DST_mk_basetype(int_name1, DW_ATE_signed, typesize);
02074         (void) DST_append_child(parent_dst, *int_idx_p);
02075       }
02076     }
02077     int_idx = *int_idx_p;
02078 
02079   }
02080 
02081   USRCPOS_srcpos(srcpos) = line_number;
02082   if (ST_sclass(st) == SCLASS_FORMAL_REF) {
02083     dst = DST_mk_formal_parameter( srcpos,
02084       ST_name( st ),
02085       int_idx,  /* type DST_IDX */
02086       ST_st_idx(st),  /* symbol */
02087       DST_INVALID_IDX,
02088       DST_INVALID_IDX,
02089       FALSE,
02090       FALSE,
02091       FALSE,   // is_artificial
02092       FALSE ); // is_declaration_only
02093     DST_SET_deref( DST_INFO_flag( DST_INFO_IDX_TO_PTR (dst) ) );
02094   } else
02095     dst = DST_mk_variable( srcpos,
02096       ST_name( st ),
02097       int_idx,  /* type DST_IDX */
02098       0 /* offset */,
02099       ST_st_idx(st),  /* symbol */
02100       DST_INVALID_IDX,
02101       FALSE,    /* memory allocated */
02102       TRUE,     /* parameter has sc_auto */
02103       FALSE,    /* sc_extern || sc_unspecified */
02104       FALSE);   /* is_artificial */
02105 
02106   (void)DST_append_child( parent_dst, dst );
02107 #if 0
02108   info = DST_INFO_IDX_TO_PTR( dst );
02109   assoc = &DST_VARIABLE_def_st(
02110     DST_ATTR_IDX_TO_PTR(DST_INFO_attributes(info), DST_VARIABLE));
02111   pDST_ASSOC_INFO_st_idx(assoc) = ST_st_idx(st);
02112   DST_SET_assoc_idx(DST_INFO_flag(info));
02113   DST_RESET_assoc_fe(DST_INFO_flag(info));
02114 #endif
02115 }
02116 
02117 
02118 extern DST_IDX 
02119 Find_DST_From_ST ( ST *st, PU_Info *pu_info )
02120 {
02121   DST_INFO_IDX  dst, child_idx;
02122   DST_INFO      *info;
02123   INT32   level, index;
02124   DST_ASSOC_INFO *assoc;
02125   DST_DW_tag  tag;
02126   DST_flag      flag;
02127   DST_ATTR_IDX  iattr;
02128 
02129   level = ST_level(st);
02130   index = ST_index(st);
02131   dst = PU_Info_pu_dst( pu_info );
02132   /* Go through the list of children in the parent subprogram to find the
02133   ** one that points to this ST entry
02134   */
02135   info = DST_INFO_IDX_TO_PTR( dst );
02136   iattr = DST_INFO_attributes( info );
02137   child_idx = DST_SUBPROGRAM_def_first_child(
02138     DST_ATTR_IDX_TO_PTR(iattr, DST_SUBPROGRAM));
02139   while (!DST_IS_NULL(child_idx)) {
02140     info = DST_INFO_IDX_TO_PTR( child_idx );
02141     tag = DST_INFO_tag(info);
02142     flag = DST_INFO_flag(info);
02143     iattr = DST_INFO_attributes(info);
02144     level = ST_level(st);
02145     index = ST_index(st);
02146     switch (tag) 
02147     {
02148       case DW_TAG_formal_parameter:
02149         assoc = &DST_FORMAL_PARAMETER_st(
02150     DST_ATTR_IDX_TO_PTR(iattr, DST_FORMAL_PARAMETER));
02151   break;
02152       case DW_TAG_variable:
02153         assoc = &DST_VARIABLE_def_st(
02154     DST_ATTR_IDX_TO_PTR(iattr, DST_VARIABLE));
02155   break;
02156       default:
02157   goto next;
02158     }
02159     if (pDST_ASSOC_INFO_st_level(assoc) == level 
02160   && pDST_ASSOC_INFO_st_index(assoc) == index) {
02161         // PV 644324: F90 arrays with dope vectors have DST entries for
02162         // compiler-generated variables for array bounds that match in
02163         // level and index but have no name: search for entry with valid name
02164       DST_INFO_IDX name_idx;
02165 
02166       if (tag == DW_TAG_formal_parameter) {
02167         name_idx = DST_FORMAL_PARAMETER_name(DST_ATTR_IDX_TO_PTR(iattr,
02168                                                 DST_FORMAL_PARAMETER));
02169       } else if (tag == DW_TAG_variable) {
02170         DST_VARIABLE *vattr = DST_ATTR_IDX_TO_PTR(iattr, DST_VARIABLE);
02171 
02172         name_idx = DST_IS_comm(flag) ? DST_VARIABLE_comm_name(vattr) :
02173                                        DST_VARIABLE_def_name(vattr);
02174       } else
02175         Fail_FmtAssertion("impossible tag == %d\n", (INT) tag);
02176 
02177       if (DST_IS_NULL(name_idx))
02178         goto next;
02179 
02180       return child_idx;
02181     }
02182 next:
02183     child_idx = DST_INFO_sibling(DST_INFO_IDX_TO_PTR(child_idx));
02184   }
02185   return( DST_INVALID_IDX );
02186 }
02187 
02188 
02189 extern void 
02190 Create_New_DST ( DST_INFO_IDX dst, ST *st , BOOL append_to_nested )
02191 {
02192   DST_INFO      *info;
02193   DST_INFO_IDX  new_dst, type_idx;
02194   DST_ASSOC_INFO *assoc;
02195   DST_DW_tag  tag;
02196   DST_flag  flag;
02197   DST_ATTR_IDX  iattr;
02198   DST_VARIABLE  *vattr;
02199   DST_FORMAL_PARAMETER *fattr;
02200   USRCPOS       srcpos;
02201   char    *name;
02202 
02203   USRCPOS_srcpos(srcpos) = 0LL;
02204   info = DST_INFO_IDX_TO_PTR( dst );
02205   tag = DST_INFO_tag(info);
02206   iattr = DST_INFO_attributes(info);
02207   flag = DST_INFO_flag(info);
02208   type_idx = DST_INVALID_IDX;
02209   switch (tag) 
02210   {
02211     case DW_TAG_formal_parameter:
02212       fattr = DST_ATTR_IDX_TO_PTR(iattr, DST_FORMAL_PARAMETER);
02213       type_idx = DST_FORMAL_PARAMETER_type( fattr );
02214       name = DST_STR_IDX_TO_PTR( DST_FORMAL_PARAMETER_name( fattr ) );
02215       break;
02216     case DW_TAG_variable:
02217       if (DST_IS_comm(flag)) {
02218   vattr = DST_ATTR_IDX_TO_PTR(iattr, DST_VARIABLE);
02219   type_idx = DST_VARIABLE_comm_type( vattr );
02220   name = DST_STR_IDX_TO_PTR( DST_VARIABLE_comm_name( vattr ) );
02221       }
02222       else {
02223         vattr = DST_ATTR_IDX_TO_PTR(iattr, DST_VARIABLE);
02224         type_idx = DST_VARIABLE_def_type( vattr );
02225   name = DST_STR_IDX_TO_PTR( DST_VARIABLE_def_name( vattr ) );
02226       }
02227       break;
02228     default:
02229   Fail_FmtAssertion( "Unimplemented local MP variable kind" );
02230   }
02231   new_dst = DST_mk_variable( srcpos,
02232       name,
02233       type_idx,   /* type DST_IDX */
02234       0 /* offset */,
02235       ST_st_idx(st),  /* symbol */
02236       DST_INVALID_IDX,
02237       FALSE,    /* memory allocated */
02238       TRUE,     /* parameter has sc_auto */
02239       FALSE,    /* sc_extern || sc_unspecified */
02240       FALSE);   /* is_artificial */
02241 
02242   if (append_to_nested)
02243     (void)DST_append_child( nested_dst, new_dst );
02244   info = DST_INFO_IDX_TO_PTR( new_dst );
02245 #if 0
02246   iattr = DST_INFO_attributes(info);
02247   assoc = &DST_VARIABLE_def_st(
02248     DST_ATTR_IDX_TO_PTR(iattr, DST_VARIABLE));
02249   pDST_ASSOC_INFO_st_idx(assoc) = ST_st_idx(st);
02250   DST_SET_assoc_idx(DST_INFO_flag(info));
02251   DST_RESET_assoc_fe(DST_INFO_flag(info));
02252 #endif
02253 }
02254 
02255 
02256 static void 
02257 Create_Func_DST ( char * st_name )
02258 {
02259   DST_INFO_IDX  dst = PU_Info_pu_dst( Current_PU_Info );
02260   DST_INFO  *info = DST_INFO_IDX_TO_PTR(dst);
02261   DST_ASSOC_INFO *assoc;
02262   USRCPOS       srcpos;
02263 
02264   USRCPOS_srcpos(srcpos) = line_number;
02265   nested_dst =  DST_mk_subprogram( srcpos,
02266       st_name,
02267       DST_INVALID_IDX,  /* return type */
02268       DST_INVALID_IDX,  /* for weak symbols */
02269       ST_st_idx(parallel_proc),
02270       DW_INL_not_inlined,
02271       DW_VIRTUALITY_none,
02272       0,
02273       FALSE,      /* declaration */
02274       FALSE,      /* prototype */
02275 #ifdef KEY
02276                         FALSE,                  // is_artificial
02277 #endif
02278       FALSE     /* external */
02279       );
02280   (void)DST_append_child( dst, nested_dst );
02281 #if 0
02282   info = DST_INFO_IDX_TO_PTR( nested_dst );
02283   assoc = &DST_SUBPROGRAM_def_st(
02284     DST_ATTR_IDX_TO_PTR(DST_INFO_attributes(info), DST_SUBPROGRAM));
02285   pDST_ASSOC_INFO_st_idx(assoc) = ST_st_idx(parallel_proc);
02286   DST_SET_assoc_idx(DST_INFO_flag(info));
02287   DST_RESET_assoc_fe(DST_INFO_flag(info));
02288 #endif
02289 }
02290 
02291 
02292 /*  Compare two PRAGMA nodes or XPRAGMA trees for equality.  */
02293 
02294 static BOOL 
02295 Identical_Pragmas ( WN * wn1, WN * wn2 )
02296 {
02297   INT32 i;
02298 
02299   if ((WN_operator(wn1) != WN_operator(wn2)) ||
02300       (WN_pragma(wn1) != WN_pragma(wn2)) ||
02301       (WN_st(wn1) != WN_st(wn2)) ||
02302       (WN_pragma_flags(wn1) != WN_pragma_flags(wn2)) ||
02303       ((WN_operator(wn1) == OPR_PRAGMA) &&
02304        (WN_pragma_arg64(wn1) != WN_pragma_arg64(wn2))) ||
02305       (WN_kid_count(wn1) != WN_kid_count(wn2)))
02306     return (FALSE);
02307 
02308   for (i = 0; i < WN_kid_count(wn1); i++)
02309     if (WN_Compare_Trees(WN_kid(wn1, i), WN_kid(wn2, i)) != 0)
02310       return (FALSE);
02311 
02312   return (TRUE);
02313 }
02314 
02315 /*
02316 Because sometimes we may merely need a temp var, not a preg, e.g. the var
02317 to accept a value as the function's formal parameter.
02318 So, this function just allocate a temp var in current scope.
02319 */
02320 static void 
02321 Create_Temp( TYPE_ID mtype, const char *name, ST **st )
02322 {
02323   ST *new_st;
02324   new_st = New_ST (CURRENT_SYMTAB);
02325   ST_Init (new_st,
02326            Save_Str2 ( "__ompv_temp_", name ),
02327            CLASS_VAR,
02328            SCLASS_AUTO,
02329            EXPORT_LOCAL,
02330            MTYPE_To_TY (mtype));
02331   Set_ST_is_temp_var ( new_st );
02332   *st = new_st;
02333 }
02334 
02335 #ifdef KEY
02336 // If old_st_idx has already been localized, return the new
02337 // st_idx. Else, create a new local symbol and return its st_idx.
02338 static ST_IDX Localize_Symbol (ST_IDX old_st_idx, VAR_TABLE * v)
02339 {
02340   for ( ; v->orig_st; v++) {
02341     if (ST_st_idx(*v->orig_st) == old_st_idx &&
02342         v->vtype == VAR_LOCAL) {
02343       return ST_st_idx(*v->new_st);
02344     }
02345   }
02346 
02347   ST_IDX new_st_idx = 0;
02348 
02349   ST * new_st = New_ST (CURRENT_SYMTAB);
02350   ST * old_st = &St_Table[old_st_idx];
02351   ST_Init (new_st,
02352            Save_Str (ST_name(old_st_idx)),
02353            ST_class(old_st),
02354            ST_sclass(old_st),
02355            ST_export(old_st),
02356            ST_type(old_st));
02357   new_st->flags = old_st->flags;
02358   new_st->flags_ext = old_st->flags_ext;
02359 
02360   return ST_st_idx(new_st);
02361 }
02362 
02363 // For C++ exception handling, the PU holds different exception
02364 // handling-related information, generated by the front-end.
02365 // old_inito is expected to hold the start of the info for the
02366 // serial function.
02367 // Clone the information (INITOs, INITVs, and local STs), and
02368 // localize where necessary.
02369 //
02370 // TODO: The parallel function being created may not need all
02371 // the typeinfos from the serial function, but currently we will
02372 // have all of them in the typeinfo table for the parallel function.
02373 static INITO_IDX
02374 Process_PU_Exc_Info ( INITO_IDX old_inito, VAR_TABLE * vtab )
02375 {
02376   INITO_IDX new_inito;
02377   ST *old_initst, *new_initst;
02378   INITV_IDX old_initv, new_initv, pinito, parent, prev;
02379   STACK<INITV_IDX> old_stack(Malloc_Mem_Pool), new_stack(Malloc_Mem_Pool);
02380 
02381   old_initst = INITO_st(old_inito);
02382   old_initv  = INITO_val(old_inito);
02383 
02384   // Table name (__EH_INFO_PER_PU__)
02385   new_initst = New_ST (CURRENT_SYMTAB);
02386   ST_Init (new_initst,
02387            Save_Str ( ST_name(old_initst) ),
02388            ST_class(old_initst),
02389            ST_sclass(old_initst),
02390            ST_export(old_initst),
02391            ST_type(old_initst));
02392 
02393   new_initst->flags = old_initst->flags;
02394   new_initst->flags_ext = old_initst->flags_ext;
02395 
02396   Set_ST_is_not_used(*old_initst);
02397 
02398   new_inito = New_INITO ( new_initst );
02399 
02400   pinito = new_inito;
02401   parent = 0;
02402   prev = 0;
02403 
02404   // __Exc_Ptr__, __Exc_Filter__
02405   for (INT i = 0; i < 2; i++)
02406   {
02407     (void) Initv_Table.New_entry(new_initv);
02408     INITV& new_initv_ref = Initv_Table[new_initv];
02409     INITV& old_initv_ref = Initv_Table[old_initv];
02410     if (pinito) {
02411       Set_INITO_val(pinito, new_initv);
02412       pinito = 0;
02413     } else if (prev) {
02414       Set_INITV_next(prev, new_initv);
02415     }
02416     INITVKIND k = INITV_kind(old_initv);
02417     Is_True (k == INITVKIND_VAL,
02418              ("Unexpected initv kind during PU exception processing"));
02419     INITO_IDX inito = 0;
02420     ST_IDX st = TCON_uval(INITV_tc_val(old_initv_ref));
02421     if (st)
02422       st = Localize_Symbol (st, vtab);
02423     INITV_Set_VAL(new_initv_ref, Enter_tcon (Host_To_Targ (MTYPE_U4, st)),
02424                   INITV_repeat2(old_initv_ref));
02425     old_initv = INITV_next(old_initv);
02426     prev = new_initv;
02427   }
02428 
02429   INITO_IDX old_inito_array[2] = {0, 0};
02430   INITO_IDX new_inito_array[2] = {0, 0};
02431 
02432   // __TYPEINFO_TABLE__, __EH_SPEC_TABLE__
02433   for (INT i = 0; i < 2; i++)
02434   {
02435     (void) Initv_Table.New_entry(new_initv);
02436     INITV& new_initv_ref = Initv_Table[new_initv];
02437     INITV& old_initv_ref = Initv_Table[old_initv];
02438     if (prev)
02439       Set_INITV_next(prev, new_initv);
02440     INITVKIND k = INITV_kind(old_initv);
02441     Is_True (k == INITVKIND_VAL,
02442              ("Unexpected initv kind during typeinfo/EH-spec processing"));
02443 
02444     INITO_IDX inito = 0;
02445     ST_IDX st = TCON_uval(INITV_tc_val(old_initv_ref));
02446     if (st)
02447     {
02448       inito = (INITO_IDX) st;
02449       st = Localize_Symbol (INITO_st_idx(Inito_Table[inito]), vtab);
02450       INITO_IDX new_inito = New_INITO (st, INITO_val(inito));
02451 
02452       INITV_Set_VAL(new_initv_ref, Enter_tcon (Host_To_Targ (MTYPE_U4,
02453                                                              new_inito)),
02454                     INITV_repeat2(old_initv_ref));
02455       old_inito_array[i] = inito;
02456       new_inito_array[i] = new_inito;
02457     }
02458     else
02459       INITV_Set_VAL(new_initv_ref, Enter_tcon (Host_To_Targ (MTYPE_U4, st)),
02460                     INITV_repeat2(old_initv_ref));
02461     old_initv = INITV_next(old_initv);
02462     prev = new_initv;
02463   }
02464 
02465   for (INT i = 0; i < 2; i++) {
02466 
02467     // i == 0 : info in typeinfo table
02468     // i == 1 : info in exception-specification table
02469     old_initv = old_inito_array[i] ? INITO_val(old_inito_array[i]) : 0;
02470     pinito = new_inito_array[i];
02471     parent = prev = 0;
02472 
02473     while ( old_initv ) {
02474 
02475       (void) Initv_Table.New_entry(new_initv);
02476       INITV& new_initv_ref = Initv_Table[new_initv];
02477       INITV& old_initv_ref = Initv_Table[old_initv];
02478 
02479       if (pinito) {
02480         Set_INITO_val(pinito, new_initv);
02481         pinito = 0;
02482       } else if (parent) {
02483         Set_INITV_blk(parent, new_initv);
02484         parent = 0;
02485       } else if (prev) {
02486         Set_INITV_next(prev, new_initv);
02487       }
02488 
02489       INITVKIND k = INITV_kind(old_initv);
02490       switch ( k ) {
02491 
02492       case INITVKIND_ZERO:
02493         INITV_Set_ZERO(new_initv_ref, INITV_mtype(old_initv_ref),
02494                        INITV_repeat2(old_initv_ref));
02495         old_initv = INITV_next(old_initv);
02496         prev = new_initv;
02497         break;
02498 
02499       case INITVKIND_ONE:
02500         INITV_Set_ONE(new_initv_ref, INITV_mtype(old_initv_ref),
02501                       INITV_repeat2(old_initv_ref));
02502         old_initv = INITV_next(old_initv);
02503         prev = new_initv;
02504         break;
02505 
02506       case INITVKIND_VAL:
02507       {
02508         ST_IDX st = TCON_uval(INITV_tc_val(old_initv_ref));
02509         INITV_Set_VAL(new_initv_ref, Enter_tcon (Host_To_Targ (MTYPE_U4, st)),
02510                       INITV_repeat2(old_initv_ref));
02511         old_initv = INITV_next(old_initv);
02512         prev = new_initv;
02513       }
02514       break;
02515 
02516       case INITVKIND_BLOCK:
02517         INITV_Set_BLOCK(new_initv_ref, INITV_repeat1(old_initv_ref), 0);
02518         old_stack.Push(old_initv);
02519         new_stack.Push(new_initv);
02520         old_initv = INITV_blk(old_initv);
02521         parent = new_initv;
02522         prev = 0;
02523         break;
02524 
02525       default:
02526         Fail_FmtAssertion ( "unexpected INITV kind %d", (INT) k );
02527       }
02528 
02529       while (!old_initv && old_stack.Elements() > 0) {
02530         old_initv = INITV_next(old_stack.Pop());
02531         prev = new_stack.Pop();
02532       }
02533     }
02534   }
02535 
02536   return new_inito;
02537 }
02538 #endif
02539 
02540 static WN * Gen_MP_Store ( ST * st, WN_OFFSET offset, WN * value, 
02541          BOOL scalar_only = FALSE );
02542 
02543 /*
02544 Create MicroTask for Working threads.  This includes creating the following:
02545 the corresponding nested symbol table; entries for the TY, PU, and ST
02546 tables; debugging information; PU_Info object; and Whirl tree.
02547 Current_PU_Info is set to point to the new nested function, and the
02548 parallel function's symtab becomes CURRENT_SYMTAB.
02549 */
02550 
02551 static void 
02552 Create_MicroTask ( PAR_FUNC_TYPE func_type )
02553 {
02554   BOOL is_do32 = FALSE, is_do64 = FALSE, is_region = FALSE;
02555   switch (func_type) {  // validate input, set type flag
02556   case PAR_FUNC_DO32:
02557     is_do32 = TRUE;
02558     break;
02559   case PAR_FUNC_DO64:
02560     is_do64 = TRUE;
02561     break;
02562   case PAR_FUNC_REGION:
02563     is_region = TRUE;
02564     break;
02565   default:
02566     Fail_FmtAssertion("invalid parallel function type %d", (INT) func_type);
02567     break;
02568   }
02569 
02570     // should be merged up after done. Currently reserved for Debug
02571   const char *construct_type_str = is_region ? "ompregion" : "ompdo";
02572   char temp_str[64];
02573 
02574 
02575   // get function prototype
02576 
02577   TY_IDX &func_ty_idx = mpregion_ty;
02578 
02579   if  (func_ty_idx == TY_IDX_ZERO) {
02580     // create new type for function, and type for pointer to function
02581 
02582     TY& ty = New_TY(func_ty_idx);
02583     sprintf(temp_str, ".%s", construct_type_str);
02584     TY_Init(ty, 0, KIND_FUNCTION, MTYPE_UNKNOWN, Save_Str(temp_str));
02585     Set_TY_align(func_ty_idx, 1);
02586 
02587     TYLIST_IDX parm_idx;
02588     TYLIST& parm_list = New_TYLIST(parm_idx);
02589     Set_TY_tylist(ty, parm_idx);
02590     Set_TYLIST_type(parm_list, Be_Type_Tbl(MTYPE_V));  // return type
02591 
02592       // Two basic parameters
02593     Set_TYLIST_type(New_TYLIST(parm_idx), // gtid
02594                       Be_Type_Tbl(Pointer_type));
02595     Set_TYLIST_type(New_TYLIST(parm_idx), // btid
02596                       Be_Type_Tbl(Pointer_type));
02597 
02598     Set_TYLIST_type(New_TYLIST(parm_idx), TY_IDX_ZERO); // end of parm list
02599 
02600       // now create a type for a pointer to this function
02601     TY_IDX ptr_ty_idx;
02602     TY &ptr_ty = New_TY(ptr_ty_idx);
02603     sprintf(temp_str, ".%s_ptr", construct_type_str);
02604     TY_Init(ptr_ty, Pointer_Size, KIND_POINTER, Pointer_Mtype,
02605             Save_Str(temp_str));
02606     Set_TY_pointed(ptr_ty, func_ty_idx);
02607   }
02608 
02609 
02610   // generate new name for nested function
02611 
02612   INT32 mp_region_num;    // MP region number within parent PU
02613   INT32 mp_construct_num; // construct number within MP region
02614 
02615   if (mpnum_node)
02616     mp_region_num = WN_pragma_arg1(mpnum_node);
02617   else
02618       // should PAR regions and PAR DO's be numbered separately? -- DRK
02619     mp_region_num = ++(is_region ? region_id : do_id);
02620   mp_construct_num = mpid_table[mp_region_num]++;
02621 
02622   const char *old_st_name = ST_name(PU_Info_proc_sym(Current_PU_Info));
02623   char *st_name = (char *) alloca(strlen(old_st_name) + 32);
02624   if (mp_construct_num == 0)
02625     sprintf ( st_name, "__%s_%s%d", construct_type_str, old_st_name,
02626         mp_region_num );
02627   else
02628     sprintf ( st_name, "__%s_%s%d.%d", construct_type_str, old_st_name,
02629         mp_region_num, mp_construct_num );
02630 
02631 
02632   // create new PU and ST for nested function
02633 
02634   PU_IDX pu_idx;
02635   PU& pu = New_PU(pu_idx);
02636   PU_Init(pu, func_ty_idx, CURRENT_SYMTAB);
02637 
02638 /*
02639 Many questions of DRK's about flags:
02640 
02641 is_pure and no_side_effects shouldn't be set due to output ref. parms?
02642 does no_delete matter?
02643 have no idea: needs_fill_align_lowering, needs_t9, put_in_elf_section,
02644   has_return_address, has_inlines, calls_{set,long}jmp, namelist
02645 has_very_high_whirl and mp_needs_lno should have been handled already
02646 is inheriting pu_recursive OK?
02647 */
02648 
02649   Set_PU_no_inline(pu);
02650   Set_PU_is_nested_func(pu);
02651   Set_PU_mp(pu);
02652 #ifdef KEY
02653   Set_PU_mp_lower_generated(pu);
02654 #endif // KEY
02655     // child PU inherits language flags from parent
02656   if (PU_c_lang(Current_PU_Info_pu()))
02657     Set_PU_c_lang(pu);
02658   if (PU_cxx_lang(Current_PU_Info_pu()))
02659     Set_PU_cxx_lang(pu);
02660   if (PU_f77_lang(Current_PU_Info_pu()))
02661     Set_PU_f77_lang(pu);
02662   if (PU_f90_lang(Current_PU_Info_pu()))
02663     Set_PU_f90_lang(pu);
02664   if (PU_java_lang(Current_PU_Info_pu()))
02665     Set_PU_java_lang(pu);
02666 
02667   Set_FILE_INFO_has_mp(File_info);  // is this true after MP lowerer?--DRK
02668 
02669   parallel_proc = New_ST(GLOBAL_SYMTAB);
02670   ST_Init(parallel_proc,
02671           Save_Str (st_name),
02672           CLASS_FUNC,
02673           SCLASS_TEXT,
02674           EXPORT_LOCAL,
02675           pu_idx);
02676   Set_ST_addr_passed(parallel_proc);
02677 
02678   Allocate_Object ( parallel_proc );
02679 
02680 
02681   // create nested symbol table for parallel function
02682 
02683   New_Scope(CURRENT_SYMTAB + 1,
02684             Malloc_Mem_Pool,  // find something more appropriate--DRK
02685             TRUE);
02686   csymtab = CURRENT_SYMTAB;
02687   func_level = CURRENT_SYMTAB;
02688   Scope_tab[csymtab].st = parallel_proc;
02689 
02690   Set_PU_lexical_level(pu, CURRENT_SYMTAB);
02691 
02692   Create_Func_DST ( st_name );
02693 
02694 
02695   // pre-allocate in child as many pregs as there are in the parent
02696 
02697   for (UINT32 i = 1; i < PREG_Table_Size(psymtab); i++) {
02698     PREG_IDX preg_idx;
02699     PREG &preg = New_PREG(csymtab, preg_idx);
02700       // share name with corresponding parent preg
02701     Set_PREG_name_idx(preg,
02702       PREG_name_idx((*Scope_tab[psymtab].preg_tab)[preg_idx]));
02703   }
02704 
02705     // create ST's for parameters
02706 
02707   ST *arg_gtid = New_ST( CURRENT_SYMTAB );
02708   ST_Init (arg_gtid,
02709              Save_Str ( "__ompv_gtid_a" ),
02710              CLASS_VAR,
02711              SCLASS_FORMAL,
02712              EXPORT_LOCAL,
02713              Be_Type_Tbl(MTYPE_I4));
02714   Set_ST_is_value_parm( arg_gtid );
02715 
02716   ST *arg_slink = New_ST( CURRENT_SYMTAB );
02717   ST_Init( arg_slink,
02718            Save_Str( "__ompv_slink_a" ),
02719            CLASS_VAR,
02720            SCLASS_FORMAL,
02721            EXPORT_LOCAL,
02722            Be_Type_Tbl( Pointer_type ));
02723   Set_ST_is_value_parm( arg_slink );
02724 
02725     // TODO: other procedure specific arguments should
02726     // be handled here.
02727 
02728   // create WHIRL tree for nested function
02729 
02730   parallel_func = WN_CreateBlock ( );
02731   reference_block = WN_CreateBlock ( );
02732 #ifdef KEY
02733   WN *thread_priv_prag = WN_first(WN_func_pragmas(PU_Info_tree_ptr(Current_PU_Info)));
02734   if (thread_priv_prag) {
02735     while (thread_priv_prag) { 
02736       if (WN_opcode(thread_priv_prag) == OPC_PRAGMA &&
02737           WN_pragma(thread_priv_prag) == WN_PRAGMA_THREADPRIVATE) {
02738         WN_INSERT_BlockLast ( reference_block,
02739       WN_CreatePragma ( WN_PRAGMA_THREADPRIVATE,
02740                                           WN_st_idx(thread_priv_prag),
02741                         WN_pragma_arg1(thread_priv_prag), 
02742                                           WN_pragma_arg2(thread_priv_prag) ));
02743       }
02744       thread_priv_prag = WN_next(thread_priv_prag);
02745     }
02746   }
02747 #endif
02748   // Currently, don't pass data via arguments.
02749   WN *func_entry = WN_CreateEntry ( 2, parallel_proc,
02750                                     parallel_func, WN_CreateBlock ( ),
02751             reference_block );
02752 
02753   WN_kid0(func_entry) = WN_CreateIdname ( 0, arg_gtid );
02754   WN_kid1(func_entry) = WN_CreateIdname ( 0, arg_slink );
02755      // TODO: variable arguments list should be added here.
02756 
02757   WN_linenum(func_entry) = line_number;
02758 
02759   // The arg_slink contains slink for caller. should put into a 
02760   // implied temp var.
02761   ST *slink = Gen_Temp_Symbol (MTYPE_To_TY(Pointer_type), "__slink_sym");
02762 
02763   Is_True( slink != NULL, ("The slink should not be NULL"));
02764   WN *wn_store_slink = Gen_MP_Store( slink, 0,
02765            WN_Ldid( Pointer_type, 0, arg_slink, ST_type( arg_slink ), 0 ));
02766   WN_linenum( wn_store_slink ) = line_number;
02767   WN_INSERT_BlockLast( parallel_func, wn_store_slink );
02768 
02769   // to unify the process of Transform_Do and provide the 
02770   // possibility to promote gtid to preg, we stroe the value
02771   // of gtid in another temp vars.
02772   // The gtid can be eniminated, since the symbol of arguments are also 
02773   // local storage.
02774   Create_Temp( MTYPE_I4, "gtid", &local_gtid );
02775   WN *wn_store_gtid = Gen_MP_Store( local_gtid, 0,
02776       WN_Ldid( MTYPE_I4, 0, arg_gtid, ST_type(arg_gtid), 0 ));
02777 //      WN_IloadLdid( MTYPE_I4, 0, Be_Type_Tbl( MTYPE_I4 ), arg_gtid, 0 ));
02778   WN_linenum( wn_store_gtid ) = line_number;
02779   WN_INSERT_BlockLast( parallel_func, wn_store_gtid );    
02780   // create PU_Info for nested function
02781 
02782 
02783   PU_Info *parallel_pu = TYPE_MEM_POOL_ALLOC ( PU_Info, Malloc_Mem_Pool );
02784   PU_Info_init ( parallel_pu );
02785   Set_PU_Info_tree_ptr (parallel_pu, func_entry );
02786   verify_mp_lowered_ptr->Set_nested_pu_tree(func_entry);
02787 
02788   PU_Info_proc_sym(parallel_pu) = ST_st_idx(parallel_proc);
02789   PU_Info_maptab(parallel_pu) = cmaptab = WN_MAP_TAB_Create(MEM_pu_pool_ptr);
02790   PU_Info_pu_dst(parallel_pu) = nested_dst;
02791   Set_PU_Info_state(parallel_pu, WT_SYMTAB, Subsect_InMem);
02792   Set_PU_Info_state(parallel_pu, WT_TREE, Subsect_InMem);
02793   Set_PU_Info_state(parallel_pu, WT_PROC_SYM, Subsect_InMem);
02794   Set_PU_Info_flags(parallel_pu, PU_IS_COMPILER_GENERATED);
02795 
02796     // use hack to save csymtab using parallel_pu, so we can restore it
02797     // later when we lower parallel_pu; this is necessary because the
02798     // new symtab routines can't maintain more than one chain of symtabs
02799     // in memory at one time, and we lower the parent PU all the way to
02800     // CG before we lower any of the nested MP PUs
02801         // Save_Local_Symtab expects this
02802   Set_PU_Info_symtab_ptr(parallel_pu, NULL);
02803   Save_Local_Symtab(csymtab, parallel_pu);
02804 
02805   Is_True(PU_Info_state(parallel_pu, WT_FEEDBACK) == Subsect_Missing,
02806           ("there should be no feedback for parallel_pu"));
02807   if (Cur_PU_Feedback) {
02808 #ifdef KEY
02809     parallel_pu_fb = CXX_NEW(FEEDBACK(func_entry,
02810                                       MEM_pu_nz_pool_ptr,
02811                                       1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
02812                                       cmaptab),
02813                              MEM_pu_nz_pool_ptr);
02814 #else
02815     parallel_pu_fb = CXX_NEW(FEEDBACK(func_entry,
02816                                       MEM_pu_nz_pool_ptr,
02817               1, 1, 1, 1, 1, 1,
02818               cmaptab),
02819                  MEM_pu_nz_pool_ptr);
02820 #endif
02821     Set_PU_Info_state(parallel_pu, WT_FEEDBACK, Subsect_InMem);
02822     Set_PU_Info_feedback_ptr(parallel_pu, parallel_pu_fb);
02823         // Note that unlike every other kind of map, the FEEDBACK map for
02824         // the child PU is read and written by the MP lowerer. Therefore
02825         // we copy over all the relevant values here, and don't transfer
02826         // the parent FEEDBACK map at the end of MP lowerering.
02827     FB_Transfer(Cur_PU_Feedback, parallel_pu_fb, stmt_block);
02828   }
02829 
02830   RID *root_rid = RID_Create ( 0, 0, func_entry );
02831   RID_type(root_rid) = RID_TYPE_func_entry;
02832   Set_PU_Info_regions_ptr ( parallel_pu, root_rid );
02833   Is_True(PU_Info_regions_ptr(parallel_pu) != NULL,
02834    ("Create_MicroTask, NULL root RID"));
02835 
02836   PU_Info *tpu = PU_Info_child(Current_PU_Info);
02837 
02838     // add parallel_pu after last child MP PU_Info item in parent's list
02839   if (tpu && PU_Info_state(tpu, WT_SYMTAB) == Subsect_InMem &&
02840       PU_mp(PU_Info_pu(tpu)) ) {
02841     PU_Info *npu;
02842 
02843     while ((npu = PU_Info_next(tpu)) &&
02844      PU_Info_state(npu, WT_SYMTAB) == Subsect_InMem &&
02845      PU_mp(PU_Info_pu(npu)) )
02846       tpu = npu;
02847 
02848     PU_Info_next(tpu) = parallel_pu;
02849     PU_Info_next(parallel_pu) = npu;
02850   } else {
02851     PU_Info_child(Current_PU_Info) = parallel_pu;
02852     PU_Info_next(parallel_pu) = tpu;
02853   }
02854 
02855 
02856   // change some global state; need to clean this up--DRK
02857 
02858   Current_PU_Info = parallel_pu;
02859   Current_pu = &Current_PU_Info_pu();
02860   Current_Map_Tab = pmaptab;
02861 
02862   Add_DST_variable ( arg_gtid, nested_dst, line_number, DST_INVALID_IDX );
02863   Add_DST_variable ( arg_slink, nested_dst, line_number, DST_INVALID_IDX );
02864 
02865 }
02866 
02867 /*  Create either a preg or a temp depending on presence of C++ exception
02868     handling.  */
02869 
02870 static void 
02871 Create_Preg_or_Temp ( TYPE_ID mtype, const char *name, ST **st,
02872           WN_OFFSET *ofst )
02873 {
02874   ST *new_st;
02875 
02876   if (!pu_has_eh) {
02877     *st = MTYPE_To_PREG ( mtype );
02878     *ofst = Create_Preg (mtype, name);
02879   } else {
02880     new_st = New_ST (CURRENT_SYMTAB);
02881     ST_Init (new_st,
02882              Save_Str2 ( "__ompv_temp_", name ),
02883              CLASS_VAR,
02884              SCLASS_AUTO,
02885              EXPORT_LOCAL,
02886              MTYPE_To_TY (mtype));
02887     Set_ST_is_temp_var ( new_st );
02888     *st = new_st;
02889     *ofst = 0;
02890   }
02891 }
02892 
02893 
02894 /*
02895 If tree is the test for whether a thread is the MASTER, return TRUE, else
02896 return FALSE.
02897 
02898 The test for being the MASTER consists of checking whether a PREG called
02899 thread_num is 0.  thread_num is set by code preceding the "if" to be the
02900 result of calling omp_get_thread_num().
02901 */
02902 
02903 static BOOL 
02904 Is_Master_Test(WN *tree)
02905 {
02906   if (WN_operator(tree) != OPR_EQ)
02907     return FALSE;
02908 
02909   WN *wn_ldid;
02910 
02911   if (WN_operator(WN_kid(tree, 0)) == OPR_LDID)
02912     wn_ldid = WN_kid(tree, 0);
02913   else if (WN_operator(WN_kid(tree, 1)) == OPR_LDID)
02914     wn_ldid = WN_kid(tree, 1);
02915   else
02916     return FALSE;
02917 
02918   WN *wn_intconst = (wn_ldid == WN_kid(tree, 0)) ? WN_kid(tree, 1) :
02919     WN_kid(tree, 0);
02920 
02921   if (WN_operator(wn_intconst) != OPR_INTCONST)
02922     return FALSE;
02923 
02924   if (WN_const_val(wn_intconst) != 1 ||
02925 #ifdef KEY // bug 6282
02926       WN_class(wn_ldid) != CLASS_PREG ||
02927 #endif
02928       Preg_Is_Dedicated(WN_offset(wn_ldid)) ||
02929       strcmp(IS_MASTER_PREG_NAME, Preg_Name(WN_offset(wn_ldid))) != 0)
02930     return FALSE;
02931 
02932   return TRUE;
02933 }
02934 
02935 
02936 /*
02937 If tree is the test for whether a thread should enter a SINGLE section,
02938 return TRUE, else return FALSE.
02939 
02940 The test for entering a SINGLE consists of checking whether a PREG called
02941 MPSP_STATUS_PREG_NAME is a non-0 value.  The PREG is set by code preceding
02942 the "if" to be the result of calling omp_begin_single_process() or
02943 mp_begin_single_process().
02944 */
02945 
02946 static BOOL 
02947 Is_Single_Test(WN *tree)
02948 {
02949   if (WN_operator(tree) != OPR_LDID ||
02950 #ifdef KEY // bug 5118
02951       WN_class(tree) != CLASS_PREG ||
02952 #endif
02953       Preg_Is_Dedicated(WN_offset(tree)) ||
02954       strcmp(MPSP_STATUS_PREG_NAME, Preg_Name(WN_offset(tree))) != 0)
02955 
02956     return FALSE;
02957 
02958   return TRUE;
02959 }
02960 
02961 
02962 /*
02963 If the root of tree is a SINGLE, MASTER, CRITICAL, or ATOMIC construct (and
02964 therefore guards all the WNs below it), enter all nodes guarded by tree
02965 into guarded_set; otherwise, do nothing.
02966 
02967 Only recursive calls should use optional parameter tree_is_guarded.
02968 */
02969 
02970 static void
02971 Enter_Guarded_WNs(WN_TO_BOOL_HASH *guarded_set, WN *tree,
02972                   BOOL tree_is_guarded = FALSE) // only used for recursion
02973 {
02974   if (tree_is_guarded) {
02975       // enter entire tree recursively
02976     guarded_set->Enter(tree, TRUE);
02977 
02978     if (!OPCODE_is_leaf(WN_opcode(tree))) {
02979       if (WN_opcode(tree) == OPC_BLOCK) {
02980         for (WN *kid = WN_first(tree); kid; kid = WN_next(kid))
02981           Enter_Guarded_WNs(guarded_set, kid, TRUE);
02982       } else {
02983         for (INT kidno = 0; kidno < WN_kid_count(tree); kidno++) {
02984           WN *kid = WN_kid(tree, kidno);
02985           if (kid)
02986             Enter_Guarded_WNs(guarded_set, kid, TRUE);
02987         }
02988       }
02989     }
02990 
02991     return;
02992   }
02993 
02994 /*
02995 The lowered WHIRL for the guarding MP constructs is as follows:
02996 
02997   MASTER:
02998     "then" block of "if" passes Is_Master_Test()
02999   SINGLE:
03000     "then" block of "if" passes Is_Single_Test()
03001   named CRITICAL:
03002     everything between matching OPC_VCALL(MPR_GETLOCK) and
03003       OPC_VCALL(MPR_UNLOCK) is guarded
03004   unnamed CRITICAL:
03005     everything between OPC_VCALL(MPR_SETLOCK) and OPC_VCALL(MPR_UNSETLOCK)
03006       is guarded
03007   ATOMIC:
03008     Lowered in 3 different ways.  One is as a CRITICAL section (handled as
03009     above).  The other two are as intrinsic calls, in which case we get
03010     help from a routine in the OMP Prelowerer.  Only the LDA for the scalar
03011     variable or array base being atomically updated needs to be guarded.
03012 */
03013 
03014   if (WN_operator(tree) == OPR_INTRINSIC_CALL) {
03015     WN *lda = Get_ATOMIC_Update_LDA(tree);
03016     if (lda) {
03017       guarded_set->Enter(lda, TRUE);
03018       return;
03019     }
03020   }
03021 
03022   OPCODE opc = WN_opcode(tree);
03023   ST_IDX end_st, end_name_st = ST_IDX_ZERO;
03024 
03025   switch (opc) {
03026   case OPC_IF:
03027     if (Is_Master_Test(WN_if_test(tree)) ||
03028         Is_Single_Test(WN_if_test(tree)) )
03029       Enter_Guarded_WNs(guarded_set, WN_then(tree), TRUE);
03030     return;
03031   case OPC_VCALL:
03032 /* To modify (1)MPR_GETLOCK ---> MPR_CRITICAL 
03033              (2)MPR_UNLOCK ---> MPR_END_CRITICAL 
03034              (3)MPR_SETLOCK ---> MPR_CRITICAL
03035              (4)MPR_UNSETLOCK ---> MPR_END_CRITICAL
03036         By lg !
03037 */ 
03038 /*
03039     if (WN_st_idx(tree) == GET_MPRUNTIME_ST(MPR_GETLOCK)) { // named CRITICAL
03040       end_st = GET_MPRUNTIME_ST(MPR_UNLOCK);
03041         // call has one PARM child that's an LDA of the lock var.
03042       end_name_st = WN_st_idx(WN_kid0(WN_kid0(tree)));
03043     } else if (WN_st_idx(tree) == GET_MPRUNTIME_ST(MPR_SETLOCK)) {
03044         // unnamed CRITICAL
03045       end_st = GET_MPRUNTIME_ST(MPR_UNSETLOCK);
03046 */
03047     if (WN_st_idx(tree) == GET_MPRUNTIME_ST(MPR_OMP_CRITICAL)) { 
03048     // named CRITICAL and unnamed CRITICAL
03049       end_st = GET_MPRUNTIME_ST(MPR_OMP_END_CRITICAL);
03050         // call has one PARM child that's an LDA of the lock var.
03051       end_name_st = WN_st_idx(WN_kid0(WN_kid0(tree)));
03052     } else
03053       return;
03054     break;
03055   default:
03056     return; // not a guarding construct
03057   }
03058 
03059   Is_True(opc == OPC_VCALL,
03060           ("should be looking for call that marks end of guarded code"));
03061 
03062     // add all nodes in CRITICAL section to guarded_set, warning if we
03063     // can't find the matching CRITICAL END
03064   DYN_ARRAY<WN *> nodes_in_critsect(Malloc_Mem_Pool);
03065 
03066   for (WN *guarded_wn = WN_next(tree); guarded_wn;
03067        guarded_wn = WN_next(guarded_wn)) {
03068     if (WN_opcode(guarded_wn) == OPC_VCALL &&
03069         WN_st_idx(guarded_wn) == end_st &&
03070         (!end_name_st || WN_st_idx(WN_kid0(WN_kid0(guarded_wn))) ==
03071                              end_name_st) )
03072       break;  // found matching CRITICAL END
03073     nodes_in_critsect.AddElement(guarded_wn);
03074   }
03075 //  if (!guarded_wn)
03076 //    DevWarn("Enter_Guarded_WNs() did not find matching CRITICAL END");
03077 
03078   for (INT i = 0; i <= nodes_in_critsect.Lastidx(); i++)
03079     Enter_Guarded_WNs(guarded_set, nodes_in_critsect[i], TRUE);
03080 }
03081 
03082 
03083 /*  Walk tree to locate all uplevel references and build list of them.
03084     guarded_set is the set of WNs guarded by SINGLE or MASTER constructs;
03085     guared stores to non-SHARED STs do not elicit a warning message. */
03086 
03087 static void 
03088 Gather_Uplevel_References ( WN * block, INT32 level, WN * parent,
03089           WN * grandparent, WN * tree,
03090           WN_TO_BOOL_HASH *guarded_set )
03091 {
03092   WN *wn;
03093   WN *node;
03094   INT32 i;
03095   ST *st;
03096   OPCODE op;
03097   OPERATOR opr;
03098 
03099   BOOL a_pointer;
03100   WN_PRAGMA_ACCESSED_FLAGS flags;
03101 
03102   Is_True(level >= 2, ("impossible symtab level == %d", level));
03103 
03104   if (tree) {
03105 
03106     Enter_Guarded_WNs(guarded_set, tree);
03107 
03108     op = WN_opcode(tree);
03109     opr = WN_operator(tree);
03110 
03111     if (op == OPC_LOOP_INFO)
03112       return;
03113 
03114     if (op == OPC_BLOCK)
03115       for (node = WN_first(tree); node; node = WN_next(node))
03116   Gather_Uplevel_References ( block, level, tree, parent, node,
03117                               guarded_set );
03118     else
03119       for (i = 0; i < WN_kid_count(tree); i++)
03120   Gather_Uplevel_References ( block, level, tree, parent,
03121             WN_kid(tree, i), guarded_set );
03122 
03123     if (OPCODE_has_sym(op) && (st = WN_st(tree)) != NULL &&
03124         ST_level(st) < level && ST_class(st) == CLASS_VAR) {
03125 
03126       a_pointer = (TY_kind(ST_type(st)) == KIND_POINTER);
03127 
03128       if (opr == OPR_LDID && !a_pointer)
03129          flags = ACCESSED_LOAD;
03130       else if (opr == OPR_STID)
03131          flags = ACCESSED_STORE;
03132       else if ((opr == OPR_LDA) && !a_pointer)
03133         if (WN_operator(parent) == OPR_ILOAD)
03134            flags = ACCESSED_LOAD;
03135         else if (WN_operator(parent) == OPR_ISTORE)
03136            flags = ACCESSED_STORE;
03137         else if (WN_operator(parent) == OPR_ARRAY)
03138           if (WN_operator(grandparent) == OPR_ILOAD)
03139              flags = ACCESSED_LOAD;
03140           else if (WN_operator(grandparent) == OPR_ISTORE)
03141              flags = ACCESSED_STORE;
03142           else
03143             flags = (WN_PRAGMA_ACCESSED_FLAGS) (ACCESSED_LOAD |
03144                      ACCESSED_STORE |
03145                      ACCESSED_ILOAD |
03146                      ACCESSED_ISTORE);
03147         else
03148            flags = (WN_PRAGMA_ACCESSED_FLAGS) (ACCESSED_LOAD |
03149                 ACCESSED_STORE |
03150                 ACCESSED_ILOAD |
03151                 ACCESSED_ISTORE);
03152       else if ((opr == OPR_LDID) && a_pointer)
03153         if (WN_operator(parent) == OPR_ILOAD)
03154           flags = (WN_PRAGMA_ACCESSED_FLAGS) (ACCESSED_LOAD |
03155                 ACCESSED_ILOAD);
03156         else if (WN_operator(parent) == OPR_ISTORE)
03157           flags = (WN_PRAGMA_ACCESSED_FLAGS) (ACCESSED_LOAD |
03158                 ACCESSED_ISTORE);
03159         else if (WN_operator(parent) == OPR_ARRAY)
03160           if (WN_operator(grandparent) == OPR_ILOAD)
03161              flags = (WN_PRAGMA_ACCESSED_FLAGS) (ACCESSED_LOAD |
03162                       ACCESSED_ILOAD);
03163           else if (WN_operator(grandparent) == OPR_ISTORE)
03164              flags = (WN_PRAGMA_ACCESSED_FLAGS) (ACCESSED_LOAD |
03165                       ACCESSED_ISTORE);
03166         else
03167              flags = (WN_PRAGMA_ACCESSED_FLAGS) (ACCESSED_LOAD |
03168                       ACCESSED_STORE |
03169                       ACCESSED_ILOAD |
03170                       ACCESSED_ISTORE);
03171       else
03172         flags = (WN_PRAGMA_ACCESSED_FLAGS) (ACCESSED_LOAD |
03173             ACCESSED_STORE |
03174             ACCESSED_ILOAD |
03175             ACCESSED_ISTORE);
03176     else
03177         flags = (WN_PRAGMA_ACCESSED_FLAGS) (ACCESSED_LOAD |
03178               ACCESSED_STORE |
03179               ACCESSED_ILOAD |
03180               ACCESSED_ISTORE);
03181 
03182       wn = WN_first(block);
03183       while (wn && (WN_st(wn) < st))
03184           wn = WN_next(wn);
03185       if (wn && (WN_st(wn) == st))
03186          WN_pragma_arg2(wn) |= flags;
03187       else {
03188         const ST_SCLASS sclass = ST_sclass(st);
03189 
03190         if (sclass == SCLASS_AUTO || sclass == SCLASS_FORMAL_REF ||
03191             sclass == SCLASS_FORMAL || sclass == SCLASS_PSTATIC)
03192           Set_ST_has_nested_ref ( st );
03193 
03194   WN_INSERT_BlockBefore ( block, wn,
03195         WN_CreatePragma ( WN_PRAGMA_ACCESSED_ID, st, 0,
03196               flags ));
03197       }
03198 
03199       if ((flags & ACCESSED_STORE) && (TY_kind(ST_type(st)) == KIND_SCALAR)) {
03200   for (i = 0; (i < shared_count) && (st != shared_table[i]); i++) { }
03201   if (i == shared_count) {
03202     ST *split_blk, *common_blk = ST_Source_COMMON_Block(st, &split_blk);
03203     BOOL is_threadprivate_common =
03204       (ST_is_thread_private(st)) ||
03205       (split_blk && ST_is_thread_private(split_blk)) ||
03206       (common_blk && ST_is_thread_private(common_blk));
03207 
03208           if (!Is_NameLock_ST(st) &&
03209               !is_threadprivate_common &&
03210               !guarded_set->Find(tree) &&
03211 #ifdef KEY
03212               strncmp(ST_name(st), "__thdprv", 8) &&
03213 #endif
03214               !comp_gen_construct) {
03215 #ifdef KEY
03216             USRCPOS srcpos;
03217             USRCPOS_srcpos(srcpos) = WN_Get_Linenum(tree);
03218             Set_Error_Line(USRCPOS_linenum(srcpos));
03219 #endif
03220             ErrMsg ( EC_MPLOWER_shared_store, st );
03221           }
03222     shared_table[shared_count++] = st;
03223   }
03224       }
03225 
03226     }
03227 
03228     if (((op == OPC_U4INTRINSIC_CALL) &&
03229    (WN_intrinsic(tree) == INTRN_U4I4ALLOCA)) ||
03230   ((op == OPC_U8INTRINSIC_CALL) &&
03231    (WN_intrinsic(tree) == INTRN_U8I8ALLOCA))) {
03232       Is_True(!Alloca_Dealloca_On,
03233               ("Alloca_Dealloca_On yet found INTRN_ALLOCA"));
03234       pu_has_alloca = TRUE;
03235     }
03236 
03237     if (opr == OPR_ALLOCA) {
03238       Is_True(Alloca_Dealloca_On,
03239               ("found OPR_ALLOCA yet not Alloca_Dealloca_On"));
03240       pu_has_alloca = TRUE;
03241     }
03242 
03243     if (op == OPC_REGION)
03244       pu_has_region = TRUE;
03245 
03246   }
03247 }
03248 
03249 
03250 /*  Walk tree gathering information about all interesting preg usage.  */
03251 
03252 static void 
03253 Walk_and_Info_Pregs ( WN * tree )
03254 {
03255   WN *node;
03256   INT32 i;
03257   OPCODE op;
03258 
03259   if (tree) {
03260 
03261     op = WN_opcode(tree);
03262     if (op == OPC_BLOCK)
03263       for (node = WN_first(tree); node; node = WN_next(node))
03264   Walk_and_Info_Pregs ( node );
03265     else
03266       for (i = 0; i < WN_kid_count(tree); i++)
03267   Walk_and_Info_Pregs ( WN_kid(tree, i) );
03268 
03269     if (OPCODE_has_sym(op) && OPCODE_has_offset(op) && WN_st(tree) &&
03270 #ifdef KEY // bug 11914: if OPC_PRAGMA, WN_offsetx will not return correct pnum
03271         op != OPC_PRAGMA &&
03272 #endif
03273         (ST_class(WN_st(tree)) == CLASS_PREG) &&
03274         !Preg_Is_Dedicated(WN_offsetx(tree))) {
03275       PREG_IDX pnum = Get_Preg_Idx(WN_offsetx(tree));
03276 
03277       PREG_INFO *preg = &preg_info_table->at(pnum);
03278 
03279       if (preg->type == MTYPE_UNKNOWN)
03280   preg->type = ST_btype(WN_st(tree));
03281     }
03282   }
03283 }
03284 
03285 
03286 /*  Walk tree replacing livein/out parent pregs with temps.  */
03287 
03288 static void
03289 Walk_and_Replace_Pregs ( WN * tree )
03290 {
03291   WN *node;
03292   INT32 i;
03293   OPCODE op;
03294   PREG_INFO *preg;
03295 
03296   if (tree) {
03297 
03298     op = WN_opcode(tree);
03299     if (op == OPC_BLOCK)
03300       for (node = WN_first(tree); node; node = WN_next(node))
03301   Walk_and_Replace_Pregs ( node );
03302     else
03303       for (i = 0; i < WN_kid_count(tree); i++)
03304   Walk_and_Replace_Pregs ( WN_kid(tree, i) );
03305 
03306     if (OPCODE_has_sym(op) && OPCODE_has_offset(op) && WN_st(tree) &&
03307   (ST_class(WN_st(tree)) == CLASS_PREG) &&
03308   !Preg_Is_Dedicated(WN_offsetx(tree)) ) {
03309       preg = &preg_info_table->at(Get_Preg_Idx(WN_offsetx(tree)));
03310 
03311       if (preg->temp && (preg->pclass != PCLASS_COPYIN_DEADOUT)) {
03312         WN_st_idx(tree) = ST_st_idx(preg->temp);
03313         WN_set_offsetx(tree, 0);
03314       }
03315 
03316     }
03317   }
03318 }
03319 
03320 
03321 /*
03322 Translate a label in sequential code to an equivalent label in MP code. If
03323 the equivalent MP label doesn't exist then create it.  For orphaned
03324 constructs, just return the input label--no translation needed, since we
03325 don't copy the MP code or move it into a nested scope.
03326 */
03327 
03328 // scrutinize all uses of St_Table and Label_Table to make sure they
03329 // refer to the right symtab level -- DRK
03330 
03331 static LABEL_IDX 
03332 Translate_Label ( LABEL_IDX plabel_idx )
03333 {
03334   if (plabel_idx == LABEL_IDX_ZERO)
03335     return LABEL_IDX_ZERO;
03336 
03337   if (mpt == MPP_ORPHANED_SINGLE || mpt == MPP_ORPHANED_PDO)
03338     return plabel_idx;
03339 
03340   LABEL_IDX clabel_idx = label_info_table[LABEL_IDX_index(plabel_idx)];
03341 
03342   if (clabel_idx == LABEL_IDX_ZERO) {
03343       // remove when symtab-setting stuff gets cleaned up--DRK
03344     Is_True(csymtab != SYMTAB_IDX_ZERO, ("child symtab not created yet"));
03345     Is_True(psymtab != SYMTAB_IDX_ZERO, ("psymtab not set yet"));
03346     Is_True(psymtab < csymtab,
03347             ("fishy-looking psymtab %d and/or csymtab %d",
03348        (INT) psymtab, (INT) csymtab));
03349     Is_True(CURRENT_SYMTAB == csymtab, ("CURRENT_SYMTAB != csymtab"));
03350     char* Cur_PU_Name = ST_name(PU_Info_proc_sym(Current_PU_Info));
03351     INT strsize = strlen(User_Label_Number_Format) + 64 + strlen(Cur_PU_Name);
03352     char* labelname = (char*) calloc(strsize, 1);
03353     sprintf ( labelname, User_Label_Number_Format, (INT) csymtab,
03354         (INT) plabel_idx, ST_name(Get_Current_PU_ST()) );
03355 
03356     LABEL &clabel = New_LABEL(csymtab, clabel_idx);
03357     LABEL_Init(clabel, Save_Str(labelname),
03358                LABEL_kind((*Scope_tab[psymtab].label_tab)[LABEL_IDX_index(plabel_idx)]));
03359     label_info_table[LABEL_IDX_index(plabel_idx)] = clabel_idx;
03360   }
03361   
03362   return clabel_idx;
03363 }
03364 
03365 /* Return TRUE if the symbol st is of type KIND_ARRAY or KIND_ARRAY*
03366  * From be/lno/ipa_lno_read.cxx, for ARRAY_REDUCTION. csc.
03367  */
03368 static BOOL
03369 Is_Kind_Array(const ST* st)
03370 {
03371   TY_IDX ty_idx = ST_type(st);
03372   if (TY_kind(ty_idx) == KIND_POINTER)
03373     ty_idx = TY_pointed(ty_idx);
03374   return TY_kind(ty_idx) == KIND_ARRAY;
03375 }
03376 
03377 /*
03378 Return TRUE if upper and lower bounds of each dimension of arr_ty are
03379 defined, FALSE otherwise. arr_ty must be an array type.
03380 */
03381 
03382 static BOOL 
03383 TY_All_Bounds_Defined(TY_IDX arr_ty)
03384 {
03385   Is_True(TY_kind(arr_ty) == KIND_ARRAY, ("not an array type"));
03386 
03387   INT i;
03388   for (i = 0; i < TY_AR_ndims(arr_ty); i++) {
03389     if (!TY_AR_const_lbnd(arr_ty, i) &&
03390         TY_AR_lbnd_var(arr_ty, i) == 0)
03391       return FALSE; // lower bound not defined
03392     if (!TY_AR_const_ubnd(arr_ty, i) &&
03393         TY_AR_ubnd_var(arr_ty, i) == 0)
03394       return FALSE; // upper bound not defined
03395   }
03396 
03397   return TRUE;
03398 } // TY_All_Bounds_Defined()
03399 
03400 
03401 /*  Calculate size of a dynamic array (in bytes).  */
03402 
03403 static WN * 
03404 Calculate_Array_Size ( ST * st, TY_IDX ty )
03405 {
03406   INT32 i;
03407   WN   *wn;
03408   WN   *lower = NULL;
03409   WN   *upper = NULL;
03410   const OPCODE int_opc = (Pointer_Size == 4) ? OPC_I4INTCONST :
03411                          (Pointer_Size == 8) ? OPC_I8INTCONST : OPCODE_UNKNOWN;
03412   const mTYPE_ID int_mtype = (int_opc == OPC_I4INTCONST) ? MTYPE_I4 : MTYPE_I8;
03413 
03414   Is_True(int_opc != OPCODE_UNKNOWN, ("invalid Pointer_Size"));
03415 
03416   wn = WN_CreateIntconst ( int_opc, TY_size(TY_AR_etype(ty)) );
03417   for (i = 0; i < TY_AR_ndims(ty); i++) {
03418     if (TY_AR_const_lbnd(ty, i))
03419       lower = WN_CreateIntconst ( int_opc, TY_AR_lbnd_val(ty, i) );
03420     else {
03421       if (TY_AR_lbnd_var(ty,i)) {
03422         lower = WN_CreateLdid (OPCODE_make_op(OPR_LDID,
03423                                 TY_mtype(ST_type(TY_AR_lbnd_var(ty,i))),
03424                                 TY_mtype(ST_type(TY_AR_lbnd_var(ty,i)))),
03425                                0, TY_AR_lbnd_var(ty,i),
03426                                ST_type(TY_AR_lbnd_var(ty,i)));
03427       }
03428       else lower = NULL;
03429     }
03430     if (TY_AR_const_ubnd(ty, i))
03431       upper = WN_CreateIntconst ( int_opc, TY_AR_ubnd_val(ty, i) );
03432     else {
03433       if (TY_AR_ubnd_var(ty,i)) {
03434         upper = WN_CreateLdid (OPCODE_make_op(OPR_LDID,
03435                                  TY_mtype(ST_type(TY_AR_ubnd_var(ty,i))),
03436                                  TY_mtype(ST_type(TY_AR_ubnd_var(ty,i)))),
03437                                0, TY_AR_ubnd_var(ty,i),
03438                                ST_type(TY_AR_ubnd_var(ty,i)));
03439       }
03440       else upper = NULL;
03441     }
03442     if (upper && lower) {
03443       wn = WN_Mpy ( int_mtype, wn, WN_Add ( int_mtype,
03444               WN_Sub ( int_mtype, upper, lower ),
03445               WN_CreateIntconst ( int_opc,
03446                 1 )));
03447     } else {
03448       ErrMsg ( EC_MPLOWER_local_nosize, st );
03449       WN_DELETE_Tree (wn);
03450       wn = WN_CreateIntconst ( int_opc, 0 );
03451       break;
03452     }
03453   }
03454 
03455   return (wn);
03456 }
03457 
03458 // Return a Whirl BLOCK for allocating a VLA auto variable using ALLOCA.
03459 static WN *
03460 Gen_Auto_Alloca(ST *st, WN_OFFSET offset, TY_IDX ty, WN *size)
03461 {
03462   WN *block = WN_CreateBlock(), *vla_stid_kid;
03463 
03464   if (Alloca_Dealloca_On) {
03465       // use ALLOCA operator
03466     vla_stid_kid = WN_CreateAlloca(size);
03467 
03468   } else {
03469       // Call ALLOCA intrinsic
03470     WN *intrin_call = WN_Create(
03471       (Pointer_Size == 4) ? OPC_U4INTRINSIC_CALL : OPC_U8INTRINSIC_CALL, 1);
03472     WN_intrinsic(intrin_call) = (Pointer_Size == 4) ? INTRN_U4I4ALLOCA :
03473                                 INTRN_U8I8ALLOCA;
03474     WN_Set_Call_Non_Data_Mod(intrin_call);
03475     WN_Set_Call_Non_Data_Ref(intrin_call);
03476     WN_Set_Call_Non_Parm_Mod(intrin_call);
03477     WN_Set_Call_Non_Parm_Ref(intrin_call);
03478     WN_Set_Call_Parm_Ref(intrin_call);
03479     WN_linenum(intrin_call) = line_number;
03480     WN_kid(intrin_call, 0) = WN_CreateParm(
03481       (Pointer_Size == 4) ? MTYPE_I4 : MTYPE_I8, size,
03482       Be_Type_Tbl((Pointer_Size == 4) ? MTYPE_I4 : MTYPE_I8),
03483       WN_PARM_BY_VALUE);
03484 
03485     WN_INSERT_BlockLast(block, intrin_call);
03486 
03487       // Load returned value
03488     PREG_NUM rreg1, rreg2;
03489 
03490     GET_RETURN_PREGS(rreg1, rreg2, Pointer_type);
03491     vla_stid_kid = WN_LdidPreg(Pointer_type, rreg1);
03492   }
03493 
03494   WN *vla_stid = WN_Stid(Pointer_type, offset, st, ty, vla_stid_kid);
03495   WN_linenum(vla_stid) = line_number;
03496   WN_INSERT_BlockLast(block, vla_stid);
03497 
03498   return block;
03499 }
03500 
03501 
03502 // A VLA that is scoped within a parallel construct
03503 // will have its ALLOCA generated by the front end,
03504 // and it doesn't need a new ALLOCA when localized.
03505 
03506 static vector<ST*> inner_scope_vla;
03507 
03508 static void 
03509 Gather_Inner_Scope_Vlas(WN *wn)
03510 {
03511   if (WN_operator(wn) == OPR_STID && WN_operator(WN_kid0(wn)) == OPR_ALLOCA) {
03512     inner_scope_vla.push_back(WN_st(wn));    
03513   }
03514   else if (WN_operator(wn) == OPR_BLOCK) {
03515     for (WN *kid = WN_first(wn); kid; kid = WN_next(kid)) {
03516       Gather_Inner_Scope_Vlas(kid);
03517     }
03518   }
03519   else {
03520     for (INT kidno = 0; kidno < WN_kid_count(wn); kidno++) {
03521       Gather_Inner_Scope_Vlas(WN_kid(wn, kidno));
03522     }
03523   }
03524 }
03525 
03526 static BOOL
03527 Vla_Needs_Alloca(ST *st)
03528 {
03529   vector<ST*>::iterator i;
03530   for (i = inner_scope_vla.begin(); i != inner_scope_vla.end(); i++) {
03531     if (*i == st) {
03532       return FALSE;
03533     }
03534   }
03535   return TRUE;
03536 } 
03537 
03538 #ifdef KEY
03539 // Keep track of localized copies of threadprivate variables.
03540 class Localized_thdprv_var
03541 {
03542   ST_IDX var; // local ST for a threadprivate variable
03543   ST_IDX localized; // localized copy of 'var'
03544 
03545   public:
03546   Localized_thdprv_var (ST_IDX v, ST_IDX l) : var (v), localized (l) {}
03547   ST_IDX Thdprv_ptr (void) const { return var; }
03548   ST_IDX Thdprv_local (void) const { return localized; }
03549 };
03550 
03551 // This vector is cleared at the end of MP processing for a PU.
03552 std::vector<Localized_thdprv_var> localized_var_vect;
03553 #endif // KEY
03554 
03555 /*
03556 Make a local symbol having the same type as the original symbol.  The
03557 parameters firstprivate_blockp and alloca_blockp are the same as in
03558 Create_Local_Variables().  Input parameter prev_def points to a prior entry
03559 for the symbol (NULL if there's none): in particular, if vtype is
03560 VAR_FIRSTPRIVATE, there may have been a prior VAR_LASTLOCAL entry (if the
03561 variable is both FIRSTPRIVATE and LASTPRIVATE) or a prior VAR_LOCAL entry
03562 (if old_st was marked SHARED_DEADOUT).
03563 */
03564 
03565 static void 
03566 Localize_Variable ( VAR_TABLE *v, VAR_TYPE vtype, OPERATOR opr,
03567                     WN *vtree, ST *old_st, WN_OFFSET old_offset,
03568                     WN **firstprivate_blockp, WN **alloca_blockp,
03569                     VAR_TABLE *prev_def )
03570 {
03571   ST   *sym;
03572   TY_IDX ty;
03573   char *localname;
03574   DST_INFO_IDX dst;
03575   const BOOL orphaned =
03576     (mpt == MPP_ORPHANED_SINGLE || mpt == MPP_ORPHANED_PDO);
03577 
03578   Is_True(!prev_def || vtype == VAR_FIRSTPRIVATE,
03579           ("prev_def only valid for VAR_FIRSTPRIVATE"));
03580   Is_True(!prev_def || prev_def->vtype == VAR_LASTLOCAL ||
03581           prev_def->vtype == VAR_LOCAL,
03582           ("invalid vtype for prev_def"));
03583 
03584     // disallow privatizing things that are EQUIVALENCEd: PV 707883
03585   switch (vtype) {
03586   case VAR_LASTLOCAL:
03587   case VAR_LOCAL:
03588   case VAR_FIRSTPRIVATE:
03589     if (Has_Base_Block(old_st) && ST_is_equivalenced(old_st)) {
03590         // if the MP region in which the privatization pragma appears
03591         // was compiler-generated, it must have come from LNO (-pfa), in
03592   // which case alias analysis has determined that privatization is
03593   // actually OK: PV 574997
03594       if (comp_gen_construct) {
03595 //        DevWarn("allowing privatization of EQUIVALENCEd %s", ST_name(old_st));
03596         break;
03597       }
03598 // Bug 3795
03599 #ifndef KEY
03600       ErrMsg(EC_MPLOWER_priv_equiv, old_st);
03601 #endif
03602       return;
03603     }
03604     break;
03605   default:
03606     break;
03607   }
03608 
03609   v->vtype        = vtype;
03610   v->is_static_array  = ((ST_sclass(old_st) == SCLASS_FORMAL) &&
03611        ((vtype == VAR_LOCAL) || (vtype == VAR_LASTLOCAL) ||
03612         (vtype == VAR_FIRSTPRIVATE)) &&
03613        (TY_kind(ST_type(old_st)) == KIND_POINTER) &&
03614        (TY_kind(TY_pointed(ST_type(old_st))) == KIND_ARRAY) &&
03615        (TY_size(TY_pointed(ST_type(old_st))) != 0));
03616   v->is_dynamic_array = (((vtype == VAR_LOCAL) || (vtype == VAR_LASTLOCAL) ||
03617         (vtype == VAR_FIRSTPRIVATE)) &&
03618        (TY_kind(ST_type(old_st)) == KIND_POINTER) &&
03619                          (ST_keep_name_w2f(old_st) || 
03620                           PU_src_lang(Get_Current_PU()) == PU_F77_LANG ||
03621                           PU_src_lang(Get_Current_PU()) == PU_F90_LANG) &&
03622        (TY_kind(TY_pointed(ST_type(old_st))) == KIND_ARRAY) &&
03623        (TY_size(TY_pointed(ST_type(old_st))) == 0) &&
03624        TY_All_Bounds_Defined(TY_pointed(
03625                                ST_type(old_st)) ) );
03626        v->is_non_pod = ( ST_class(old_st) != CLASS_PREG &&
03627                         ( TY_kind(ST_type(old_st)) == KIND_STRUCT &&
03628                         TY_is_non_pod(ST_type(old_st)) ) ||
03629                         ( TY_kind(ST_type(old_st)) == KIND_ARRAY &&
03630                         TY_kind(TY_etype(ST_type(old_st))) == KIND_STRUCT &&
03631                         TY_is_non_pod(TY_etype(ST_type(old_st)))));
03632   v->vtree        = vtree;
03633   v->vtreex       = NULL;
03634   v->orig_st        = old_st;
03635   v->orig_offset      = old_offset;
03636 
03637 #ifdef Is_True_On
03638   if (v->is_non_pod)
03639     switch (mpt) {
03640     case MPP_SINGLE:
03641     case MPP_ORPHANED_SINGLE:
03642     case MPP_PDO:
03643     case MPP_ORPHANED_PDO:
03644     case MPP_PARALLEL_REGION:
03645       break;
03646     default:
03647       Fail_FmtAssertion("non-POD object invalidly privatized on construct "
03648                         "with mpt == %d", (INT) mpt);
03649     }
03650 #endif
03651 
03652   if (prev_def) {
03653     v->mtype = prev_def->mtype;
03654     v->has_offset = prev_def->has_offset;
03655     v->ty = prev_def->ty;
03656     v->vtree = prev_def->vtree ? WN_COPY_Tree(prev_def->vtree) : NULL;
03657     v->vtreex = prev_def->vtreex ? WN_COPY_Tree(prev_def->vtreex) : NULL;
03658     v->new_st = prev_def->new_st;
03659     v->new_offset = prev_def->new_offset;
03660     if (prev_def->vtype == VAR_LASTLOCAL)
03661       prev_def->is_last_and_firstprivate = TRUE;
03662 
03663   } else if (ST_class(old_st) != CLASS_PREG) {
03664 
03665     ty = ST_type(old_st);
03666 #ifdef KEY // bug 7259 and 8076
03667     if ((TY_kind(ty) == KIND_STRUCT) && 
03668         (vtype == VAR_REDUCTION_SCALAR || vtype == VAR_REDUCTION_ARRAY))
03669       ty = FLD_type(TY_fld(ty));
03670 #endif
03671     if ((TY_kind(ty) == KIND_POINTER) &&
03672   ((v->is_static_array) || (vtype == VAR_REDUCTION_ARRAY)))
03673 #ifdef KEY //bug 11661
03674      {
03675 #endif
03676       ty = TY_pointed(ty);
03677 #ifdef KEY //bug 11661: for structure, we need the field type 
03678       if (TY_kind(ty) == KIND_STRUCT && vtype == VAR_REDUCTION_ARRAY)
03679         ty = FLD_type(TY_fld(ty));
03680      }
03681 #endif
03682 
03683     if ((TY_kind(ty) == KIND_ARRAY) && (vtype == VAR_REDUCTION_ARRAY))
03684       ty = TY_etype(ty);
03685     if ((vtype == VAR_REDUCTION_ARRAY_OMP) && (TY_kind(ty) == KIND_POINTER)
03686           && (TY_kind(TY_pointed(ty)) == KIND_ARRAY))
03687     {
03688       ty = TY_pointed(ty);
03689       // we need to create an array in local stack.
03690       // This may not always work.
03691       // csc.
03692       /*ty = TY_etype(ty);*/
03693     }
03694   
03695   localname = (char *) alloca(strlen(ST_name(old_st)) + 32);
03696       // if already localized, append "x" to localization prefix
03697     if (strncmp(ST_name(old_st), "__mplocal_", 10) == 0)
03698       sprintf ( localname, "__mplocalx_%s", &ST_name(old_st)[10] );
03699     else if (strncmp(ST_name(old_st), "__mplocalfe_", 12) == 0)
03700       sprintf ( localname, "__mplocalfex_%s", &ST_name(old_st)[12] );
03701     else if (strncmp(ST_name(old_st), "__mptemp_", 9) == 0)
03702       sprintf ( localname, "__mptempx_%s", &ST_name(old_st)[9] );
03703     else
03704       sprintf ( localname, "__mplocal_%s", ST_name(old_st) );
03705 
03706     if (v->is_non_pod && orphaned) {
03707         // Within orphaned worksharing constructs, non-POD objects are
03708         // privatized already by the frontend, so we don't create a new
03709         // symbol for such objects.
03710       sym = NULL;
03711 
03712     } else {
03713       sym = NULL;
03714 #ifdef KEY
03715     INT16 i;
03716     ST *symbol;
03717     WN *thread_priv_prag = NULL;
03718     WN *matched_pragma = NULL;
03719     if (reference_block) {
03720       thread_priv_prag = WN_first(reference_block);
03721       if (thread_priv_prag) {
03722         while (thread_priv_prag) { 
03723           if (WN_opcode(thread_priv_prag) == OPC_PRAGMA &&
03724               WN_pragma(thread_priv_prag) == WN_PRAGMA_THREADPRIVATE) {
03725             if (WN_pragma_arg1(thread_priv_prag) == ST_st_idx(old_st)){
03726               matched_pragma = thread_priv_prag;
03727               break;
03728             }
03729           }
03730           thread_priv_prag = WN_next(thread_priv_prag);
03731         }
03732 // Bug 4178
03733         thread_priv_prag = WN_first(reference_block);
03734         while (!matched_pragma && thread_priv_prag) {
03735           if (WN_opcode(thread_priv_prag) == OPC_PRAGMA &&
03736               WN_pragma(thread_priv_prag) == WN_PRAGMA_THREADPRIVATE){ 
03737             FOREACH_SYMBOL (CURRENT_SYMTAB, symbol, i) {
03738               if (symbol == ST_ptr(WN_pragma_arg1(thread_priv_prag)) &&
03739                   strcmp(localname, ST_name(symbol)) == 0) {
03740                 sym = symbol;
03741                 break;
03742               }
03743             }
03744             if (!sym)
03745               break;
03746           }
03747           thread_priv_prag = WN_next(thread_priv_prag);
03748         }
03749       }
03750     }
03751     // TODO: Remove the above fix for bug 4178
03752     // Ensure all occurrences of a local thdprv pointer gets the same
03753     // local copy. Needed for multiple orphan DO regions, when each
03754     // of them accesses the same threadprivate variable.
03755     if (!sym)
03756       for (INT it = 0; it < localized_var_vect.size(); it++)
03757       {
03758         if (localized_var_vect[it].Thdprv_ptr() == ST_st_idx (old_st))
03759         {
03760           sym = ST_ptr (localized_var_vect[it].Thdprv_local());
03761           break;
03762         }
03763       }
03764 #endif
03765         // Create privatized version of symbol.
03766      if (!sym) {
03767        sym = New_ST (CURRENT_SYMTAB);
03768        ST_Init (sym,
03769              Save_Str (localname),
03770                CLASS_VAR,             // SCLASS_AUTO requires CLASS_VAR
03771                SCLASS_AUTO,
03772                EXPORT_LOCAL,
03773                ty);
03774 
03775        if (ST_addr_saved(old_st))
03776           Set_ST_addr_saved(sym);
03777        if (ST_addr_passed(old_st))
03778           Set_ST_addr_passed(sym);
03779      }
03780 #ifdef KEY
03781      { // Assumption: The local pragma for a local thdprv ST must be present
03782        // in the function pragmas
03783        WN *prag = WN_first(WN_func_pragmas(PU_Info_tree_ptr(Current_PU_Info)));
03784        while (prag)
03785        {          
03786          if (WN_opcode (prag) == OPC_PRAGMA &&
03787              WN_pragma (prag) == WN_PRAGMA_THREADPRIVATE &&
03788              WN_pragma_arg1 (prag) == ST_st_idx (old_st))
03789          {
03790            Localized_thdprv_var v (WN_pragma_arg1 (prag), ST_st_idx (sym));
03791 
03792            localized_var_vect.push_back (v);
03793            WN_pragma_arg1 (prag) = ST_st_idx (sym);
03794      break;
03795          }
03796          prag = WN_next (prag);
03797        }
03798      }
03799      if (matched_pragma) 
03800   WN_pragma_arg1(matched_pragma) = ST_st_idx(sym);
03801 #endif
03802 
03803       // Don't do the following; it depends on a back-end-specific table
03804       // that doesn't exist until we're compiling the nested MP
03805       // procedure, and addr_used_locally is recomputed by the optimizer
03806       // in any case.
03807       // if (BE_ST_addr_used_locally(old_st)) Set_BE_ST_addr_used_locally(sym);
03808 
03809       if (v->is_dynamic_array) {
03810         Set_ST_pt_to_unique_mem(sym);
03811         Set_ST_pt_to_compiler_generated_mem(sym);
03812       }
03813 
03814       if (Debug_Level > 0) {
03815           // search in the DST tree of the parent subprogram for the
03816           // DST entry corresponding to this symbol
03817 #ifndef KEY
03818         dst = Find_DST_From_ST( old_st, ppuinfo );
03819 #else // bug 5473
03820   if (ppuinfo) dst = Find_DST_From_ST( old_st, ppuinfo );
03821   else dst = DST_INVALID_IDX;
03822 #endif
03823           // Only create a new DST entry for a valid symbol, not any
03824           // of the predef stuff.  If we're localizing for an orphaned
03825     // construct, there's no nested function and associated symbol
03826     // table or DST.
03827         if (!DST_IS_NULL(dst))
03828           Create_New_DST( dst, sym, !orphaned );
03829       }
03830     } // if (orphaned)
03831 
03832     if (TY_kind(ty) == KIND_ARRAY) {
03833       v->mtype = TY_mtype(TY_etype(ty));
03834       v->has_offset = (vtype != VAR_LASTLOCAL) && (vtype != VAR_LOCAL) &&
03835           (vtype != VAR_FIRSTPRIVATE) && (vtype != VAR_REDUCTION_ARRAY_OMP);
03836     } else if (TY_kind(ty) == KIND_STRUCT) {
03837       v->mtype = TY_mtype(ty);
03838       v->has_offset = FALSE;
03839     } else if (v->is_dynamic_array) {
03840       v->mtype = TY_mtype(TY_AR_etype(TY_pointed(ty)));
03841       v->has_offset = FALSE;
03842     } else {
03843       v->mtype = TY_mtype(ty);
03844       v->has_offset = TRUE;
03845     }
03846     v->ty         = ty;
03847     v->new_st     = sym;
03848     v->new_offset = 0;
03849 
03850     if ((v->is_static_array) && (vtree == NULL)) {
03851       v->vtree = WN_RLdid ( Promote_Type(Pointer_type), Pointer_type,
03852           old_offset, old_st, ST_type(old_st) );
03853       v->vtreex = WN_Create ( (Pointer_Size == 4) ? OPC_U4ARRAY : OPC_U8ARRAY,
03854             3 );
03855       WN_element_size(v->vtreex) = Pointer_Size;
03856       WN_kid0(v->vtreex) = WN_RLdid ( Promote_Type(Pointer_type), Pointer_type,
03857               old_offset, old_st, ST_type(old_st) );
03858       WN_kid1(v->vtreex) = WN_Intconst ( MTYPE_I4, 0 );
03859       WN_kid2(v->vtreex) = WN_Intconst ( MTYPE_I4, 0 );
03860     }
03861 
03862     if (v->is_dynamic_array && 
03863         Vla_Needs_Alloca(v->orig_st) &&
03864         !v->is_non_pod) { // fecc allocates non-POD VLAs
03865       if (*alloca_blockp == NULL)
03866       *alloca_blockp = WN_CreateBlock ( );
03867       WN_INSERT_BlockLast(*alloca_blockp,
03868         Gen_Auto_Alloca(v->new_st, v->new_offset, v->ty,
03869                         Calculate_Array_Size(old_st, TY_pointed(ty))));
03870     }
03871 
03872   } else {  // ST_class(old_st) == CLASS_PREG
03873     v->mtype      = ST_btype(old_st);
03874     v->has_offset = TRUE;
03875     v->ty         = ST_type(old_st);
03876     v->new_st     = old_st;
03877     v->new_offset = old_offset;
03878 
03879   }
03880 
03881   if (vtype == VAR_FIRSTPRIVATE && firstprivate_blockp &&
03882       !v->is_non_pod) {   // fecc generates constructor calls
03883     if (*firstprivate_blockp == NULL)
03884       *firstprivate_blockp = WN_CreateBlock ( );
03885     WN_INSERT_BlockLast(*firstprivate_blockp,
03886       Gen_MP_Load_Store(v->orig_st, v->orig_offset,
03887                         v->new_st, v->new_offset,
03888                         v->is_dynamic_array));
03889   }
03890 
03891     /* determine the opcode for reductions */
03892   if (vtype == VAR_REDUCTION_SCALAR || 
03893     vtype == VAR_REDUCTION_ARRAY  ||
03894     vtype == VAR_REDUCTION_ARRAY_OMP) {
03895     TYPE_ID rtype, dtype = MTYPE_V;
03896 
03897    /* Operator is explicit in OMP, or inferred by OMP_Prelower for MP.
03898    If it's still unknown at this point, it couldn't be inferred
03899    because the operator wasn't used in the lexical scope of the
03900    reduction clause, so it's an error. */
03901     if (opr == OPERATOR_UNKNOWN) {
03902       char *redvar_name = (char *) alloca(strlen(ST_name(v->orig_st)) + 32);
03903 
03904       sprintf(redvar_name, "%s %s",
03905         vtree ? "element of array" : "variable",
03906               ST_name(v->orig_st));
03907       ErrMsg(EC_MPLOWER_red_not_found, redvar_name);
03908     }
03909 
03910       // Promote 1 and 2 byte types to 4 bytes
03911     if (v->mtype == MTYPE_I1 || v->mtype == MTYPE_I2)
03912       rtype = MTYPE_I4;
03913     else if (v->mtype == MTYPE_U1 || v->mtype == MTYPE_U2)
03914       rtype = MTYPE_U4;
03915     else
03916       rtype = v->mtype;
03917 
03918     switch (opr) {
03919     case OPR_LAND:
03920     case OPR_LIOR:
03921       if (v->mtype == MTYPE_I8) {
03922           // truncate result on LOGICAL*8 to 4 bytes: PV 602935
03923         rtype = MTYPE_I4;
03924       }
03925       break;
03926 
03927     case OPR_EQ:
03928     case OPR_NE:
03929       if (rtype == MTYPE_I8) {
03930         dtype = MTYPE_I8;
03931           // truncate .EQV./.NEQV. result on LOGICAL*8: PV 659567
03932         rtype = MTYPE_I4;
03933       } else {
03934         dtype = rtype;
03935       }
03936       break;
03937 
03938     case OPR_CAND:
03939     case OPR_CIOR:
03940         // for && and ||, the rtype must be MTYPE_I4: PV 677602
03941       rtype = MTYPE_I4;
03942       break;
03943 
03944     default:
03945       break;
03946     }
03947 
03948     v->reduction_opr = opr;
03949     v->reduction_opc = OPCODE_make_op(opr, rtype, dtype);
03950   } else {
03951     v->reduction_opr = OPERATOR_UNKNOWN;
03952     v->reduction_opc = OPCODE_UNKNOWN;
03953   }
03954 }
03955 
03956 
03957 /*
03958 Verify that the given PRAGMA or XPRAGMA tree doesn't reference any
03959 non-dedicated pregs.
03960 */
03961 
03962 static void 
03963 Verify_No_Pregs_In_Tree(WN *tree)
03964 {
03965   WN_ITER *it = WN_WALK_TreeIter(tree);
03966 
03967   while (it) {
03968     WN *wn = it->wn;
03969 
03970     OPERATOR opr = WN_operator(wn);
03971 
03972     if (OPERATOR_has_sym(opr) && OPERATOR_has_offset(opr) && WN_st(wn) &&
03973         ST_class(WN_st(wn)) == CLASS_PREG &&
03974         !Preg_Is_Dedicated(WN_offsetx(wn)))
03975       Fail_FmtAssertion("invalid preg reference in worksharing scope pragma");
03976 
03977     it = WN_WALK_TreeNext(it);
03978   }
03979 }
03980 #ifdef KEY
03981 /* Generate a procedure body to copy the data */
03982 
03983 static ST*
03984 Create_Copyfunc(ST *struct_st)
03985 {
03986   SYMTAB_IDX cp_psymtab = CURRENT_SYMTAB;
03987   PU_Info *cp_ppuinfo = Current_PU_Info;
03988   WN_MAP_TAB *cp_pmaptab = Current_Map_Tab;
03989   WN_MAP_TAB *cp_cmaptab = cmaptab; 
03990   ST *cp_parallel_proc = parallel_proc, *swap_proc;
03991   SYMTAB_IDX cp_csymtab;
03992   INT32 cp_func_level;
03993 
03994   const char *construct_type_str = "cp_thunk";
03995   TY_IDX &func_ty_idx = mpregion_ty;
03996   char temp_str[64];
03997 
03998   if  (func_ty_idx == TY_IDX_ZERO) {
03999     // create new type for function, and type for pointer to function
04000 
04001     TY& ty = New_TY(func_ty_idx);
04002     sprintf(temp_str, ".%s", construct_type_str);
04003     TY_Init(ty, 0, KIND_FUNCTION, MTYPE_UNKNOWN, Save_Str(temp_str));
04004     Set_TY_align(func_ty_idx, 1);
04005 
04006     TYLIST_IDX parm_idx;
04007     TYLIST& parm_list = New_TYLIST(parm_idx);
04008     Set_TY_tylist(ty, parm_idx);
04009     Set_TYLIST_type(parm_list, Be_Type_Tbl(MTYPE_V));  // return type
04010 
04011       // Two basic parameters
04012     Set_TYLIST_type(New_TYLIST(parm_idx), // src
04013                       Be_Type_Tbl(Pointer_type));
04014     Set_TYLIST_type(New_TYLIST(parm_idx), // dst
04015                       Be_Type_Tbl(Pointer_type));
04016 
04017     Set_TYLIST_type(New_TYLIST(parm_idx), TY_IDX_ZERO); // end of parm list
04018 
04019       // now create a type for a pointer to this function
04020     TY_IDX ptr_ty_idx;
04021     TY &ptr_ty = New_TY(ptr_ty_idx);
04022     sprintf(temp_str, ".%s_ptr", construct_type_str);
04023     TY_Init(ptr_ty, Pointer_Size, KIND_POINTER, Pointer_Mtype,
04024             Save_Str(temp_str));
04025     Set_TY_pointed(ptr_ty, func_ty_idx);
04026   }
04027 
04028   PU_IDX pu_idx;
04029   PU& pu = New_PU(pu_idx);
04030   PU_Init(pu, func_ty_idx, CURRENT_SYMTAB);
04031 
04032   Set_PU_no_inline(pu);
04033   Set_PU_is_nested_func(pu);
04034   Set_PU_mp(pu);
04035   if (PU_c_lang(Current_PU_Info_pu()))
04036     Set_PU_c_lang(pu);
04037   if (PU_cxx_lang(Current_PU_Info_pu()))
04038     Set_PU_cxx_lang(pu);
04039   if (PU_f77_lang(Current_PU_Info_pu()))
04040     Set_PU_f77_lang(pu);
04041   if (PU_f90_lang(Current_PU_Info_pu()))
04042     Set_PU_f90_lang(pu);
04043   if (PU_java_lang(Current_PU_Info_pu()))
04044     Set_PU_java_lang(pu);
04045 
04046   Set_FILE_INFO_has_mp(File_info);
04047 
04048   char *st_name = (char *) alloca(strlen(construct_type_str) + 32);
04049   sprintf ( st_name, "__%s_%d", construct_type_str, ST_st_idx(struct_st));
04050 
04051   parallel_proc = New_ST(GLOBAL_SYMTAB);
04052   ST_Init(parallel_proc,
04053           Save_Str (st_name),
04054           CLASS_FUNC,
04055           SCLASS_TEXT,
04056           EXPORT_LOCAL,
04057           pu_idx);
04058   Set_ST_addr_passed(parallel_proc);
04059 
04060   Allocate_Object ( parallel_proc );
04061 
04062   New_Scope(CURRENT_SYMTAB + 1,
04063             Malloc_Mem_Pool,  
04064             TRUE);
04065   cp_csymtab = CURRENT_SYMTAB;
04066   cp_func_level = CURRENT_SYMTAB;
04067   Scope_tab[cp_csymtab].st = parallel_proc;
04068 
04069   Set_PU_lexical_level(pu, CURRENT_SYMTAB);
04070   Create_Func_DST ( st_name );
04071 
04072   for (UINT32 i = 1; i < PREG_Table_Size(cp_psymtab); i++) {
04073     PREG_IDX preg_idx;
04074     PREG &preg = New_PREG(cp_csymtab, preg_idx);
04075       // share name with corresponding parent preg
04076     Set_PREG_name_idx(preg,
04077       PREG_name_idx((*Scope_tab[cp_psymtab].preg_tab)[preg_idx]));
04078   }
04079   ST *arg_src = New_ST( CURRENT_SYMTAB );
04080   ST_Init (arg_src,
04081              Save_Str ( "__ompv_src_a" ),
04082              CLASS_VAR,
04083              SCLASS_FORMAL,
04084              EXPORT_LOCAL,
04085              Be_Type_Tbl( Pointer_type ));
04086   Set_ST_is_value_parm( arg_src );
04087                                                                                                                                                              
04088   ST *arg_dst = New_ST( CURRENT_SYMTAB );
04089   ST_Init( arg_dst,
04090            Save_Str( "__ompv_dst_a" ),
04091            CLASS_VAR,
04092            SCLASS_FORMAL,
04093            EXPORT_LOCAL,
04094            Be_Type_Tbl( Pointer_type ));
04095   Set_ST_is_value_parm( arg_dst );
04096 
04097   WN *func_body = WN_CreateBlock();
04098   WN *func_entry = WN_CreateEntry(2, parallel_proc,
04099                                  func_body,
04100                                  WN_CreateBlock(),
04101                                  WN_CreateBlock());
04102 
04103   WN_linenum(func_entry) = line_number;
04104   WN_kid0(func_entry) = WN_CreateIdname ( 0, arg_src );
04105   WN_kid1(func_entry) = WN_CreateIdname ( 0, arg_dst );
04106   WN_linenum(func_entry) = line_number;
04107 
04108   FLD_HANDLE  fld;
04109   fld = TY_flist(Ty_Table[ST_type(struct_st)]);
04110   WN *value, *addr, *istore;
04111   TYPE_ID type;
04112   for (; !fld.Is_Null (); fld = FLD_next(fld)){
04113     TY& ty = Ty_Table [FLD_type (fld)];
04114     TY *pty = &ty;
04115     TY_IDX pty_idx = TY_pointed(*pty);
04116     OPCODE addr_load_opc = OPCODE_make_op(OPR_ILOAD, Pointer_type, Pointer_type);
04117     if (TY_kind(pty_idx) != KIND_ARRAY){
04118       type = TY_mtype(pty_idx);
04119       OPCODE load_opc = OPCODE_make_op(OPR_ILOAD,type,type);
04120       value = WN_CreateIload(load_opc, 0,
04121                         Be_Type_Tbl(type),
04122                         Make_Pointer_Type(Be_Type_Tbl(type),FALSE),
04123                         WN_CreateIload(addr_load_opc, FLD_ofst(fld),
04124                                        Be_Type_Tbl(Pointer_type),
04125                                        Make_Pointer_Type(Be_Type_Tbl(Pointer_type),FALSE),
04126                                        WN_Ldid(Pointer_type, 0, arg_src, ST_type(arg_src))));
04127       istore = WN_CreateIstore(OPCODE_make_op(OPR_ISTORE,MTYPE_V,type),
04128                         0,
04129                         Make_Pointer_Type(Be_Type_Tbl(type),FALSE),
04130                         value,
04131                         WN_CreateIload(addr_load_opc, FLD_ofst(fld),
04132                                        Be_Type_Tbl(Pointer_type),
04133                                        Make_Pointer_Type(Be_Type_Tbl(Pointer_type),FALSE),
04134                                        WN_Ldid(Pointer_type, 0, arg_dst, ST_type(arg_dst))));
04135       WN_INSERT_BlockLast(func_body, istore);
04136     }
04137     else{
04138 // Bug 3822
04139       WN *call = Transform_To_Memcpy(WN_CreateIload(addr_load_opc, FLD_ofst(fld),
04140                                                     Be_Type_Tbl(Pointer_type),
04141                                                     Make_Pointer_Type(Be_Type_Tbl(Pointer_type),FALSE),
04142                                                     WN_Ldid(Pointer_type, 0, arg_dst, ST_type(arg_dst))),
04143                                      WN_CreateIload(addr_load_opc, FLD_ofst(fld),
04144                                                     Be_Type_Tbl(Pointer_type),
04145                                                     Make_Pointer_Type(Be_Type_Tbl(Pointer_type),FALSE),
04146                                                     WN_Ldid(Pointer_type, 0, arg_src, ST_type(arg_src))),
04147                                      0, 
04148                                      Make_Pointer_Type(Be_Type_Tbl(Pointer_type),FALSE), 
04149                                      Make_Pointer_Type(Be_Type_Tbl(Pointer_type),FALSE), 
04150                                      WN_CreateIntconst (OPC_U4INTCONST,TY_size(pty_idx)));
04151       WN_INSERT_BlockLast(func_body, call);
04152     }
04153   }
04154   WN *wn = WN_CreateReturn ( );
04155   WN_linenum(wn) = line_number;
04156   WN_INSERT_BlockLast ( func_body, wn );
04157 
04158   PU_Info *copy_pu = TYPE_MEM_POOL_ALLOC ( PU_Info, Malloc_Mem_Pool );
04159   PU_Info_init ( copy_pu );
04160   Set_PU_Info_tree_ptr (copy_pu, func_entry );
04161   //verify_mp_lowered_ptr->Set_nested_pu_tree(func_entry);
04162 
04163   PU_Info_proc_sym(copy_pu) = ST_st_idx(parallel_proc);
04164   PU_Info_maptab(copy_pu) = cp_cmaptab = WN_MAP_TAB_Create(MEM_pu_pool_ptr);
04165   PU_Info_pu_dst(copy_pu) = nested_dst;
04166   Set_PU_Info_state(copy_pu, WT_SYMTAB, Subsect_InMem);
04167   Set_PU_Info_state(copy_pu, WT_TREE, Subsect_InMem);
04168   Set_PU_Info_state(copy_pu, WT_PROC_SYM, Subsect_InMem);
04169   Set_PU_Info_flags(copy_pu, PU_IS_COMPILER_GENERATED);
04170 
04171   Set_PU_Info_symtab_ptr(copy_pu, NULL);
04172   Save_Local_Symtab(cp_csymtab, copy_pu);
04173 
04174   if (Cur_PU_Feedback) {
04175     parallel_pu_fb = CXX_NEW(FEEDBACK(func_entry,
04176                                       MEM_pu_nz_pool_ptr,
04177                                       1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
04178                                       cp_cmaptab),
04179                              MEM_pu_nz_pool_ptr);
04180     Set_PU_Info_state(copy_pu, WT_FEEDBACK, Subsect_InMem);
04181     Set_PU_Info_feedback_ptr(copy_pu, parallel_pu_fb);
04182     FB_Transfer(Cur_PU_Feedback, parallel_pu_fb, stmt_block); 
04183   }
04184 
04185   RID *root_rid = RID_Create ( 0, 0, func_entry );
04186   RID_type(root_rid) = RID_TYPE_func_entry;
04187   Set_PU_Info_regions_ptr ( copy_pu, root_rid );
04188   Is_True(PU_Info_regions_ptr(copy_pu) != NULL,
04189          ("Create_Copythunk, NULL root RID"));
04190 
04191   PU_Info *tpu = PU_Info_child(Current_PU_Info);
04192 
04193     // add parallel_pu after last child MP PU_Info item in parent's list
04194   if (tpu && PU_Info_state(tpu, WT_SYMTAB) == Subsect_InMem &&
04195       PU_mp(PU_Info_pu(tpu)) ) {
04196     PU_Info *npu;
04197 
04198     while ((npu = PU_Info_next(tpu)) &&
04199      PU_Info_state(npu, WT_SYMTAB) == Subsect_InMem &&
04200      PU_mp(PU_Info_pu(npu)) )
04201       tpu = npu;
04202 
04203     PU_Info_next(tpu) = copy_pu;
04204     PU_Info_next(copy_pu) = npu;
04205   } else {
04206     PU_Info_child(Current_PU_Info) = copy_pu;
04207     PU_Info_next(copy_pu) = tpu;
04208   }
04209 
04210 
04211   // change some global state; need to clean this up--DRK
04212 
04213   Current_PU_Info = cp_ppuinfo;
04214   Current_pu = &Current_PU_Info_pu();
04215   Current_Map_Tab = cp_pmaptab;
04216   Transfer_Maps ( cp_pmaptab, cp_cmaptab, func_body,
04217       PU_Info_regions_ptr(Current_PU_Info) );
04218 
04219   Current_Map_Tab = cp_cmaptab;
04220   // We don't need to update dependence graph since this function is totally new.
04221   //MP_Fix_Dependence_Graph ( cp_ppuinfo, Current_PU_Info, func_body ); 
04222   Set_PU_Info_depgraph_ptr(copy_pu,NULL);
04223   Current_Map_Tab = cp_pmaptab;
04224 
04225   CURRENT_SYMTAB = cp_psymtab;
04226   Add_DST_variable ( arg_src, nested_dst, line_number, DST_INVALID_IDX );
04227   Add_DST_variable ( arg_dst, nested_dst, line_number, DST_INVALID_IDX );
04228 
04229   swap_proc = parallel_proc;
04230   parallel_proc = cp_parallel_proc;
04231   return swap_proc;
04232 }
04233 
04234 /*  Generate a copyprivate call.  Generate a procedure to copy the data. 
04235     Also, generate a structure so that the compiler can pass the address 
04236     of each copyprivate variable into RTL. */
04237 
04238 static void
04239 Gen_MP_Copyprivate(WN *copyprivates, WN **copyprivate_blockp,
04240                    WN *ldid_lock)
04241 {
04242   WN *wnx;
04243   FLD_HANDLE fld;
04244   FLD *next;
04245   ST *st, *fld_st;
04246 
04247 #ifndef TARG_NVISA
04248   BOOL target_32bit = Is_Target_32bit();
04249 #else
04250   BOOL target_32bit = FALSE;
04251 #endif
04252 
04253   /* Create a struct type */
04254   INT32 count = 0;
04255   for (wnx = copyprivates; wnx; wnx = WN_next(wnx),count++);
04256 
04257   TY_IDX struct_ty_idx;
04258   TY& struct_ty = New_TY(struct_ty_idx);
04259   TY_Init(struct_ty, target_32bit ? 4*count : 8*count, 
04260           KIND_STRUCT, MTYPE_M, STR_IDX_ZERO);
04261   Set_TY_align(struct_ty_idx, MTYPE_align_req(Pointer_type));
04262 
04263   INT32 offset = 0;
04264   for (wnx = copyprivates; wnx; wnx = WN_next(wnx)){
04265     fld_st = WN_st(wnx);
04266     fld = New_FLD ();
04267     if (wnx == copyprivates) 
04268       Set_TY_fld(struct_ty, fld);
04269     FLD_Init (fld, Save_Str(ST_name(fld_st)), 
04270               Make_Pointer_Type (TY_IDX(ST_type(fld_st))), offset);
04271     offset += target_32bit ? 4 : 8;
04272   }
04273   Set_FLD_last_field (fld);
04274 
04275   char st_name[32];
04276   sprintf ( st_name, "__mp_cpprv_%d", ST_st_idx(fld_st) );
04277   st = New_ST(CURRENT_SYMTAB);
04278   ST_Init (st,
04279            Save_Str(st_name),
04280            CLASS_VAR,
04281            SCLASS_AUTO,
04282            EXPORT_LOCAL,
04283            struct_ty_idx);
04284   Set_ST_base (st, st);
04285 
04286   WN *wn;
04287   /* Generate a series of store stmt to get the address of each
04288      copyprivate variable */
04289   fld = TY_flist(Ty_Table[ST_type(st)]);
04290 
04291   for (wnx = copyprivates; wnx; wnx = WN_next(wnx), fld = FLD_next(fld))
04292   {
04293     TY_IDX ty = FLD_type(fld);
04294     wn = WN_Stid ( TY_mtype(ty), FLD_ofst(fld), st, 
04295                    ty, WN_Lda (Pointer_type,0,WN_st(wnx)) );
04296 #ifdef KEY // bug 8764
04297     Set_ST_addr_saved(WN_st(wnx));
04298 #endif
04299     WN_linenum(wn) = line_number;
04300     WN_INSERT_BlockLast(*copyprivate_blockp, wn);
04301   }
04302 
04303   /* Generate a procedure call for copyprivate */
04304   wn = WN_Create ( OPC_VCALL, 3 );
04305   WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_COPYPRIVATE);
04306 
04307   WN_Set_Call_Non_Data_Mod ( wn );
04308   WN_Set_Call_Non_Data_Ref ( wn );
04309   WN_Set_Call_Non_Parm_Mod ( wn );
04310   WN_Set_Call_Non_Parm_Ref ( wn );
04311   WN_Set_Call_Parm_Mod ( wn );
04312   WN_Set_Call_Parm_Ref ( wn );
04313   WN_linenum(wn) = line_number;
04314   WN_kid0(wn) = WN_CreateParm ( MTYPE_I4,
04315                                 ldid_lock,
04316                                 Be_Type_Tbl(MTYPE_I4), WN_PARM_BY_VALUE );
04317 
04318   WN_kid1(wn) = WN_CreateParm (Pointer_type,
04319                                WN_Lda(Pointer_type, 0, st),
04320                                Make_Pointer_Type ( ST_type(st),FALSE ),
04321                                WN_PARM_BY_REFERENCE );
04322   /* Create a procedure */
04323 
04324   Push_Some_Globals( );
04325   ST *copyproc = Create_Copyfunc(st);
04326   Pop_Some_Globals( );
04327 
04328   WN_kid2(wn) = WN_CreateParm (Pointer_type,
04329                                WN_Lda(Pointer_type, 0, copyproc),
04330                                Make_Pointer_Type ( ST_pu_type(copyproc),FALSE ),
04331                                WN_PARM_BY_REFERENCE );
04332 
04333   WN_INSERT_BlockLast(*copyprivate_blockp, wn);
04334 }
04335 #endif
04336 /*  Walk the reduction, last_local, local, and firstprivate lists and add the
04337     contents to the VAR_TABLE table.  If firstprivate_blockp is non-NULL,
04338     then (*firstprivate_blockp) must be NULL, and the code to initialize
04339     values of FIRSTPRIVATE variables is returned in (*firstprivate_blockp);
04340     if the value of (*firstprivate_blockp) is NULL upon return, no such
04341     code was generated.  Accumulate code to allocate dynamic arrays in
04342     (*alloca_blockp).  */
04343 
04344 static void 
04345 Create_Local_Variables ( VAR_TABLE * vtab, WN * reductions,
04346              WN * lastlocals, WN * locals,
04347              WN * firstprivates, 
04348              WN **firstprivate_blockp,
04349              WN * lastthread,
04350              WN ** alloca_blockp )
04351 {
04352   WN        *l;
04353   OPERATOR   opr;
04354   VAR_TABLE *v = vtab;
04355   BOOL is_non_combined_worksharing = FALSE;
04356 
04357   switch (mpt) {
04358   case MPP_SINGLE:
04359   case MPP_ORPHANED_SINGLE:
04360   case MPP_PDO:
04361   case MPP_ORPHANED_PDO:
04362 #ifdef KEY /* Bug 4828 */
04363   case MPP_WORKSHARE:
04364   case MPP_ORPHANED_WORKSHARE:
04365 #endif
04366     is_non_combined_worksharing = TRUE;
04367     break;
04368   case MPP_PARALLEL_DO:
04369   case MPP_PARALLEL_REGION:
04370 #ifdef KEY
04371   case MPP_ORPHAN:
04372 #endif
04373     break;
04374   default:
04375     Fail_FmtAssertion("illegal construct, mpt == %d", (INT) mpt);
04376   }
04377 
04378 #ifdef Is_True_On
04379   if (is_non_combined_worksharing) {
04380       /* PV 656616 : In a worksharing construct, pregs should never appear
04381          in a reduction, lastlocal, or firstprivate pragma. In the non-
04382          orphaned case, they should have been scoped shared on the
04383    parallel region and replaced by temps during Process_Preg_Temps().
04384    In the orphaned case, it's a reprivatization error. */
04385     WN *ll[] = { reductions, lastlocals, firstprivates, NULL };
04386     INT i;
04387 
04388     for (i = 0; ll[i]; i++)
04389       for (l = ll[i]; l; l = WN_next(l))
04390         Verify_No_Pregs_In_Tree(l);
04391   }
04392 #endif
04393 
04394   /* Do reductions */
04395   for (l = reductions; l; l = WN_next(l)) {
04396     if (WN_opcode(l) == OPC_PRAGMA) {
04397   VAR_TYPE reduction_var_type = VAR_REDUCTION_SCALAR;
04398   if( WN_pragma_omp(l) && WN_st(l) && 
04399       Is_Kind_Array(WN_st(l)) == TRUE)
04400 //    ( TY_kind( ST_type( WN_st( l ))) == KIND_ARRAY ))
04401     reduction_var_type = VAR_REDUCTION_ARRAY_OMP;
04402 
04403   Localize_Variable( v, reduction_var_type,
04404                    (OPERATOR) WN_pragma_arg2(l), NULL, WN_st(l),
04405                     WN_offsetx(l), firstprivate_blockp, alloca_blockp,
04406                     NULL );
04407         v++;
04408     } else {
04409       opr = WN_operator(WN_kid0(l));
04410       if ((opr == OPR_LDA) || (opr == OPR_LDID)) {
04411         Localize_Variable ( v, VAR_REDUCTION_SCALAR,
04412           (OPERATOR) WN_pragma_arg2(l), NULL,
04413           WN_st(WN_kid0(l)), WN_offsetx(WN_kid0(l)),
04414           firstprivate_blockp, alloca_blockp, NULL );
04415         v++;
04416       } else if (opr == OPR_ARRAY) {
04417        Localize_Variable ( v, VAR_REDUCTION_ARRAY,
04418                            (OPERATOR) WN_pragma_arg2(l),
04419                                  WN_COPY_Tree ( WN_kid0(l) ),
04420                WN_st(WN_kid0(WN_kid0(l))),
04421                WN_offsetx(WN_kid0(WN_kid0(l))),
04422                firstprivate_blockp, alloca_blockp, NULL );
04423        v++;
04424 #ifdef KEY // bug 9112 : handle the extra offset specified by an ADD
04425       } else if (opr == OPR_ADD && 
04426            WN_operator(WN_kid0(WN_kid0(l))) == OPR_ARRAY) {
04427        INT ofst = WN_const_val(WN_kid1(WN_kid0(l)));
04428        Localize_Variable ( v, VAR_REDUCTION_ARRAY,
04429                            (OPERATOR) WN_pragma_arg2(l),
04430                                  WN_COPY_Tree ( WN_kid0(WN_kid0(l)) ),
04431                WN_st(WN_kid0(WN_kid0(WN_kid0(l)))),
04432                WN_offsetx(WN_kid0(WN_kid0(WN_kid0(l))))+ofst,
04433                firstprivate_blockp, alloca_blockp, NULL );
04434        v++;
04435 #endif
04436       } else {
04437         Fail_FmtAssertion ( "invalid reduction directive" );
04438       }
04439     }
04440   }
04441 
04442   /* Do lastlocals */
04443   for (l = lastlocals; l; l = WN_next(l)) {
04444     if (WN_pragma_arg2(l) & SHARED_DEADOUT)
04445       Localize_Variable ( v, VAR_LOCAL, OPERATOR_UNKNOWN, NULL, WN_st(l),
04446                           WN_offsetx(l), firstprivate_blockp,
04447         alloca_blockp, NULL );
04448     else
04449       Localize_Variable ( v, VAR_LASTLOCAL, OPERATOR_UNKNOWN, NULL,
04450                           WN_st(l), WN_offsetx(l), firstprivate_blockp,
04451         alloca_blockp, NULL );
04452     v++;
04453   }
04454    
04455   /* Do locals */
04456   for (l = locals; l; l = WN_next(l)) {
04457     Localize_Variable ( v, VAR_LOCAL, OPERATOR_UNKNOWN, NULL, WN_st(l),
04458                         WN_offsetx(l), firstprivate_blockp, alloca_blockp,
04459       NULL );
04460     if (lastthread && (v->orig_st == WN_st(lastthread)) &&
04461   (v->orig_offset == WN_offsetx(lastthread))) {
04462       WN_st_idx(lastthread) = ST_st_idx(v->new_st);
04463       WN_set_offsetx(lastthread, v->new_offset);
04464     }
04465     v++;
04466   }
04467 
04468   /* Do firstprivates */
04469   for (l = firstprivates; l; l = WN_next(l)) {
04470       // Search for LASTLOCAL entry for l in vtab.
04471     VAR_TABLE *llv = vtab;
04472 
04473     for ( ; llv->orig_st; llv++)
04474       if (WN_st(l) == llv->orig_st &&
04475           (!llv->has_offset || WN_offsetx(l) == llv->orig_offset)) {
04476           // VAR_LOCAL can happen for SHARED_DEADOUT
04477         Is_True(llv->vtype == VAR_LASTLOCAL || llv->vtype == VAR_LOCAL,
04478                 ("impossible combination of variable types"));
04479   break;
04480       }
04481 
04482     if (!llv->orig_st)
04483       llv = NULL;
04484 
04485     Localize_Variable ( v, VAR_FIRSTPRIVATE, OPERATOR_UNKNOWN, NULL,
04486                         WN_st(l), WN_offsetx(l), firstprivate_blockp,
04487       alloca_blockp, llv );
04488     if (lastthread && (v->orig_st == WN_st(lastthread)) &&
04489   (v->orig_offset == WN_offsetx(lastthread))) {
04490       WN_st_idx(lastthread) = ST_st_idx(v->new_st);
04491       WN_set_offsetx(lastthread, v->new_offset);
04492     }
04493     v++;
04494   }
04495 
04496 }
04497 
04498 
04499 /*  Determine the final (accumulating) reduction op based on the primary
04500     reduction op.  This is necessary because OPR_SUB and OPR_DIV must be
04501     handled specially.  While the individual threads perform a SUB/DIV the
04502     final reduction op must be ADD/MUL.  */
04503 
04504 static OPCODE 
04505 Make_Final_Reduction_Op ( OPCODE op )
04506 {
04507   OPERATOR opr = OPCODE_operator(op);
04508 
04509   if (opr == OPR_SUB)
04510       return (OPCODE_make_op ( OPR_ADD, OPCODE_rtype(op), MTYPE_V ));
04511   else if (opr == OPR_DIV)
04512       return (OPCODE_make_op ( OPR_MPY, OPCODE_rtype(op), MTYPE_V ));
04513   else
04514       return (op);
04515 }
04516 
04517 
04518 /*
04519 Set ST of *new_initv to localized version of ST of *old_initv (or just
04520 ST of *old_initv, if it's not localized).
04521 */
04522 
04523 static void
04524 Localize_INITVKIND_SYMOFF(INITV_IDX new_idx, INITV_IDX old_idx, VAR_TABLE *v )
04525 {
04526   Is_True(new_idx !=0, ("null new_idx"));
04527   Is_True(old_idx !=0, ("null old_idx"));
04528 
04529   INITV &new_initv = Initv_Table[new_idx];
04530   INITV &old_initv = Initv_Table[old_idx];
04531 
04532   BOOL same_initv = new_idx == old_idx;
04533   INITV_IDX orig_next;
04534   if (same_initv)
04535     orig_next = INITV_next(old_idx);
04536 
04537   Is_True(INITV_kind(new_initv) == INITVKIND_SYMOFF,
04538           ("wrong kind of new_initv"));
04539   Is_True(INITV_kind(old_initv) == INITVKIND_SYMOFF,
04540           ("wrong kind of old_initv"));
04541 
04542   INITV_Set_SYMOFF(new_initv, INITV_repeat1(old_initv), INITV_st(old_initv),
04543                    INITV_ofst(old_initv));
04544   if (same_initv)
04545     Set_INITV_next(new_idx, orig_next);
04546 
04547   for ( ; v->orig_st; v++) {
04548     if (ST_st_idx(*v->orig_st) == INITV_st(old_initv) &&
04549         (!v->has_offset || (v->orig_offset == INITV_ofst(old_initv))) ) {
04550       INITV_Set_SYMOFF(new_initv, INITV_repeat1(new_initv),
04551           ST_st_idx(*v->new_st),
04552     v->has_offset ? v->new_offset : INITV_ofst(new_initv));
04553       if (same_initv)
04554         Set_INITV_next(new_idx, orig_next);
04555       break;
04556     }
04557   }
04558 }
04559 
04560 
04561 /*
04562 Apply Localize_INITVKIND_SYMOFF() to each INITVKIND_SYMOFF in an INITO.
04563 */
04564 
04565 static void
04566 Localize_All_INITVKIND_SYMOFFs(INITO_IDX obj_idx, VAR_TABLE *vtab )
04567 {
04568   Is_True(obj_idx !=0, ("null obj_idx"));
04569 
04570   STACK<INITV_IDX> initv_stack(Malloc_Mem_Pool);
04571   INITV_IDX val_idx = INITO_val(obj_idx);
04572 
04573   while (val_idx) {
04574     INITVKIND k = INITV_kind(val_idx);
04575     switch (k) {
04576       case INITVKIND_SYMOFF:
04577         Localize_INITVKIND_SYMOFF(val_idx, val_idx, vtab);
04578   val_idx = INITV_next(val_idx);
04579   break;
04580 
04581       case INITVKIND_ZERO:
04582       case INITVKIND_ONE:
04583       case INITVKIND_VAL:
04584       case INITVKIND_PAD:
04585       case INITVKIND_SYMDIFF:   // do we need to localize these next 3?
04586       case INITVKIND_SYMDIFF16:
04587       case INITVKIND_LABEL:
04588            val_idx = INITV_next(val_idx);
04589            break;
04590 
04591       case INITVKIND_BLOCK:
04592         initv_stack.Push(val_idx);
04593         val_idx = INITV_blk(val_idx);
04594         break;
04595 
04596       default:
04597         Fail_FmtAssertion ( "unknown INITV kind %d", (INT) k );
04598     }
04599 
04600     while (!val_idx && initv_stack.Elements() > 0) {
04601       val_idx = INITV_next(initv_stack.Pop());
04602     }
04603   }
04604 }
04605 
04606 
04607   // functor class
04608 struct Localize_Nested_PU_Exception_Region {
04609   INITO_IDX old_inito;
04610   VAR_TABLE *vtab;
04611   SYMTAB_IDX level;
04612   Localize_Nested_PU_Exception_Region(INITO_IDX _old_inito, VAR_TABLE *_vtab,
04613     SYMTAB_IDX _level) : old_inito(_old_inito), vtab(_vtab), level(_level) { }
04614   BOOL operator() (UINT32 nested_raw_idx, const INITO *) const {
04615     INITO_IDX nested_inito_idx = make_INITO_IDX(nested_raw_idx, level);
04616 
04617     if (old_inito == nested_inito_idx) {
04618       Localize_All_INITVKIND_SYMOFFs(old_inito, vtab);
04619       return TRUE;
04620     }
04621     return FALSE;
04622   }
04623 };
04624 
04625 
04626 /*  Process C++ exception handling block.  */
04627 
04628 static void 
04629 Process_Exception_Region ( WN * node, VAR_TABLE * vtab )
04630 {
04631   char *localname;
04632   INITO_IDX old_inito, new_inito;
04633   ST *old_initst, *new_initst;
04634   INITV_IDX old_initv, new_initv, pinito, parent, prev;
04635   STACK<INITV_IDX> old_stack(Malloc_Mem_Pool), new_stack(Malloc_Mem_Pool);
04636 
04637   Is_True(((WN_opcode(node) == OPC_REGION) && WN_ereg_supp(node)),
04638     ("expecting region node with ereg_supp"));
04639 
04640 #ifdef Is_True_On
04641   switch (mpt) {
04642   case MPP_SINGLE:
04643   case MPP_PDO:
04644   case MPP_PARALLEL_DO:
04645   case MPP_PARALLEL_REGION:
04646   case MPP_ORPHAN:
04647     break;
04648   default:
04649     Fail_FmtAssertion("not inside a PARALLEL region");
04650   }
04651 #endif
04652 
04653 #ifdef KEY
04654   // Don't do it if we reached here in Post_MP_Processing phase
04655   if (parallel_proc)
04656 #endif
04657   Set_PU_has_exc_scopes(Pu_Table[ST_pu(*parallel_proc)]);
04658 
04659   old_inito  = WN_ereg_supp(node);
04660 
04661     // Fix PV 560818: Suppose old_inito is associated with the nested PU
04662     // (as can happen if it appears in a PDO inside a parallel region,
04663     // since Walk_And_Localize() gets called twice on its region).  Then
04664     // we localize by replacing old_inito's ST's, because if we had instead
04665     // created a new INITO then old_inito would have remained associated
04666     // with the nested PU (which is redundant, and probably incorrect) and
04667     // might have contained incorrect unlocalized STs.
04668   if (For_all_until(Inito_Table, Current_scope,
04669           Localize_Nested_PU_Exception_Region(old_inito, vtab,
04670                                         Current_scope)) != 0)
04671     return;
04672 
04673   old_initst = INITO_st(old_inito);
04674   old_initv  = INITO_val(old_inito);
04675 
04676   localname = (char *) alloca(strlen(ST_name(old_initst)) + 32);
04677   sprintf ( localname, "__mpstatic_%s", ST_name(old_initst) );
04678 
04679   new_initst = New_ST (CURRENT_SYMTAB);
04680   ST_Init (new_initst,
04681            Save_Str ( localname ),
04682            ST_class(old_initst),
04683            ST_sclass(old_initst),
04684            ST_export(old_initst),
04685            ST_type(old_initst));
04686 
04687     // is blindly copying all flags correct? -- DRK
04688   new_initst->flags = old_initst->flags;
04689   new_initst->flags_ext = old_initst->flags_ext;
04690 
04691     // Because we're moving stmt_block out of the parent PU, and we assume
04692     // INITO's aren't shared with any other REGION, old_inito will no
04693     // longer be referenced by any REGION upon return from lower_mp(), so
04694     // mark its ST as unused. (If it actually is still referenced, we'll
04695     // hit an assertion in be/cg/cgemit.cxx.) If we don't mark it unused,
04696     // it may contain references to labels created by
04697     // Rename_Duplicate_Labels() whose WN's no longer exist in the parent,
04698     // which would cause a different assertion in cgemit.cxx.
04699   Set_ST_is_not_used(*old_initst);
04700 
04701   WN_ereg_supp(node) = new_inito = New_INITO ( new_initst );
04702 
04703   pinito = new_inito;
04704   parent = 0;
04705   prev = 0;
04706 
04707   while ( old_initv ) {
04708 
04709     (void) Initv_Table.New_entry(new_initv);
04710     INITV& new_initv_ref = Initv_Table[new_initv];
04711     INITV& old_initv_ref = Initv_Table[old_initv];
04712 
04713     if (pinito) {
04714       Set_INITO_val(pinito, new_initv);
04715       pinito = 0;
04716     } else if (parent) {
04717       Set_INITV_blk(parent, new_initv);
04718       parent = 0;
04719     } else if (prev) {
04720       Set_INITV_next(prev, new_initv);
04721     }
04722 
04723     INITVKIND k = INITV_kind(old_initv);
04724     switch ( k ) {
04725 
04726     case INITVKIND_SYMOFF:
04727       INITV_Set_SYMOFF(new_initv_ref, INITV_repeat1(old_initv_ref),
04728           INITV_st(old_initv_ref), INITV_ofst(old_initv_ref));
04729       Localize_INITVKIND_SYMOFF(new_initv, old_initv, vtab);
04730       old_initv = INITV_next(old_initv);
04731       prev = new_initv;
04732       break;
04733 
04734     case INITVKIND_ZERO:
04735       INITV_Set_ZERO(new_initv_ref, INITV_mtype(old_initv_ref),
04736           INITV_repeat2(old_initv_ref));
04737       old_initv = INITV_next(old_initv);
04738       prev = new_initv;
04739       break;
04740 
04741     case INITVKIND_ONE:
04742       INITV_Set_ONE(new_initv_ref, INITV_mtype(old_initv_ref),
04743           INITV_repeat2(old_initv_ref));
04744       old_initv = INITV_next(old_initv);
04745       prev = new_initv;
04746       break;
04747 
04748     case INITVKIND_VAL:
04749       INITV_Set_VAL(new_initv_ref, INITV_tc(old_initv_ref),
04750           INITV_repeat2(old_initv_ref));
04751       old_initv = INITV_next(old_initv);
04752       prev = new_initv;
04753       break;
04754 
04755     case INITVKIND_BLOCK:
04756       INITV_Set_BLOCK(new_initv_ref, INITV_repeat1(old_initv_ref), 0);
04757       old_stack.Push(old_initv);
04758       new_stack.Push(new_initv);
04759       old_initv = INITV_blk(old_initv);
04760       parent = new_initv;
04761       prev = 0;
04762       break;
04763 
04764     case INITVKIND_PAD:
04765       INITV_Set_PAD(new_initv_ref, INITV_pad(old_initv_ref));
04766       old_initv = INITV_next(old_initv);
04767       prev = new_initv;
04768       break;
04769 
04770     case INITVKIND_SYMDIFF:
04771     case INITVKIND_SYMDIFF16:
04772       INITV_Set_SYMDIFF(new_initv_ref, INITV_repeat1(old_initv_ref),
04773           INITV_lab1(old_initv_ref), INITV_st2(old_initv_ref),
04774           INITV_kind(old_initv) == INITVKIND_SYMDIFF16);
04775       old_initv = INITV_next(old_initv);
04776       prev = new_initv;
04777       break;
04778 
04779     case INITVKIND_LABEL:
04780       INITV_Set_LABEL(new_initv_ref, INITV_repeat1(old_initv_ref),
04781                       Translate_Label(INITV_lab(old_initv_ref)));
04782       old_initv = INITV_next(old_initv);
04783       prev = new_initv;
04784       break;
04785 
04786     default:
04787       Fail_FmtAssertion ( "unknown INITV kind %d", (INT) k );
04788 
04789     }
04790 
04791     while (!old_initv && old_stack.Elements() > 0) {
04792       old_initv = INITV_next(old_stack.Pop());
04793       prev = new_stack.Pop();
04794     }
04795 
04796   }
04797   
04798 }
04799 
04800 
04801 /*
04802 To fix PV 553472, Walk_and_Localize() has to update alias information when
04803 renaming variables in orphaned MP constructs.  These updates require that
04804 we maintain parent pointers.  The following data structure allows
04805 Walk_and_Localize() to maintain a list of parent pointers, for orphaned
04806 constructs only.
04807 */
04808 
04809 class Localize_Parent_Stack {
04810 public:
04811   BOOL orphaned;
04812   STACK<WN *> parent_stack; // a node's parent is always below it on the stack
04813     // If _orphaned is FALSE, wn may be NULL; otherwise wn must be the top
04814     // of the Whirl tree to be localized
04815   Localize_Parent_Stack(BOOL _orphaned, WN *top) : orphaned(_orphaned),
04816     parent_stack(Malloc_Mem_Pool) { Push(top); }
04817   void Push(WN *wn) { if (orphaned) parent_stack.Push(wn); }
04818   void Pop() { if (orphaned) (void) parent_stack.Pop(); }
04819 };
04820 
04821 
04822 #define OMP_NON_POD_LASTLOCAL_FLAG_NAME "__omp_non_pod_lastlocal"
04823 #define OMP_NON_POD_FIRST_AND_LASTLOCAL_FLAG_NAME \
04824         "__omp_non_pod_first_and_lastlocal"
04825 
04826 /*
04827 Return TRUE if wn is an IF node that looks like this:
04828 
04829    IF
04830      I4I4LDID 0 <1,84,st_name> T<4,.predef_I4,4>
04831      I4INTCONST 0 (0x0)
04832     I4I4NE
04833    THEN
04834     ....
04835    END_IF
04836 
04837 where st_name can be either __omp_non_pod_lastlocal or
04838 __omp_non_pod_first_and_lastlocal.
04839 
04840 If return value is TRUE, return TRUE in *is_first_and_last if st_name
04841 was __omp_non_pod_first_and_lastlocal, FALSE otherwise.
04842 */
04843 
04844 BOOL 
04845 Is_Nonpod_Finalization_IF(WN *wn, BOOL *is_first_and_last)
04846 {
04847   if (WN_operator(wn) != OPR_IF)
04848     return FALSE;
04849 
04850   WN *test = WN_if_test(wn);
04851   if (WN_operator(test) != OPR_NE)
04852     return FALSE;
04853 
04854   WN *ldid = WN_kid0(test), *intconst = WN_kid1(test);
04855   ST *ldid_st;
04856   if (WN_operator(ldid) != OPR_LDID ||
04857       (ldid_st = WN_st(ldid)) == NULL)
04858     return FALSE;
04859 
04860   BOOL first_and_last;
04861 
04862   if (strcmp(ST_name(*ldid_st), OMP_NON_POD_LASTLOCAL_FLAG_NAME) == 0)
04863     first_and_last = FALSE;
04864   else if (strcmp(ST_name(*ldid_st),
04865                   OMP_NON_POD_FIRST_AND_LASTLOCAL_FLAG_NAME) == 0)
04866     first_and_last = TRUE;
04867   else
04868     return FALSE;
04869 
04870   if (WN_operator(intconst) != OPR_INTCONST ||
04871       WN_rtype(intconst) != MTYPE_I4 ||
04872       WN_const_val(intconst) != 0)
04873     return FALSE;
04874 
04875   *is_first_and_last = first_and_last;
04876   return TRUE;
04877 }
04878 
04879 
04880 /*
04881 Walk the tree, replacing global references with local ones.  Within
04882 parallel regions, also translate label numbers from those of the parent PU
04883 to those of the child, and generate new INITO/INITV structures (for e.g.
04884 C++ exception handling blocks) for the child PU.
04885 
04886 Argument is_par_region must be TRUE iff tree is an MP construct that's a
04887 parallel region.
04888 
04889 In a non-recursive call to this routine, output argument
04890 non_pod_finalization must point to a NULL WN *. Upon return,
04891 (*non_pod_finalization) points to the non-POD finalization IF node (if one
04892 was found in the tree), and this IF node is removed from the tree; the IF
04893 node cannot have been the "tree" argument in the non-recursive call.
04894 
04895 Note that within orphaned worksharing constructs, non-POD variables have
04896 been localized already by the frontend, so we don't rewrite references to
04897 such variables that appear in vtab.
04898 
04899 In a non-recursive call to this routine, it is guaranteed that if the root
04900 node of tree is not a load or store (e.g. it's a DO_LOOP or block), that
04901 root node will not be replaced.
04902 */
04903 
04904 static WN *
04905 Walk_and_Localize (WN * tree, VAR_TABLE * vtab, Localize_Parent_Stack * lps,
04906                    BOOL is_par_region, WN **non_pod_finalization)
04907 {
04908   OPCODE op;
04909   OPERATOR opr;
04910   INT32 i;
04911   WN *r;
04912   WN *temp;
04913   ST *old_sym;
04914   WN_OFFSET old_offset;
04915   VAR_TABLE *w;
04916   const BOOL is_orphaned_worksharing =
04917                 (mpt == MPP_ORPHANED_PDO || mpt == MPP_ORPHANED_SINGLE);
04918 
04919   /* Ignore NULL subtrees. */
04920 
04921   if (tree == NULL)
04922     return (tree);
04923 
04924   /* Initialization. */
04925 
04926   op = WN_opcode(tree);
04927   opr = OPCODE_operator(op);
04928 
04929   /* Look for and replace any nodes referencing localized symbols */
04930 
04931   if (opr == OPR_LDID) {
04932     old_sym = WN_st(tree);
04933     old_offset = WN_offsetx(tree);
04934     for (w=vtab; w->orig_st; w++) {
04935       if ((w->orig_st == old_sym) &&
04936 #ifndef KEY
04937     (w->has_offset ? (w->orig_offset == old_offset) : TRUE ) &&
04938 #endif
04939           (w->vtype != VAR_REDUCTION_ARRAY) &&
04940     ! (w->is_non_pod && is_orphaned_worksharing)) {
04941   if (w->is_static_array) {
04942     temp = WN_Lda ( Pointer_type, w->new_offset, w->new_st);
04943       // PV 682222: if the MP lowerer introduces LDA's on privatized
04944       // ST's, we must run PU_adjust_addr_flags() before we run WOPT
04945     Set_BE_ST_pu_needs_addr_flag_adjust (PU_Info_proc_sym(Current_PU_Info));
04946     WN_Delete ( tree );
04947     tree = temp;
04948     // Don't do the following; it depends on a back-end-specific table
04949     // that doesn't exist until we're compiling the nested MP
04950     // procedure, and addr_used_locally is recomputed by the optimizer
04951     // in any case.
04952     // Set_BE_ST_addr_used_locally(w->new_st);
04953     op = WN_opcode(tree);
04954     opr = OPCODE_operator(op);
04955   } else {
04956           WN_st_idx(tree) = ST_st_idx(w->new_st);
04957     if (w->has_offset)
04958 #ifdef KEY
04959       WN_set_offsetx(tree, old_offset);
04960 #else
04961       WN_set_offsetx(tree, w->new_offset);
04962 #endif
04963   }
04964   if (w->is_dynamic_array) {  // fix PV 553472 by updating aliases
04965             // child of ldst that's on the path to tree
04966           WN *ldst, *ldst_child = tree;
04967 
04968             // search for first parent that's ILOAD or ISTORE
04969           for (INT i = 0; i < lps->parent_stack.Elements();
04970          i++, ldst_child = ldst) {
04971             ldst = lps->parent_stack.Top_nth(i);
04972       opr = WN_operator(ldst);
04973 
04974               // kid0 of ARRAY must be on path to tree (i.e., tree must
04975               // be part of the base address computation)
04976             if (opr == OPR_ARRAY && ldst_child != WN_kid0(ldst))
04977               break;
04978               // kid1 of ISTORE must be on path to tree (i.e., tree must
04979               // be part of the store address computation)
04980             if (opr == OPR_ISTORE && ldst_child != WN_kid1(ldst))
04981               break;
04982 
04983             if (opr != OPR_ILOAD && opr != OPR_ISTORE)
04984               continue;
04985 
04986               // this tells WOPT that despite the fact that w->new_st has
04987               // the PT_TO_UNIQUE_MEM bit set, ldst in fact accesses memory
04988               // that's pointed to by w->new_st
04989             Erase_Restricted_Mapping(ldst);
04990           }
04991   }
04992   break;
04993       }
04994     }
04995   } else if (opr == OPR_STID) {
04996     old_sym = WN_st(tree);
04997     old_offset = WN_offsetx(tree);
04998     for (w=vtab; w->orig_st; w++) {
04999       if ((w->vtree == NULL) &&
05000     (w->orig_st == old_sym) &&
05001 #ifndef KEY
05002     (w->has_offset ? (w->orig_offset == old_offset) : TRUE ) &&
05003 #endif
05004     ! (w->is_non_pod && is_orphaned_worksharing)) {
05005   WN_st_idx(tree) = ST_st_idx(w->new_st);
05006   if (w->has_offset)
05007 #ifdef KEY
05008     WN_set_offsetx(tree, old_offset);
05009 #else
05010     WN_set_offsetx(tree, w->new_offset);
05011 #endif
05012   break;
05013       }
05014     }
05015   } else if (opr == OPR_ILOAD) {
05016     for (w=vtab; w->orig_st; w++) {
05017       if ((w->vtree && (WN_Compare_Trees(w->vtree, WN_kid0(tree)) == 0)) ||
05018     (w->vtreex && (WN_Compare_Trees(w->vtreex, WN_kid0(tree)) == 0))) {
05019         Is_True(! w->is_non_pod, ("non-POD pointer expression?!?"));
05020   temp = WN_RLdid ( Promote_Type(w->mtype), w->mtype, w->new_offset,
05021         w->new_st, w->ty );
05022 #ifdef KEY // bug 10707: honor the type in the original tree node
05023   if (WN_rtype(tree) == MTYPE_F8 && WN_rtype(temp) == MTYPE_C8 ||
05024       WN_rtype(tree) == MTYPE_F4 && WN_rtype(temp) == MTYPE_C4) {
05025     WN_set_rtype(temp, WN_rtype(tree));
05026     WN_set_desc(temp, WN_desc(tree));
05027   }
05028 #endif
05029   WN_DELETE_Tree ( tree );
05030   tree = temp;
05031   op = WN_opcode(tree);
05032   opr = OPCODE_operator(op);
05033   break;
05034       }
05035     }
05036 #ifdef KEY
05037     if (opr == OPR_ILOAD)  // There was no match above
05038       WN_kid0(tree) = Walk_and_Localize ( WN_kid0(tree), vtab, lps,
05039                                           is_par_region, non_pod_finalization );
05040 #endif // KEY
05041   } else if (opr == OPR_ISTORE) {
05042     for (w=vtab; w->orig_st; w++) {
05043       if ((w->vtree && (WN_Compare_Trees(w->vtree, WN_kid1(tree)) == 0)) ||
05044     (w->vtreex && (WN_Compare_Trees(w->vtreex, WN_kid1(tree)) == 0))) {
05045         Is_True(! w->is_non_pod, ("non-POD pointer expression?!?"));
05046   temp = WN_Stid ( w->mtype, w->new_offset, w->new_st, w->ty,
05047        WN_kid0(tree) );
05048 #ifdef KEY // bug 10707: honor the type in the original tree node
05049   if (WN_desc(tree) == MTYPE_F8 && WN_desc(temp) == MTYPE_C8 ||
05050       WN_desc(tree) == MTYPE_F4 && WN_desc(temp) == MTYPE_C4) {
05051     WN_set_desc(temp, WN_desc(tree));
05052   }
05053 #endif
05054   WN_linenum(temp) = WN_linenum(tree);
05055   WN_prev(temp) = WN_prev(tree);
05056   if (WN_prev(temp))
05057     WN_next(WN_prev(temp)) = temp;
05058   WN_next(temp) = WN_next(tree);
05059   if (WN_next(temp))
05060     WN_prev(WN_next(temp)) = temp;
05061   WN_DELETE_Tree ( WN_kid1(tree) );
05062   WN_Delete ( tree );
05063   tree = temp;
05064   op = WN_opcode(tree);
05065   opr = OPCODE_operator(op);
05066   break;
05067       }
05068     }
05069     // PV 600983: don't translate labels (or exception regions) inside
05070     // orphaned constructs
05071   } else if ((op == OPC_REGION) && WN_ereg_supp(tree) &&
05072              !is_orphaned_worksharing) {
05073     Process_Exception_Region ( tree, vtab );
05074   } else if (OPCODE_has_label(op) && is_par_region && 
05075              !is_orphaned_worksharing) {
05076     LABEL_IDX new_lab =  Translate_Label (WN_label_number(tree));
05077     WN_label_number(tree) = new_lab;
05078     if (opr == OPR_LDA_LABEL) Set_LABEL_addr_saved(new_lab); // Bug 13821
05079   } else if (OPCODE_has_sym(op) && WN_st(tree)) {
05080     old_sym = WN_st(tree);
05081     old_offset = OPCODE_has_offset(op) ? WN_offsetx(tree) : 0;
05082     for (w=vtab; w->orig_st; w++) {
05083       if ((w->vtype != VAR_REDUCTION_ARRAY) &&
05084     (w->orig_st == old_sym) &&
05085     (w->has_offset ? (w->orig_offset == old_offset) : TRUE ) &&
05086     ! (w->is_non_pod && is_orphaned_worksharing)) {
05087   WN_st_idx(tree) = ST_st_idx(w->new_st);
05088   if (OPCODE_has_offset(op) && w->has_offset)
05089     WN_set_offsetx(tree, w->new_offset);
05090   break;
05091       }
05092     }
05093   }
05094 
05095   /* Walk all children */
05096 
05097   lps->Push(tree);
05098   if (op == OPC_BLOCK) {
05099     r = WN_first(tree);
05100     while (r) { // localize each node in block
05101       r = Walk_and_Localize ( r, vtab, lps, is_par_region, 
05102                               non_pod_finalization );
05103       if (WN_prev(r) == NULL)
05104         WN_first(tree) = r;
05105       if (WN_next(r) == NULL)
05106         WN_last(tree) = r;
05107 
05108       if (Is_Nonpod_Finalization_IF(r, &non_pod_first_and_lastprivate)) {
05109         if (*non_pod_finalization)
05110           Fail_FmtAssertion("already found non-POD finalization IF");
05111           // remove mem barriers around the IF
05112         WN *bar1 = WN_prev(r), *bar2 = WN_next(r), *then = WN_then(r),
05113            *bar3 = WN_first(then), *bar4 = WN_last(then);
05114         Is_True(bar1 && WN_operator(bar1) == OPR_FORWARD_BARRIER,
05115           ("bad bar1"));
05116         Is_True(bar2 && WN_operator(bar2) == OPR_BACKWARD_BARRIER,
05117           ("bad bar2"));
05118         Is_True(bar3 && WN_operator(bar3) == OPR_BACKWARD_BARRIER,
05119           ("bad bar3"));
05120         Is_True(bar4 && WN_operator(bar4) == OPR_FORWARD_BARRIER,
05121           ("bad bar4"));
05122         WN_DELETE_FromBlock(tree, bar1);
05123         WN_DELETE_FromBlock(tree, bar2);
05124         WN_DELETE_FromBlock(then, bar3);
05125         WN_DELETE_FromBlock(then, bar4);
05126           // extract finalization code without localizing it
05127         *non_pod_finalization = r;
05128         WN *tmp = WN_next(r);
05129         WN_EXTRACT_FromBlock(tree, r);
05130         r = tmp;
05131       } else {
05132         r = WN_next(r);
05133       }
05134     }
05135   } else {
05136     for (i=0; i < WN_kid_count(tree); i++)
05137       WN_kid(tree, i) = Walk_and_Localize ( WN_kid(tree, i), vtab, lps,
05138                                             is_par_region,
05139                                             non_pod_finalization );
05140   }
05141   lps->Pop();
05142 
05143   return (tree);
05144 }   
05145 
05146 
05147 /*
05148 * Create any needed temporaries in local scope. especially for Dos 
05149 * This function has been modified by csc.
05150 */
05151 
05152 
05153 static void 
05154 Make_Local_Temps ( void )
05155 {
05156     // note that if multiple orphaned PDO's appear in a PU, then multiple
05157     // instances of these local variables will be inserted into the PU's
05158     // symbol table
05159   //Maybe need to be changed to Create_Temp
05160   Create_Preg_or_Temp( do_index_type, "temp_limit", &limit_st, &limit_ofst );
05161 
05162   Create_Temp( do_index_type, "do_upper", &local_upper );
05163   Set_ST_addr_passed( local_upper );
05164 
05165   Create_Temp( do_index_type, "do_lower", &local_lower );
05166   Set_ST_addr_passed( local_lower );
05167 
05168   Create_Temp( do_index_type, "do_stride", &local_stride );
05169   Set_ST_addr_passed( local_stride );
05170 
05171   Create_Temp( MTYPE_I4, "last_iter", &last_iter );
05172   Set_ST_addr_passed( last_iter );
05173 
05174 }
05175 
05176 
05177 /***********************************************************************
05178  *
05179  * Return a global TY of size 128-bytes, aligned at 128-bytes.
05180  * Useful for unioning with lock variables.
05181  *
05182  ***********************************************************************/
05183 /* To replace static TY_IDX Lock_Padding_TY () with static void Create_Lock_Type( void ) */
05184 // CAN BE DELETED. 
05185 // since no more padding needed for Intel RTL lock type.
05186 
05187 static TY_IDX 
05188 Lock_Padding_TY () 
05189 {
05190 
05191   static TY_IDX arr_ty = TY_IDX_ZERO;
05192 
05193   if (arr_ty == TY_IDX_ZERO) 
05194   {
05195       // define arr_ty as an array of 128 bytes
05196     TY& ty = New_TY (arr_ty);
05197     TY_Init (ty, 128, KIND_ARRAY, MTYPE_UNKNOWN, Save_Str("__lock_pad_type"));
05198     Set_TY_etype(ty, Be_Type_Tbl(MTYPE_I1));
05199 
05200     ARB_HANDLE arb = New_ARB ();
05201     ARB_Init (arb, 1, 1, 1);
05202     Set_ARB_dimension(arb, 1);
05203     Set_ARB_first_dimen(arb);
05204     Set_ARB_last_dimen(arb);
05205     Set_ARB_const_lbnd(arb);
05206     Set_ARB_lbnd_val(arb,0);
05207     Set_ARB_const_ubnd(arb);
05208     Set_ARB_ubnd_val(arb,128-1);
05209     Set_ARB_const_stride(arb);
05210     Set_ARB_stride_val(arb,1);
05211 
05212     Set_TY_arb(ty, arb);
05213     Set_TY_align (arr_ty, 128);
05214   }
05215 
05216   return arr_ty;
05217 }
05218 
05219 /*  Create named critical lock temporary in parent scope. */ 
05220 // need a parent scope lock, not a common scope one?
05221 static ST * 
05222 Create_Critical_Lock ( void ) 
05223 {
05224   ST *st;
05225   char st_name[32];
05226 
05227   st = New_ST (GLOBAL_SYMTAB);
05228   sprintf ( st_name, "__mplock_%d", ++lock_id );
05229   Create_Lock_Type( );
05230   ST_Init (st,
05231            Save_Str (st_name),
05232            CLASS_VAR,
05233            SCLASS_COMMON,
05234            EXPORT_PREEMPTIBLE,
05235            lock_ty_idx );
05236 
05237   Set_ST_addr_passed(st);
05238 
05239   shared_table[shared_count++] = st;
05240 
05241   
05242 //  /* pad out to a cache-line. Union it with an 128-byte character array */
05243 //  {
05244 //    char name[64];
05245 //    ST *pad;
05246 //
05247 //   sprintf (name, "%s_pad", st_name);
05248 //  pad = New_ST (GLOBAL_SYMTAB);
05249 //    ST_Init (pad,
05250 //            Save_Str (name),
05251 //             CLASS_VAR,
05252 //             SCLASS_FSTATIC,
05253 //             EXPORT_LOCAL,
05254 //             Lock_Padding_TY());
05255 //
05256 //    Set_ST_addr_passed (pad);
05257 //
05258 //    St_Block_Union (st, pad);
05259 //  }
05260 
05261   critical_lock_not_init = TRUE;
05262 
05263   return (st);
05264 }
05265 
05266 /*  Create unnamed critical lock temporary in parent scope. */
05267 /*  lock lg */
05268 static ST * 
05269 Create_Unnamed_Critical_Lock ( void )
05270 {
05271   if( unnamed_lock_st != NULL )
05272   {
05273     critical_lock_not_init = FALSE;
05274     return unnamed_lock_st;
05275   }
05276   ST *st;
05277   char st_name[32];
05278 
05279   st = New_ST (GLOBAL_SYMTAB);
05280   // The naming convention should be fixed to guarantee its uniform
05281   sprintf ( st_name, "__mplock_0" );
05282   Create_Lock_Type( );
05283   ST_Init (st,
05284            Save_Str (st_name),
05285            CLASS_VAR,
05286            SCLASS_COMMON,
05287            EXPORT_PREEMPTIBLE,
05288            lock_ty_idx );
05289 
05290   Set_ST_addr_passed(st);
05291 //  Set_ST_is_initialized(st);
05292 //  Set_ST_init_value_zero(st);
05293 
05294   shared_table[shared_count++] = st;
05295 
05296 // 
05297 //  /* pad out to a cache-line. Union it with an 128-byte character array */
05298 //  {
05299 //    char name[64];
05300 //    ST *pad;
05301 //
05302 //    sprintf (name, "%s_pad", st_name);
05303 //    pad = New_ST (GLOBAL_SYMTAB);
05304 //    ST_Init (pad,
05305 //             Save_Str (name),
05306 //             CLASS_VAR,
05307 //             SCLASS_FSTATIC,
05308 //             EXPORT_LOCAL,
05309 //             Lock_Padding_TY());
05310 //
05311 //   Set_ST_addr_passed (pad);
05312 //    St_Block_Union (st, pad);
05313 //  }
05314 
05315   critical_lock_not_init = TRUE;
05316   unnamed_lock_st = st;
05317 
05318   return (st);
05319 }
05320 
05321 
05322 /*  Create lock variable for named lock i.e. in a COMMON block.
05323  *  lock_name is the ST for the lock-name.
05324  */
05325 static ST * Create_Name_Lock (ST* lock_name)
05326 {
05327   ST *st;
05328 //  ST *base_st;
05329   char *name;
05330 
05331   name = (char*) alloca (Targ_String_Length(ST_tcon_val(lock_name)) + 30);
05332 
05333   // For the IA64's cache line is 32 byte, so 
05334   // The padding is not need, But I'm not very
05335   // sure, need to be fixed. by csc.
05336 /*  static TY_IDX struct_ty = 0;
05337 
05338  if (struct_ty == TY_IDX_ZERO) {
05339     // Create a struct for the common 
05340     FLD_HANDLE field = New_FLD ();
05341     FLD_Init(field, Save_Str("padding"), Lock_Padding_TY(), 0);
05342     Set_FLD_last_field(field);
05343 
05344     // Create a struct type with the above fields 
05345     TY &ty = New_TY(struct_ty);
05346     TY_Init(ty, TY_size(FLD_type(field)), KIND_STRUCT, MTYPE_M,
05347             Save_Str("padding_type"));
05348     Set_TY_fld(ty, field);
05349     Set_TY_align(struct_ty, TY_align(FLD_type(field)));
05350   }
05351 
05352   // Now create the ST entry for the COMMON block 
05353   name = (char*) alloca (Targ_String_Length(ST_tcon_val(lock_name)) + 30);
05354   sprintf (name, "__namelock_common_%s",
05355            Targ_String_Address(ST_tcon_val(lock_name)));
05356 
05357   base_st            = New_ST(GLOBAL_SYMTAB);
05358   ST_Init(base_st, Save_Str(name), CLASS_VAR, SCLASS_COMMON,
05359           EXPORT_PREEMPTIBLE, struct_ty);
05360 */
05361   /* now create the real ST for the variable */
05362   Create_Lock_Type( );
05363   sprintf (name, "__namelock_%s",
05364            Targ_String_Address(ST_tcon_val(lock_name)));
05365   st = New_ST (GLOBAL_SYMTAB);
05366   ST_Init(st, 
05367           Save_Str(name), 
05368           CLASS_VAR, 
05369           SCLASS_COMMON, 
05370           EXPORT_PREEMPTIBLE,
05371           lock_ty_idx );
05372   Set_ST_addr_passed(st);
05373 
05374   critical_lock_not_init = TRUE;
05375 
05376   return (st);
05377 }
05378 
05379 
05380 /*  Do all processing necessary for pregs existing in code destined for nested
05381     procedure.  */
05382 
05383 static void 
05384 Process_Preg_Temps ( WN * tree, BOOL is_region )
05385 {
05386   INT32 i;
05387   INT32 tcnt  = PREG_Table_Size(CURRENT_SYMTAB);
05388   BOOL  anytemp = FALSE;
05389   ST    *st;
05390   TY_IDX ty;
05391   WN    *wn;
05392   TYPE_ID     mtype;
05393   PREG_INFO *preg;
05394   PREG_CLASS  pclass;
05395   char        tempname[32];
05396 
05397   if (tcnt == 0)
05398     return;
05399 
05400   PREG_INFO_TABLE prit(&mp_lower_pool, tcnt, TRUE, &preg_info_table);
05401 
05402   /*  Find out information about all preg usage in nested mp PU being
05403       created.  */
05404 
05405   Walk_and_Info_Pregs ( tree );
05406 
05407   for (wn = reduction_nodes; wn; wn = WN_next(wn))
05408     if ((WN_opcode(wn) == OPC_PRAGMA) && WN_st(wn) &&
05409        (ST_class(WN_st(wn)) == CLASS_PREG) &&
05410        !Preg_Is_Dedicated(WN_offsetx(wn)) )
05411       prit[Get_Preg_Idx(WN_offsetx(wn))].reduction_list = TRUE;
05412 
05413   for (wn = lastlocal_nodes; wn; wn = WN_next(wn))
05414     if (WN_st(wn) && (ST_class(WN_st(wn)) == CLASS_PREG) &&
05415        !Preg_Is_Dedicated(WN_offsetx(wn)) ) {
05416       prit[Get_Preg_Idx(WN_offsetx(wn))].lastlocal_list = TRUE;
05417       prit[Get_Preg_Idx(WN_offsetx(wn))].shared_flags = WN_pragma_arg2(wn);
05418   }
05419 
05420   for (wn = local_nodes; wn; wn = WN_next(wn))
05421     if (WN_st(wn) && (ST_class(WN_st(wn)) == CLASS_PREG) &&
05422         !Preg_Is_Dedicated(WN_offsetx(wn)) )
05423       prit[Get_Preg_Idx(WN_offsetx(wn))].local_list = TRUE;
05424 
05425   for (wn = firstprivate_nodes; wn; wn = WN_next(wn))
05426     if (WN_st(wn) && (ST_class(WN_st(wn)) == CLASS_PREG) &&
05427         !Preg_Is_Dedicated(WN_offsetx(wn)) )
05428           /* Treat FIRSTPRIVATE preg just like a LOCAL one */
05429       prit[Get_Preg_Idx(WN_offsetx(wn))].local_list = TRUE;
05430 
05431   for (wn = shared_nodes; wn; wn = WN_next(wn))
05432     if (WN_st(wn) && (ST_class(WN_st(wn)) == CLASS_PREG) &&
05433        !Preg_Is_Dedicated(WN_offsetx(wn)) ) {
05434       prit[Get_Preg_Idx(WN_offsetx(wn))].shared_list = TRUE;
05435       prit[Get_Preg_Idx(WN_offsetx(wn))].shared_flags = WN_pragma_arg2(wn);
05436     }
05437 
05438   if (if_preamble_block)
05439     for (wn = WN_first(if_preamble_block); wn; wn = WN_next(wn))
05440       if ((WN_operator(wn) == OPR_STID) &&
05441     (ST_class(WN_st(wn)) == CLASS_PREG) &&
05442     !Preg_Is_Dedicated(WN_offsetx(wn)) )
05443         prit[Get_Preg_Idx(WN_offsetx(wn))].preamble_store = TRUE;
05444 
05445   if (do_preamble_block)
05446     for (wn = WN_first(do_preamble_block); wn; wn = WN_next(wn))
05447       if ((WN_operator(wn) == OPR_STID) &&
05448     (ST_class(WN_st(wn)) == CLASS_PREG) &&
05449     !Preg_Is_Dedicated(WN_offsetx(wn)) )
05450         prit[Get_Preg_Idx(WN_offsetx(wn))].preamble_store = TRUE;
05451 
05452   /*  Process preg information and create parent temps for any livein /
05453       liveout values.  */
05454 
05455   for (i = 1; i < tcnt; i++) {
05456     preg = &prit[i];
05457 
05458     if (preg->type == MTYPE_UNKNOWN)
05459       pclass = PCLASS_DEADIN_DEADOUT;
05460     else if (preg->lastlocal_list)
05461       if (preg->shared_flags & SHARED_DEADOUT)
05462   pclass = PCLASS_DEADIN_DEADOUT;
05463       else
05464   pclass = PCLASS_DEADIN_LIVEOUT;
05465     else if (preg->local_list)
05466       if (preg->preamble_store)
05467         pclass = PCLASS_COPYIN_DEADOUT;
05468       else
05469         pclass = PCLASS_DEADIN_DEADOUT;
05470     else if (preg->reduction_list)
05471       pclass = PCLASS_LIVEIN_LIVEOUT;
05472     else if (preg->shared_list)
05473       if (preg->shared_flags & SHARED_DEADIN)
05474   if (preg->shared_flags & SHARED_DEADOUT)
05475     pclass = PCLASS_DEADIN_DEADOUT;
05476   else
05477     pclass = PCLASS_DEADIN_LIVEOUT;
05478       else
05479   if (preg->shared_flags & SHARED_DEADOUT)
05480     pclass = PCLASS_LIVEIN_DEADOUT;
05481   else
05482     pclass = PCLASS_LIVEIN_LIVEOUT;
05483     else if (preg->preamble_store)
05484       pclass = PCLASS_COPYIN_DEADOUT;
05485     else
05486       pclass = PCLASS_DEADIN_DEADOUT;
05487     preg->pclass = pclass;
05488 
05489     if (pclass != PCLASS_DEADIN_DEADOUT) {
05490 
05491       anytemp = TRUE;
05492       PREG_NUM pnum = Get_Preg_Num(i);
05493       mtype = preg->type;
05494       ty = MTYPE_To_TY ( mtype );
05495       sprintf ( tempname, "__mptemp_preg%d", pnum );
05496 
05497       st = New_ST ( );
05498       ST_Init ( st, Save_Str ( tempname ), CLASS_VAR, SCLASS_AUTO,
05499         EXPORT_LOCAL, ty );
05500 
05501       Set_ST_has_nested_ref ( st );
05502 
05503       preg->temp = st;
05504 
05505         // if preg is copyin or livein, spill to corresponding temp in parent
05506       if ((pclass == PCLASS_COPYIN_DEADOUT) ||
05507     (pclass == PCLASS_COPYIN_COPYOUT) ||
05508     (pclass == PCLASS_LIVEIN_DEADOUT) ||
05509     (pclass == PCLASS_LIVEIN_LIVEOUT)) {
05510   wn = WN_Stid ( mtype, 0, st, ty, WN_LdidPreg ( mtype, pnum ));
05511   WN_linenum(wn) = line_number;
05512   if (livein_block == NULL)
05513     livein_block = WN_CreateBlock ( );
05514   WN_INSERT_BlockLast ( livein_block, wn );
05515       }
05516 
05517         // if preg is copyin, restore from parent's temp to child's preg
05518       if ((pclass == PCLASS_COPYIN_DEADOUT) ||
05519     (pclass == PCLASS_COPYIN_COPYOUT)) {
05520   wn = WN_StidIntoPreg ( mtype, pnum, MTYPE_To_PREG ( mtype ),
05521              WN_RLdid ( Promote_Type(mtype), mtype, 0, st,
05522             ty ));
05523   WN_linenum(wn) = line_number;
05524   if (copyin_block == NULL)
05525     copyin_block = WN_CreateBlock ( );
05526   WN_INSERT_BlockLast ( copyin_block, wn );
05527       }
05528 
05529         // if preg is copyout, spill child's preg to parent's temp
05530       if ((pclass == PCLASS_DEADIN_COPYOUT) ||
05531     (pclass == PCLASS_COPYIN_COPYOUT)) {
05532   wn = WN_Stid ( mtype, 0, st, ty, WN_LdidPreg ( mtype, pnum ));
05533   WN_linenum(wn) = line_number;
05534   if (copyout_block == NULL)
05535     copyout_block = WN_CreateBlock ( );
05536   WN_INSERT_BlockLast ( copyout_block, wn );
05537       }
05538 
05539         // if preg is copyout or liveout, restore parent's preg from temp
05540       if ((pclass == PCLASS_DEADIN_COPYOUT) ||
05541     (pclass == PCLASS_COPYIN_COPYOUT) ||
05542     (pclass == PCLASS_DEADIN_LIVEOUT) ||
05543     (pclass == PCLASS_LIVEIN_LIVEOUT)) {
05544   wn = WN_StidIntoPreg ( mtype, pnum, MTYPE_To_PREG ( mtype ),
05545              WN_RLdid ( Promote_Type(mtype), mtype, 0, st,
05546             ty ));
05547   WN_linenum(wn) = line_number;
05548   if (liveout_block == NULL)
05549     liveout_block = WN_CreateBlock ( );
05550   WN_INSERT_BlockLast ( liveout_block, wn );
05551   shared_table[shared_count++] = st;
05552       }
05553 
05554     }
05555   }
05556 
05557   /*  Finally, translate appropriate preg usage to uplevel temp usage.  */
05558 
05559   if (anytemp) {
05560 
05561     Walk_and_Replace_Pregs ( tree );
05562 
05563     for (wn = reduction_nodes; wn; wn = WN_next(wn))
05564       if ((WN_opcode(wn) == OPC_PRAGMA) && WN_st(wn) &&
05565     (ST_class(WN_st(wn)) == CLASS_PREG) &&
05566     !Preg_Is_Dedicated(WN_offsetx(wn)) ) {
05567   PREG_NUM pnum = Get_Preg_Idx(WN_offsetx(wn));
05568   preg = &prit[pnum];
05569   if (preg->temp) {
05570     WN_st_idx(wn) = ST_st_idx(preg->temp);
05571     WN_set_offsetx(wn, 0);
05572   }
05573       } else if (WN_opcode(wn) == OPC_XPRAGMA)
05574   Walk_and_Replace_Pregs ( WN_kid0(wn) );
05575 
05576     for (wn = lastlocal_nodes; wn; wn = WN_next(wn))
05577       if (WN_st(wn) && (ST_class(WN_st(wn)) == CLASS_PREG) &&
05578     !Preg_Is_Dedicated(WN_offsetx(wn)) ) {
05579   PREG_NUM pnum = Get_Preg_Idx(WN_offsetx(wn));
05580   preg = &prit[pnum];
05581   if (preg->temp) {
05582     WN_st_idx(wn) = ST_st_idx(preg->temp);
05583     WN_set_offsetx(wn, 0);
05584   }
05585       }
05586 
05587     for (wn = local_nodes; wn; wn = WN_next(wn))
05588       if (WN_st(wn) && (ST_class(WN_st(wn)) == CLASS_PREG) &&
05589     !Preg_Is_Dedicated(WN_offsetx(wn)) ) {
05590   PREG_NUM pnum = Get_Preg_Idx(WN_offsetx(wn));
05591   preg = &prit[pnum];
05592   if (preg->temp) {
05593     WN_st_idx(wn) = ST_st_idx(preg->temp);
05594     WN_set_offsetx(wn, 0);
05595   }
05596       }
05597 
05598     for (wn = firstprivate_nodes; wn; wn = WN_next(wn))
05599       if (WN_st(wn) && (ST_class(WN_st(wn)) == CLASS_PREG) &&
05600     !Preg_Is_Dedicated(WN_offsetx(wn)) ) {
05601   PREG_NUM pnum = Get_Preg_Idx(WN_offsetx(wn));
05602   preg = &prit[pnum];
05603   if (preg->temp) {
05604     WN_st_idx(wn) = ST_st_idx(preg->temp);
05605     WN_set_offsetx(wn, 0);
05606   }
05607       }
05608 
05609     for (wn = shared_nodes; wn; wn = WN_next(wn))
05610       if (WN_st(wn) && (ST_class(WN_st(wn)) == CLASS_PREG) &&
05611     !Preg_Is_Dedicated(WN_offsetx(wn)) ) {
05612   PREG_NUM pnum = Get_Preg_Idx(WN_offsetx(wn));
05613   preg = &prit[pnum];
05614   if (preg->temp) {
05615     WN_st_idx(wn) = ST_st_idx(preg->temp);
05616     WN_set_offsetx(wn, 0);
05617   }
05618       }
05619 
05620   }
05621 }
05622 
05623 
05624 /*
05625 Transfer all maps (except WN_MAP_FEEDBACK) associated with each node in the
05626 tree from the parent mapset to the kid's.
05627 */
05628 
05629 static void
05630 Transfer_Maps_R ( WN_MAP_TAB * parent, WN_MAP_TAB * child, WN * tree,
05631                   RID * root_rid );
05632 
05633 static void
05634 Transfer_Maps ( WN_MAP_TAB * parent, WN_MAP_TAB * child, WN * tree,
05635                 RID * root_rid )
05636 {
05637     // to preserve WN_MAP_FEEDBACK in child map table, copy its contents
05638     // to fb_map
05639   HASH_TABLE<WN *, INT32> fb_map(NUM_HASH_ELEMENTS, Malloc_Mem_Pool);
05640   WN_ITER *wni = WN_WALK_TreeIter(tree);
05641 
05642   for ( ; wni; wni = WN_WALK_TreeNext(wni)) {
05643     WN *wn = WN_ITER_wn(wni);
05644 
05645     fb_map.Enter(wn, IPA_WN_MAP32_Get(child, WN_MAP_FEEDBACK, wn));
05646   }
05647 
05648   Transfer_Maps_R(parent, child, tree, root_rid); // overwrites WN_MAP_FEEDBACK
05649 
05650     // now restore values for WN_MAP_FEEDBACK from fb_map
05651   HASH_TABLE_ITER<WN *, INT32> fb_map_iter(&fb_map);
05652   WN *wn;
05653   INT32 val;
05654 
05655   while (fb_map_iter.Step(&wn, &val))
05656     IPA_WN_MAP32_Set(child, WN_MAP_FEEDBACK, wn, val);
05657 
05658 //  parent->_is_used[WN_MAP_FEEDBACK] = is_used;  // restore the flag
05659 } // Transfer_Maps
05660 
05661 // this function does the real work
05662 static void
05663 Transfer_Maps_R ( WN_MAP_TAB * parent, WN_MAP_TAB * child, WN * tree,
05664                   RID * root_rid )
05665 {
05666   WN *node;
05667   INT32 i;
05668 
05669   if (tree) {
05670     if (WN_opcode(tree) == OPC_BLOCK) {
05671       for (node = WN_first(tree); node; node = WN_next(node))
05672   Transfer_Maps_R ( parent, child, node, root_rid );
05673     } else
05674       for (i = 0; i < WN_kid_count(tree); i++)
05675   Transfer_Maps_R ( parent, child, WN_kid(tree, i), root_rid );
05676 
05677     if (WN_map_id(tree) != -1) {
05678       RID *rid = REGION_get_rid ( tree );
05679       IPA_WN_Move_Maps_PU ( parent, child, tree );
05680       if (WN_opcode(tree) == OPC_REGION) {
05681   Is_True(root_rid != NULL, ("Transfer_Maps_R, NULL root RID"));
05682   RID_unlink ( rid );
05683   RID_Add_kid ( rid, root_rid );
05684       } 
05685     }
05686   }
05687 } // Transfer_Maps_R
05688 
05689 
05690 ST_IDX Make_MPRuntime_ST ( MPRUNTIME rop )
05691 {
05692   Is_True(rop >= MPRUNTIME_FIRST && rop <= MPRUNTIME_LAST,
05693           ("Make_MPRuntime_ST: bad rop == %d", (INT) rop));
05694 
05695     // If the global type doesn't exist, create it and its pointer type.
05696   if (mpruntime_ty == TY_IDX_ZERO) {
05697     TY &mpr_ty = New_TY ( mpruntime_ty );
05698     TY_Init(mpr_ty, 0, KIND_FUNCTION, MTYPE_UNKNOWN,
05699             Save_Str(".mpruntime"));
05700     Set_TY_align(mpruntime_ty, 1);
05701 
05702     TYLIST_IDX parm_idx;
05703     TYLIST& parm_list = New_TYLIST(parm_idx);
05704     Set_TY_tylist(mpr_ty, parm_idx);
05705     Set_TYLIST_type(parm_list, Be_Type_Tbl(MTYPE_I4));  // I4 return type
05706       // are there really no parameters? -- DRK
05707     Set_TYLIST_type(New_TYLIST(parm_idx), TY_IDX_ZERO); // end of parm list
05708 
05709     TY_IDX ty_idx;
05710     TY &ty = New_TY ( ty_idx );
05711     TY_Init(ty, Pointer_Size, KIND_POINTER, Pointer_Mtype,
05712       Save_Str ( ".mpruntime_ptr" ));
05713     Set_TY_pointed(ty, mpruntime_ty);
05714 
05715     Set_TY_align(ty_idx, Pointer_Size); // unnecessary? TY_Init does
05716                                         // not set alignment -- DRK
05717   }
05718 
05719   PU_IDX pu_idx;
05720   PU& pu = New_PU(pu_idx);
05721   PU_Init(pu, mpruntime_ty, CURRENT_SYMTAB);
05722 
05723   /*  Create the ST, fill in all appropriate fields and enter into the */
05724   /*  global symbol table.  */
05725 
05726   ST *st = New_ST ( GLOBAL_SYMTAB );
05727   ST_Init(st, Save_Str ( mpr_names[rop] ), CLASS_FUNC, SCLASS_EXTERN,
05728     EXPORT_PREEMPTIBLE, pu_idx);
05729 
05730   Allocate_Object ( st );
05731 
05732   mpr_sts[rop] = ST_st_idx(*st);
05733   return mpr_sts[rop];
05734 }
05735 
05736 
05737 /*  Generate an appropriate load WN based on an ST.  */
05738 
05739 static WN * 
05740 Gen_MP_Load ( ST * st, WN_OFFSET offset, BOOL scalar_only )
05741 {
05742   WN *wn;
05743   TY_IDX ty = ST_type(st);
05744 #ifdef KEY // bug 7259
05745   if (scalar_only && TY_kind(ty) == KIND_STRUCT)
05746     ty = FLD_type(TY_fld(ty));
05747 #endif
05748 #ifdef KEY // bug 10681
05749   if (scalar_only && TY_kind(ty) == KIND_ARRAY)
05750     ty = TY_etype(ty);
05751 #endif
05752 
05753   wn = WN_RLdid ( Promote_Type(TY_mtype(ty)),
05754                   TY_mtype(ty), offset, st, ty );
05755 
05756   return (wn);
05757 }
05758 
05759 
05760 /*  Generate an appropriate store WN based on an ST.  */
05761 
05762 static WN * 
05763 Gen_MP_Store ( ST * st, WN_OFFSET offset, WN * value, BOOL scalar_only)
05764 {
05765   WN *wn;
05766   TY_IDX ty = ST_type(st);
05767 #ifdef KEY // bug 7259
05768   if (scalar_only && TY_kind(ty) == KIND_STRUCT)
05769     ty = FLD_type(TY_fld(ty));
05770 #endif
05771 #ifdef KEY // bug 10681
05772   if (scalar_only && TY_kind(ty) == KIND_ARRAY)
05773     ty = TY_etype(ty);
05774 #endif
05775 
05776   wn = WN_Stid ( TY_mtype(ty), offset, st, ty, value );
05777   WN_linenum(wn) = line_number;
05778 
05779   return (wn);
05780 }
05781 
05782 
05783 /*  Generate appropriate load/store WN's based on two ST's.  */
05784 
05785 static WN * 
05786 Gen_MP_Load_Store ( ST * from_st, WN_OFFSET from_offset,
05787                     ST * to_st,   WN_OFFSET to_offset,
05788                     BOOL is_dynamic )
05789 {
05790   TY_IDX ty;
05791   TY_IDX pty;
05792   WN *wn;
05793   WN *laddr_wn;
05794   WN *saddr_wn;
05795   WN *bytes_wn;
05796   BOOL is_from_ptr;
05797   BOOL is_to_ptr;
05798 
05799   is_from_ptr = (TY_kind(ST_type(from_st)) == KIND_POINTER);
05800   is_to_ptr   = (TY_kind(ST_type(to_st)) == KIND_POINTER);
05801   if (is_from_ptr && is_to_ptr && !is_dynamic)
05802     is_from_ptr = is_to_ptr = FALSE;
05803 
05804   ty = (is_from_ptr) ? TY_pointed(ST_type(from_st)) : ST_type(from_st);
05805 
05806 #ifndef KEY
05807   if ((TY_kind(ty) != KIND_ARRAY) && (TY_kind(ty) != KIND_STRUCT))
05808 #else
05809     if (((TY_kind(ty) != KIND_ARRAY) && (TY_kind(ty) != KIND_STRUCT)) ||
05810   // Bug 6633 - MP lowering of C++ classes with size 0 could trigger
05811   TY_kind(ty) == KIND_STRUCT && TY_size(ty) == 0)
05812 #endif
05813     wn = Gen_MP_Store ( to_st, to_offset,
05814       Gen_MP_Load ( from_st, from_offset ));
05815   else {
05816     if (TY_size(ty) > INT32_MAX)
05817       bytes_wn = WN_Intconst ( MTYPE_I8, TY_size(ty) );
05818     else if (TY_size(ty) > 0)
05819       bytes_wn = WN_Intconst ( MTYPE_I4, TY_size(ty) );
05820     else
05821       bytes_wn = Calculate_Array_Size ( from_st, ty );
05822     if (is_from_ptr)
05823       laddr_wn = WN_RLdid ( Promote_Type(Pointer_type), Pointer_type,
05824           from_offset, from_st, ST_type(from_st) );
05825     else
05826       laddr_wn = WN_Lda ( Pointer_type, from_offset, from_st );
05827     if (is_to_ptr)
05828       saddr_wn = WN_RLdid ( Promote_Type(Pointer_type), Pointer_type,
05829           to_offset, to_st, ST_type(to_st) );
05830     else
05831       saddr_wn = WN_Lda ( Pointer_type, to_offset, to_st );
05832     pty = Make_Pointer_Type ( ty, FALSE );
05833     wn = WN_CreateMstore ( 0, pty,
05834          WN_CreateMload ( 0, pty, laddr_wn,
05835               WN_COPY_Tree (bytes_wn) ),
05836          saddr_wn, bytes_wn );
05837   }
05838 
05839   return (wn);
05840 }
05841 
05842 /*
05843 Generate a barrier call. csc.
05844 Note that, the gtid can't be preg.
05845 */
05846 static WN * 
05847 Gen_Barrier (ST* gtid)
05848 {
05849   WN *wn;
05850 
05851   wn = WN_Create ( OPC_VCALL, 0 );
05852   WN_st_idx(wn) = GET_MPRUNTIME_ST ( MPR_OMP_BARRIER );
05853   WN_Set_Call_Non_Data_Mod ( wn );
05854   WN_Set_Call_Non_Data_Ref ( wn );
05855   WN_Set_Call_Non_Parm_Mod ( wn );
05856   WN_Set_Call_Non_Parm_Ref ( wn );
05857   WN_Set_Call_Parm_Ref ( wn );
05858   WN_linenum(wn) = line_number;
05859   
05860   return (wn);
05861 }
05862 
05863 /*
05864 copyin_wn must be a COPYIN pragma from an OpenMP PARALLEL or
05865 combined worksharing directive.
05866 
05867 Returns TRUE if copyin_wn is an OMP C++ non-POD COPYIN clause, FALSE
05868 otherwise.
05869 */
05870 // CAN BE DELETED. OBSOLETE
05871 
05872 static BOOL
05873 is_omp_non_pod_copyin(WN *copyin_wn)
05874 {
05875   if (WN_opcode(copyin_wn) != OPC_XPRAGMA ||
05876       !WN_pragma_omp(copyin_wn))
05877     return FALSE;
05878 
05879   WN *kid = WN_kid0(copyin_wn);
05880   if (!kid)
05881     return FALSE;
05882 
05883   ST *st = WN_st(kid);
05884   if (!st)
05885     return FALSE;
05886 
05887   return (ST_sym_class(st) == CLASS_FUNC);
05888 }
05889 
05890 #ifdef KEY
05891 extern ST *ST_Source_COMMON_Block(ST *st, ST **split, BOOL want_st);
05892 extern ST *ST_Source_Block(ST *, ST **);
05893 
05894 static ST*
05895 Get_Threadprv_St(WN *prags, ST *copyin_st, ST **copyin_local_st)
05896 {
05897   ST *split_block;
05898   ST *copyin_global_st = NULL;
05899   ST *common_block = ST_Source_Block(copyin_st, &split_block);
05900   if (!ST_is_thread_private(copyin_st) &&
05901      !(split_block && ST_is_thread_private(split_block)) &&
05902      !(common_block && ST_is_thread_private(common_block)))
05903     ErrMsg (EC_MPLOWER_copyin_st, copyin_st);
05904   BOOL match = FALSE;
05905   prags = WN_first(prags);
05906 
05907   while (prags) {
05908     if (WN_opcode(prags) == OPC_PRAGMA &&
05909         WN_pragma(prags) == WN_PRAGMA_THREADPRIVATE &&
05910         WN_st(prags) == common_block) {
05911       *copyin_local_st = ST_ptr(WN_pragma_arg1(prags));
05912       copyin_global_st = ST_ptr(WN_pragma_arg2(prags));
05913       match = TRUE;
05914     }
05915     prags = WN_next(prags);
05916   }
05917   if (!match)
05918     Fail_FmtAssertion ( "bad copyin st (%s) in MP processing",
05919                             ST_st_idx(copyin_st) );
05920   if (copyin_global_st)
05921     common_block = copyin_global_st;
05922   else
05923     Is_True (FALSE, ("Copyin source ST not found in MP processing"));
05924 
05925   return common_block;
05926 }
05927 
05928 // Called from 2 places in be driver, at the end of MP lowering of a PU.
05929 // Generates a library call at the start of a PU to get threadprivate pointer.
05930 // Walks through the PU and replaces remaining occurrences of private
05931 // variables with local copies.
05932 void
05933 Post_MP_Processing (WN * pu)
05934 {
05935   Is_True (WN_operator (pu) == OPR_FUNC_ENTRY,
05936            ("Post_MP_Processing: Function entry node expected"));
05937 
05938   local_nodes = NULL;
05939   local_count = 0;
05940 
05941   WN * prags = WN_func_pragmas (pu);
05942   WN * body = WN_func_body (pu);
05943 
05944   reference_block = WN_CreateBlock ( );
05945   WN *thread_priv_prag = WN_first(prags);
05946   while (thread_priv_prag) {
05947     if (WN_opcode(thread_priv_prag) == OPC_PRAGMA &&
05948         WN_pragma(thread_priv_prag) == WN_PRAGMA_THREADPRIVATE) {
05949       WN_INSERT_BlockLast ( reference_block,
05950       WN_CreatePragma ( WN_PRAGMA_THREADPRIVATE,
05951                                           WN_st_idx(thread_priv_prag),
05952                         WN_pragma_arg1(thread_priv_prag), 
05953                                           WN_pragma_arg2(thread_priv_prag) ));
05954     }
05955     thread_priv_prag = WN_next(thread_priv_prag);
05956   }
05957 
05958   Gen_Threadpriv_Func (prags, body, TRUE);
05959   
05960   // Get the set of local nodes from the function pragmas.
05961   WN * prag_iter, * next_prag_iter = WN_first (prags);
05962   while (prag_iter = next_prag_iter /* really an assignment */)
05963   {
05964     next_prag_iter = WN_next (prag_iter);
05965 
05966     if (WN_operator (prag_iter) == OPR_PRAGMA &&
05967         WN_pragma (prag_iter) == WN_PRAGMA_LOCAL)
05968     {
05969       WN * wn = NULL;
05970       for (wn = local_nodes; wn; wn = WN_next(wn))
05971         if (Identical_Pragmas(prag_iter, wn))
05972           break;
05973       if (wn == NULL)
05974       {
05975         prag_iter = WN_EXTRACT_FromBlock (prags, prag_iter);
05976         WN_next(prag_iter) = local_nodes;
05977         local_nodes = prag_iter;
05978   ++local_count;
05979       } else
05980         WN_DELETE_FromBlock (prags, prag_iter);
05981     }
05982   }
05983 
05984   // Reset global var
05985   parallel_proc = NULL;
05986   // Localize the variables
05987   INT32 vsize = (local_count + 1) * sizeof(VAR_TABLE);
05988   var_table = (VAR_TABLE *) alloca (vsize);
05989   BZERO (var_table, vsize);
05990 
05991   mpt = MPP_ORPHAN;
05992 
05993   Create_Local_Variables (var_table, NULL, NULL, local_nodes, NULL,
05994                           &firstprivate_block, NULL, &alloca_block);
05995   Localize_Parent_Stack lps (FALSE, NULL);
05996   Walk_and_Localize (body, var_table, &lps, FALSE, &non_pod_finalization_nodes);
05997   // Clear vector for this PU
05998   localized_var_vect.clear();
05999 
06000   // Clear local-nodes
06001   WN * next_node;
06002   while (local_nodes) {
06003     next_node = WN_next (local_nodes);
06004     WN_Delete (local_nodes);
06005     local_nodes = next_node;
06006   }
06007 }
06008 #endif
06009 
06010 /*  Generate a copyin call.  */
06011 // TODO: should be replaced when implementing TLS
06012 
06013 static WN * 
06014 Gen_MP_Copyin ( BOOL is_omp )
06015 {
06016   WN *wn;
06017   WN *wnx;
06018   WN *wny;
06019 #ifdef KEY
06020   WN *wnz;
06021 #endif
06022   TY_IDX ty;
06023   INT32 kid;
06024   INT32 size;
06025   BOOL have_pods = FALSE;
06026   BOOL have_nonpods = FALSE;
06027   INT count = 0;
06028   WN *block = WN_CreateBlock();
06029 
06030   // First scan the COPYIN nodes to determine what all we need
06031   // i.e. just PODS, just non-PODS, or both.
06032 
06033   for (wnx = copyin_nodes; wnx; wnx = WN_next(wnx)) {
06034 
06035     if (is_omp && is_omp_non_pod_copyin(wnx)) {
06036       // wnx must be a copyin for a C++ non-POD object.
06037       // We need to create special calls for those, and return them in
06038       // a block node. Process them in the subsequent loop.
06039       have_nonpods = TRUE;
06040     }
06041     else {
06042       // non-PODS require just a single call to mp/omp_copyin.
06043       count++;
06044       have_pods = TRUE;
06045     }
06046   }
06047 
06048   if (have_pods) {
06049 #ifdef KEY
06050     wn = WN_Create ( OPC_VCALL, 3 * count + 1 );
06051     WN_st_idx(wn) = GET_MPRUNTIME_ST(MPR_OMP_COPYIN_THDPRV);
06052 #else
06053     wn = WN_Create ( OPC_VCALL, 2 * count + 1 );
06054     WN_st_idx(wn) = (is_omp ? GET_MPRUNTIME_ST (MPR_OMP_COPYIN) :
06055                      GET_MPRUNTIME_ST ( MPR_COPYIN ));
06056 #endif
06057     WN_Set_Call_Non_Data_Mod ( wn );
06058     WN_Set_Call_Non_Data_Ref ( wn );
06059     WN_Set_Call_Non_Parm_Mod ( wn );
06060     WN_Set_Call_Non_Parm_Ref ( wn );
06061     WN_Set_Call_Parm_Mod ( wn );
06062     WN_Set_Call_Parm_Ref ( wn );
06063     WN_linenum(wn) = line_number;
06064 
06065 #ifdef KEY
06066     // The library expects the first argument (n) to be (# of triplets) * 3
06067     WN_kid0(wn) = WN_CreateParm ( MTYPE_I4,
06068                                   WN_Intconst ( MTYPE_I4, 3 * count ),
06069                                   Be_Type_Tbl(MTYPE_I4), WN_PARM_BY_VALUE );
06070     for (wnx = copyin_nodes, kid = 1; wnx; wnx = WN_next(wnx), kid += 3)
06071 #else
06072     WN_kid0(wn) = WN_CreateParm ( MTYPE_I4,
06073                                   WN_Intconst ( MTYPE_I4, count ),
06074                                   Be_Type_Tbl(MTYPE_I4), WN_PARM_BY_VALUE );
06075     for (wnx = copyin_nodes, kid = 1; wnx; wnx = WN_next(wnx), kid += 2)
06076 #endif
06077     {
06078 
06079       if (is_omp && is_omp_non_pod_copyin(wnx)) {
06080         continue; // skip C++ non-PODs
06081       }
06082 #ifdef KEY
06083       if (WN_opcode(wnx) == OPC_PRAGMA) {
06084         ST *ppthd, *global;
06085         global = Get_Threadprv_St(reference_block, WN_st(wnx), &ppthd);
06086         wny = WN_CreateLdid(OPCODE_make_op(OPR_LDID,
06087                                            Pointer_type, Pointer_type),
06088                             0, ppthd,ST_type(ppthd)); 
06089         // See bugs 12688, 12696 for OpenMP library change in
06090         // __ompc_get_thdprv() that necessitates the following.
06091         wnz = WN_IloadLdid(TY_mtype(ST_type(global)), 0,
06092                            ST_type(global), global, 0);
06093         ty = ST_type(WN_st(wnx));
06094         size = TY_size(ty);
06095       } else
06096         Fail_FmtAssertion ( "bad copyin node (%s) in MP processing",
06097                             OPCODE_name(WN_opcode(WN_kid0(wnx))) );
06098       WN_kid(wn,kid)   = WN_CreateParm ( Pointer_type, wny,
06099                                          Make_Pointer_Type ( ty,
06100                                                              FALSE ),
06101                                          WN_PARM_BY_REFERENCE );
06102       WN_kid(wn,kid+1)   = WN_CreateParm ( Pointer_type, wnz,
06103                                          Make_Pointer_Type ( ty,
06104                                                              FALSE ),
06105                                          WN_PARM_BY_REFERENCE );
06106       WN_kid(wn,kid+2) = WN_CreateParm ( MTYPE_I4,
06107                                          WN_Intconst ( MTYPE_I4, size ),
06108                                          Be_Type_Tbl(MTYPE_I4),
06109                                          WN_PARM_BY_VALUE );
06110 #else
06111       if (WN_opcode(wnx) == OPC_PRAGMA) {
06112         wny = WN_Lda ( Pointer_type, WN_offsetx(wnx), WN_st(wnx) );
06113         ty = ST_type(WN_st(wnx));
06114         size = TY_size(ty);
06115       } else if (WN_operator(WN_kid0(wnx)) == OPR_LDA) {
06116         wny = WN_COPY_Tree ( WN_kid0(wnx) );
06117         ty = ST_type(WN_st(WN_kid0(wnx)));
06118         size = TY_size(ty);
06119       } else if ((WN_operator(WN_kid0(wnx)) == OPR_ARRAY) &&
06120                  (WN_operator(WN_kid0(WN_kid0(wnx))) == OPR_LDA)) {
06121         wny = WN_COPY_Tree ( WN_kid0(wnx) );
06122         ty = TY_AR_etype(ST_type(WN_st(WN_kid0(WN_kid0(wnx))))); 
06123         size = TY_size(ty);
06124       } else
06125         Fail_FmtAssertion ( "bad copyin node (%s) in MP processing",
06126                             OPCODE_name(WN_opcode(WN_kid0(wnx))) );
06127 
06128       WN_kid(wn,kid)   = WN_CreateParm ( Pointer_type, wny,
06129                                          Make_Pointer_Type ( ty,
06130                                                              FALSE ),
06131                                          WN_PARM_BY_REFERENCE );
06132       WN_kid(wn,kid+1) = WN_CreateParm ( MTYPE_I4,
06133                                          WN_Intconst ( MTYPE_I4, size ),
06134                                          Be_Type_Tbl(MTYPE_I4),
06135                                          WN_PARM_BY_VALUE );
06136 #endif
06137     }
06138     WN_INSERT_BlockFirst (block, wn);
06139 #ifdef KEY
06140     // bug 5203: Ensure all threads get the value before giving the master
06141     // thread a chance to proceed/modify the variable.
06142     WN_INSERT_BlockAfter (block, wn, Gen_Barrier (local_gtid));
06143 #endif // KEY
06144   }
06145 
06146   if (have_nonpods) {
06147 
06148     for (wnx = copyin_nodes; wnx; wnx = WN_next(wnx)) {
06149 
06150       if (!(is_omp && is_omp_non_pod_copyin(wnx))) {
06151         continue; // skip PODs
06152       }
06153 
06154       ST* st = WN_st(wnx);
06155       TY_IDX ty = ST_type(st);
06156       
06157       if (TY_kind(ty) != KIND_ARRAY) {
06158 
06159         // scalar non-POD
06160 
06161         wn = WN_Create (OPC_VCALL, 2);
06162         WN_st_idx(wn) = (GET_MPRUNTIME_ST (MPR_OMP_NONPOD_COPYIN));
06163         WN_Set_Call_Non_Data_Mod ( wn );
06164         WN_Set_Call_Non_Data_Ref ( wn );
06165         WN_Set_Call_Non_Parm_Mod ( wn );
06166         WN_Set_Call_Non_Parm_Ref ( wn );
06167         WN_Set_Call_Parm_Mod ( wn );
06168         WN_Set_Call_Parm_Ref ( wn );
06169         WN_linenum(wn) = line_number;
06170       
06171         // pass the address of the object
06172         WN *obj = WN_CreateLda (OPCODE_make_op(OPR_LDA, Pointer_type, MTYPE_V),
06173                                 0,
06174                                 Make_Pointer_Type(ty,FALSE),
06175                                 st);
06176         WN_kid0(wn) = WN_CreateParm (Pointer_type,
06177                                      obj,
06178                                      Make_Pointer_Type(ty, FALSE),
06179                                      WN_PARM_BY_REFERENCE);
06180         // second argument is the address of the assignment operator
06181         FmtAssert (ST_export(WN_st(WN_kid0(wnx))) == EXPORT_PREEMPTIBLE,
06182                    ("COPYIN (%s) requires a pre-emptible assignment operator",
06183                     ST_name(st)));
06184         WN_kid1(wn) = WN_CreateParm(Pointer_type,
06185                                     WN_COPY_Tree(WN_kid0(wnx)),
06186                                     WN_ty(WN_kid0(wnx)),
06187                                     WN_PARM_BY_REFERENCE);
06188       }
06189       else {
06190 
06191         // array non-pod 
06192         // Since these are thread-private, they must be globals,
06193         // therefore they must be fixed size, and cannot be VLAs.
06194 
06195         wn = WN_Create (OPC_VCALL, 4);
06196         WN_st_idx(wn) = (GET_MPRUNTIME_ST (MPR_OMP_NONPOD_ARRAY_COPYIN));
06197         WN_Set_Call_Non_Data_Mod ( wn );
06198         WN_Set_Call_Non_Data_Ref ( wn );
06199         WN_Set_Call_Non_Parm_Mod ( wn );
06200         WN_Set_Call_Non_Parm_Ref ( wn );
06201         WN_Set_Call_Parm_Mod ( wn );
06202         WN_Set_Call_Parm_Ref ( wn );
06203         WN_linenum(wn) = line_number;
06204       
06205         // pass the address of the object
06206         WN *obj = WN_CreateLda (OPCODE_make_op(OPR_LDA, Pointer_type, MTYPE_V),
06207                                 0,
06208                                 Make_Pointer_Type(ty, FALSE),
06209                                 st);
06210         WN_kid(wn,0) = WN_CreateParm (Pointer_type,
06211                                      obj,
06212                                      Make_Pointer_Type(ty, FALSE),
06213                                      WN_PARM_BY_REFERENCE);
06214 
06215         // second argument is the address of the assignment operator
06216   // Is there any particular specification for C++ object tree's
06217   // form? what is assignment operator? == Copy constructor?
06218   // by csc. 2002/9/16
06219         FmtAssert (ST_export(WN_st(WN_kid0(wnx))) == EXPORT_PREEMPTIBLE,
06220                    ("COPYIN (%s) requires a pre-emptible assignment operator",
06221                     ST_name(st)));
06222         WN_kid(wn,1) = WN_CreateParm(Pointer_type,
06223                                      WN_COPY_Tree(WN_kid0(wnx)),
06224                                      WN_ty(WN_kid0(wnx)),
06225                                      WN_PARM_BY_REFERENCE);
06226 
06227         // third argument is the size of each element
06228         INT size;
06229         size = TY_size(TY_AR_etype(ty));
06230         WN_kid(wn,2) = WN_CreateParm(MTYPE_I8,
06231                                      WN_CreateIntconst (OPC_I8INTCONST,size),
06232                                      Be_Type_Tbl(MTYPE_I8),
06233                                      WN_PARM_BY_VALUE);
06234 
06235         // fourth argument is the number of elements
06236         INT64 num_elems = 1;
06237         for (INT i=0; i<TY_AR_ndims(ty); i++) {
06238 
06239           FmtAssert (TY_AR_const_ubnd(ty,i) &&
06240                      TY_AR_const_lbnd(ty,i) &&
06241                      TY_AR_const_stride(ty,i),
06242                      ("COPYIN array (%s) has non-const bounds. Weird!\n",
06243                       ST_name(st)));
06244 
06245           num_elems = num_elems * (TY_AR_ubnd_val(ty,i) -
06246                                    TY_AR_lbnd_val(ty,i) + 1);
06247         }
06248         WN* elems = WN_CreateIntconst(OPC_I8INTCONST,num_elems);
06249         WN_kid(wn,3) = WN_CreateParm(MTYPE_I8,
06250                                      elems,
06251                                      Be_Type_Tbl(MTYPE_I8),
06252                                      WN_PARM_BY_VALUE);
06253       }
06254       
06255       WN_INSERT_BlockLast (block, wn);
06256     }
06257   }
06258 
06259   return (block);
06260 }
06261 
06262 #define MAX_NDIM 7
06263 /***********************************************
06264  * 
06265  *  Helper routine, creates a DO loop and add 
06266  *  the appropriate PROMPF information.
06267  *  adopted for be/vho/f90_lower.cxx, csc.
06268  */
06269 static WN * 
06270 create_doloop_node(WN *index_id, WN *start, WN *end,
06271                    WN *step, WN *body,