OpenADFortTk (including Open64 and OpenAnalysis references)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
dra_clone.cxx
Go to the documentation of this file.
1 /*
2 
3  Copyright (C) 2000, 2001 Silicon Graphics, Inc. All Rights Reserved.
4 
5  This program is free software; you can redistribute it and/or modify it
6  under the terms of version 2 of the GNU General Public License as
7  published by the Free Software Foundation.
8 
9  This program is distributed in the hope that it would be useful, but
10  WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13  Further, this software is distributed without any warranty that it is
14  free of the rightful claim of any third person regarding infringement
15  or the like. Any license provided herein, whether implied or
16  otherwise, applies only to this software file. Patent licenses, if
17  any, provided herein do not apply to combinations of this program with
18  other software, or any other product whatsoever.
19 
20  You should have received a copy of the GNU General Public License along
21  with this program; if not, write the Free Software Foundation, Inc., 59
22  Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 
24  Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pky,
25  Mountain View, CA 94043, or:
26 
27  http://www.sgi.com
28 
29  For further information regarding this notice, see:
30 
31  http://oss.sgi.com/projects/GenInfo/NoticeExplan
32 
33 */
34 
35 
36 // ====================================================================
37 // ====================================================================
38 //
39 //
40 // Revision history:
41 // 16-Jul-96: Original Version
42 //
43 // Description:
44 // Routines used in cloning of subroutines based on
45 // the distribution of reshaped array arguments.
46 //
47 // ====================================================================
48 // ====================================================================
49 
50 #define ONST(x, y) (y)
51 
52 #include <alloca.h> // alloca
53 #include <unistd.h> // write
54 
55 #include "pu_info.h" // PU_Info
56 
57 #include "defs.h" // Standard definitions
58 #include "wn.h" // WN
59 #include "wn_map.h" // Current_Map_Tab
60 #include "wn_util.h" // WN_INSERT_BlockAfter
61 #include "symtab.h"
62 #include "strtab.h" // Save_Str
63 #include "mempool.h" // MEM_POOL
64 #include "cxx_memory.h" // CXX_NEW
65 #include "erbe.h" // EC_*
66 #include "errors.h" // ErrMsg, ErrMsgSrcpos
67 #include "dwarf_DST_mem.h" // DST_IDX
68 #include "clone.h" // IPO_CLONE
69 #include "clone_DST_utils.h" // DST_enter_cloned_subroutine
70 #include "dra_demangle.h" // DRA_Demangle
71 
72 #include "dra_internal.h" // Internal DRA interface
73 
74 
75 
76 // =====================================================================
77 //
78 // Local function prototypes
79 //
80 // =====================================================================
81 
82 static BOOL DRA_Clone_Initialize(void);
83 
84 static BOOL DRA_Process_Requests(char *tir_names);
85 
86 static BOOL DRA_Parse_Clone_Name(char *clone_name);
87 
88 static void DRA_Clone_Instantiate(PU_Info *orig_pu,
89  BOOL pu_has_feedback,
90  STRING_LIST *tir_list,
91  DRA_HASH_TABLE *dra_table);
92 
93 static char* DRA_New_Clone_Sig(WN *pu_wn,
94  char *clone_name,
95  DRA_HASH_TABLE *dra_table);
96 
97 static void DRA_Add_Clone (PU_Info *orig_pu,
99  STR_IDX clone_name,
100  char *arg_sig,
101  BOOL pu_has_feedback);
102 
103 static void DRA_Insert_Pragmas(WN *pu_wn,
104  char *arg_sig);
105 
106 static void DRA_Process_Commons(DRA_HASH_TABLE *dra_table,
108 
109 static void DRA_Collect_Commons(WN *pu,
110  DRA_COMMON_HASH_TABLE *dra_common_ht);
111 
112 static void DRA_Process_Globals(DRA_HASH_TABLE *dra_table);
113 
115  char *arg_sig);
116 
117 // =====================================================================
118 //
119 // Exported variables
120 //
121 // =====================================================================
122 
124 
126 
128 
130 
132 
134 
135 // =====================================================================
136 //
137 // File static variables
138 //
139 // =====================================================================
140 
142 
144 
146 
147 
148 // =====================================================================
149 //
150 // Exported function definitions
151 //
152 // =====================================================================
153 
154 
155 // =====================================================================
156 //
157 // Function Name: Get_Orig_Type
158 //
159 // Description: Given an ST return the ST_type it originally had.
160 // Same as ST_type, except when called on reshaped globals
161 // whose type has been mangled.
162 //
163 // =====================================================================
164 
166 
167  TY_IDX ty;
168 
169  if (ST_class(st) != CLASS_VAR) return ST_type(st);
170 
171  if (ONST(ST_is_global(st),ST_level(st) == GLOBAL_SYMTAB) &&
172  ST_is_reshaped(st)) {
173 
174  DRA_GLOBAL_INFO* dgi = dra_global->Find(st);
175 
176  if (dgi) {
177  // has been seen before
178  ty = dgi->Get_TY();
179  }
180  else {
181  // seeing it for the first time
182  ty = ST_type(st);
184  dra_global->Enter (st, dgi);
185  }
186  }
187  else {
188  ty = ST_type(st);
189  }
190  return ty;
191 }
192 
193 // =====================================================================
194 //
195 // Function Name: Get_Array_Type
196 //
197 // Description: Given the ST for a distributed array, return the array TY.
198 //
199 // =====================================================================
200 
201 extern TY_IDX Get_Array_Type (ST* st) {
202 
203  TY_IDX ty;
204 
205  ty = Get_Original_Type (st);
206 
207  if (TY_kind(ty) == KIND_POINTER &&
208  (ST_sclass(st) == SCLASS_FORMAL ||
209  ST_sclass(st) == SCLASS_AUTO ||
210  (ONST(ST_sclass(st)==SCLASS_BASED, ST_base_idx(st)==ST_st_idx(st)) &&
211  ST_sclass(ST_base(st)) == SCLASS_AUTO))) {
212  ty = TY_pointed(ty);
213  }
214 
215  return ty;
216 }
217 
218 
219 extern "C" void
221 {
223 
226  }
227 
228  if (Run_Dsm_Common_Check) {
229  MEM_POOL_Initialize (&DRA_check_pool, "DRA Common Check", TRUE);
230  DRA_check_pool_ptr = &DRA_check_pool;
232  }
233 
234  if (Run_Dsm_Check) {
236  }
237 
238  // information about globals must survive PUs
239  dra_global = CXX_NEW (DRA_GLOBAL_HASH_TABLE(20, Malloc_Mem_Pool),
241 }
242 
243 
244 
245 
246 // =====================================================================
247 //
248 // Function Name: DRA_Finalize
249 //
250 // Description: Pop and Delete DRA_clone_pool if necessary
251 //
252 // =====================================================================
253 
254 extern "C" void
256 {
257  ST *st;
258 
259  // delete info about distributed globals
260  //
261  {
262  HASH_TABLE_ITER<ST*, DRA_GLOBAL_INFO*> iter (dra_global);
263  ST* st;
264  DRA_GLOBAL_INFO* dgi;
265  while (iter.Step (&st, &dgi)) {
267  }
268  CXX_DELETE (dra_global, Malloc_Mem_Pool);
269  dra_global = NULL;
270  }
271 
272  // Make the symbols that are not used invisible
273  //
274  INT i;
275  FOREACH_SYMBOL (GLOBAL_SYMTAB, st, i) {
276  if (ST_is_not_used(st) &&
277  ST_class(st) == CLASS_FUNC &&
278  ST_sclass(st) == SCLASS_EXTERN &&
282  }
283  }
284 
285  // Emit type 'N' symbols for all cloned functions
286  // that are referenced in the same file
287  //
288  if (DRA_func_table != NULL) {
289 
290  NAME_ST_TABLE_ITER iter(DRA_func_table);
291  STR_IDX func_name;
292  MANGLED_FUNC *func_desc;
293 
294  while (iter.Step(&func_name, &func_desc)) {
295 
296  if (func_desc->is_clone && func_desc->is_called) {
297  ST* aux_st = New_ST (GLOBAL_SYMTAB);
298  ST_Init (aux_st,
299  func_name,
300  CLASS_NAME,
302  EXPORT_LOCAL,
303  (TY_IDX) NULL);
304  Set_ST_is_not_used(aux_st);
305  Set_ST_emit_symbol(aux_st);
306  }
307  }
308  }
309 
310  if (DRA_clone_pool_ptr != NULL) {
311  MEM_POOL_Pop (DRA_clone_pool_ptr);
312  MEM_POOL_Delete (DRA_clone_pool_ptr);
313  DRA_clone_pool_ptr = NULL;
314  }
315 
316  if (DRA_check_pool_ptr != NULL) {
317  MEM_POOL_Delete (DRA_check_pool_ptr);
318  DRA_check_pool_ptr = NULL;
319  }
320 
321  DRA_Close_File();
322 }
323 
324 
325 
326 
327 // =====================================================================
328 //
329 // Function Name: DRA_Processing
330 //
331 // Description: Main driver for DRA related tasks - reading pragmas,
332 // cloning, name mangling, and common block processing
333 //
334 // =====================================================================
335 
336 extern "C" void
338  WN* pu,
339  BOOL pu_has_feedback)
340 {
341  STRING_LIST *clone_requests = NULL;
342  DRA_HASH_TABLE *dra_table = NULL;
343 
344  Set_Error_Phase("DRA Processing");
345 
346  if (Run_Dsm_Cloner) {
347  clone_requests = DRA_clone_table->Find(ST_name_idx(WN_st(pu)));
348  }
349 
350  if (clone_requests != NULL || // we need to clone
351  Run_Dsm_Common_Check || // we need to process commons
352  ONST(SYMTAB_mp_needs_lno(Current_Symtab), // we need to mangle names
354 
355  // Initialize and push DRA_name_pool to be used for DRA_HASH_TABLE
356  //
357  DRA_name_pool_ptr = &DRA_name_pool;
358  MEM_POOL_Initialize (DRA_name_pool_ptr, "DRA Names", FALSE);
359  MEM_POOL_Push (DRA_name_pool_ptr);
360 
361  // Create dra_table that stores the info about all DRA's
362  //
363  dra_table = CXX_NEW(DRA_HASH_TABLE(31, DRA_name_pool_ptr),
364  DRA_name_pool_ptr);
365 
366  DRA_Read_Pragmas(pu, dra_table);
367  }
368 
369  if (clone_requests != NULL) {
370  DRA_Clone_Instantiate(pu_info, pu_has_feedback, clone_requests, dra_table);
371  }
372 
373  if (Run_Dsm_Common_Check) {
374  MEM_POOL_Push (DRA_check_pool_ptr);
376  *dra_common_ht = CXX_NEW (DRA_COMMON_HASH_TABLE(20, DRA_check_pool_ptr),
377  DRA_check_pool_ptr);
378 
379  DRA_Collect_Commons(pu, dra_common_ht);
380  DRA_Process_Commons(dra_table, dra_common_ht);
381 
382  CXX_DELETE (dra_common_ht, DRA_check_pool_ptr);
383  MEM_POOL_Pop (DRA_check_pool_ptr);
384 
385  // Also write out information about globals (C, C++) into rii_file
386  //
387  DRA_Process_Globals(dra_table);
388  }
389 
390  if (dra_table->Num_Entries() > 0) {
391  DRA_Mangle_All(pu, dra_table, pu_info);
393  }
394  else {
397  }
398 
399  if (Run_Dsm_Check) {
401 
402  if (ONST(SYMTAB_has_altentry(Current_Symtab),
404  // Walk the tree and process alternate entry points
405  //
406  WN_ITER *wni;
407  for (wni = WN_WALK_TreeIter(pu); wni; wni = WN_WALK_TreeNext(wni)) {
408  if (WN_opcode(WN_ITER_wn(wni)) == OPC_ALTENTRY) {
410  }
411  }
412  }
413  }
414 
415  // Pop and Delete DRA_name_pool
416  //
417  if (DRA_name_pool_ptr != NULL) {
418  MEM_POOL_Pop (DRA_name_pool_ptr);
419  MEM_POOL_Delete (DRA_name_pool_ptr);
420  DRA_name_pool_ptr = NULL;
421  }
422 }
423 
424 
425 
426 
427 // =====================================================================
428 //
429 // Local function definitions
430 //
431 // =====================================================================
432 
433 
434 // =====================================================================
435 //
436 // Function Name: DRA_Clone_Initialize
437 //
438 // Description: Process .rii file and return TRUE if Template
439 // Instatiation Requests (TIR's) have been found.
440 //
441 // =====================================================================
442 
443 static BOOL
445 {
446  // Initialize DRA_clone_pool to be used for cloning
447  // This MEM_POOL lives throughout the compilation of the file
448  //
449  MEM_POOL_Initialize (&DRA_clone_pool, "DRA Cloning", TRUE);
450  DRA_clone_pool_ptr = &DRA_clone_pool;
451  MEM_POOL_Push (DRA_clone_pool_ptr);
452 
453  // From now on use DRA_file_mmap as a normal memory pointer
454  //
455  char *tir_names = strstr(DRA_file_mmap, DRA_FILE_SEPARATOR)
456  + strlen(DRA_FILE_SEPARATOR);
457 
458  // Allocate the TIR name table
459  // Use DRA_clone_pool because the table must live across all PU's
460  //
461  DRA_clone_table = CXX_NEW(STRING_LIST_TABLE(31, DRA_clone_pool_ptr),
462  DRA_clone_pool_ptr);
463 
464  // and store all TIR names in it
465  //
466  BOOL needs_cloning = DRA_Process_Requests(tir_names);
467 
468  // Allocate the global name/ST hash table used for resolving names
469  //
470  if (DRA_func_table == NULL) {
471  DRA_func_table = CXX_NEW(NAME_ST_TABLE(31, &MEM_src_pool),
472  &MEM_src_pool);
473  }
474 
476 
477  return needs_cloning;
478 }
479 
480 
481 
482 
483 // =====================================================================
484 //
485 // Function Name: DRA_Process_Requests
486 //
487 // Description: Read the TIR names from .rii file and store them
488 // into a hash table. Keys are the original names of
489 // functions, while the entries represent linked lists
490 // of the names that need to be instantiated.
491 //
492 // =====================================================================
493 
494 static BOOL
495 DRA_Process_Requests(char *tir_name)
496 {
497  BOOL needs_cloning = FALSE;
498 
499  // Replace "----" with the string terminator '\0'
500  //
501  char *end_tir_names = strstr(tir_name, DRA_FILE_SEPARATOR);
502  if (end_tir_names != NULL) {
503  *end_tir_names = '\0';
504  }
505 
506 
507  char *end_of_line;
508  for ( ; *tir_name; *end_of_line = '\n', tir_name = end_of_line+1) {
509 
510  // find the of the line
511  //
512  if ((end_of_line = strchr(tir_name, '\n')) == NULL) {
513  break;
514  }
515 
516  // replace eol with the string terminator
517  //
518  *end_of_line = '\0';
519 
520  // Parse tir_name for correctness
521  //
522  if (!DRA_Parse_Clone_Name(tir_name)) {
523  (void) unlink(DRA_file_name);
525  return FALSE;
526  }
527 
528  char *orig_name = tir_name + DRA_MANGLE_SIG_LEN;
529  char *postfix_sig = strstr(orig_name, DRA_MANGLE_SIG);
530 
531  STR_IDX save_tir_name = Save_Str(tir_name);
532 
533  *postfix_sig = '\0';
534 
535  STR_IDX save_orig_name = Save_Str(orig_name);
536 
537  // restore original contents of overwritten location
538  //
539  *postfix_sig = DRA_MANGLE_SIG[0];
540 
541 
542  // Get the list of TIR's corresponding to the original function
543  //
544  STRING_LIST *tir_list = DRA_clone_table->Find(save_orig_name);
545 
546  // If it has been created, do it now
547  //
548  if (tir_list == NULL) {
549  tir_list = CXX_NEW(STRING_LIST(), DRA_clone_pool_ptr);
550  DRA_clone_table->Enter(save_orig_name, tir_list);
551  }
552 
553  // Add the tir name to the list
554  //
555  STRING_NODE *tir_node =
556  CXX_NEW(STRING_NODE(save_tir_name), DRA_clone_pool_ptr);
557  tir_list->Append(tir_node);
558 
559  needs_cloning = TRUE;
560  }
561 
562 
563  // restore original contents of overwritten locations
564  //
565  if (end_tir_names != NULL) {
566  *end_tir_names = DRA_FILE_SEPARATOR[0];
567  }
568 
569  return needs_cloning;
570 }
571 
572 
573 
574 
575 // =====================================================================
576 //
577 // Function Name: DRA_Parse_Clone_Name
578 //
579 // Description: Parse the name read from .rii file to make sure
580 // it can be used to generate meaningful pragmas,
581 //
582 // =====================================================================
583 
584 static BOOL
585 DRA_Parse_Clone_Name(char *clone_name)
586 {
587  // Check for DRA mangling prefix
588  //
589  if (strncmp(clone_name, DRA_MANGLE_SIG, DRA_MANGLE_SIG_LEN) != 0)
590  return FALSE;
591 
592  char *arg_sig = strstr(clone_name + DRA_MANGLE_SIG_LEN, DRA_MANGLE_SIG);
593 
594  // Check for DRA mangling suffix
595  //
596  if (arg_sig == NULL || *(arg_sig += DRA_MANGLE_SIG_LEN) == 0)
597  return FALSE;
598 
599 
600  // Check the parameter list
601  //
602  for ( ; *arg_sig; ) {
603 
604  char *current;
605 
606  // Check number of dimensions:
607  // INT16; non-negative; if 0, it must be followed by _
608  //
609  INT64 num_dims = (INT64) strtol(arg_sig, &current, 10);
610 
611  if (current == arg_sig)
612  return FALSE;
613 
614  if (num_dims == 0) {
615  if (*current++ != DRA_ARG_SEPARATOR)
616  return FALSE;
617  else {
618  arg_sig = current;
619  continue;
620  }
621  }
622 
623  if (num_dims < 0 || num_dims > INT16_MAX)
624  return FALSE;
625 
626  // Check array element size:
627  // INT64; positive; must be surrounded by D and E
628  //
629  if (*current++ != DRA_NDIMS_END)
630  return FALSE;
631 
632  arg_sig = current;
633 
634  INT64 esize = (INT64) strtol(arg_sig, &current, 10);
635 
636  if (current == arg_sig || esize <= 0 || *current++ != DRA_ESIZE_END)
637  return FALSE;
638 
639  arg_sig = current;
640 
641  // Check distributions in all dimensions:
642  // B, C, or S; C may be followed by a positive INT64
643  //
644  for (INT16 dim = 0; dim < num_dims; dim++) {
645 
646  if (*arg_sig == DRA_BLOCK_CODE || *arg_sig == DRA_STAR_CODE) {
647  arg_sig++;
648  continue;
649  }
650 
651  else if (*arg_sig == DRA_CYCLIC_CODE) {
652 
653  if (arg_sig[1] == DRA_BLOCK_CODE ||
654  arg_sig[1] == DRA_STAR_CODE ||
655  arg_sig[1] == DRA_CYCLIC_CODE ||
656  (arg_sig[1] == DRA_ARG_SEPARATOR && dim == num_dims-1)) {
657  arg_sig++;
658  continue;
659  }
660 
661  arg_sig++;
662 
663  INT64 chunk = (INT64) strtol(arg_sig, &current, 10);
664 
665  if (current == arg_sig || chunk <= 0)
666  return FALSE;
667 
668  arg_sig = current;
669  }
670 
671  else
672  return FALSE;
673  }
674 
675  if (*arg_sig++ != DRA_ARG_SEPARATOR)
676  return FALSE;
677  }
678 
679  return TRUE;
680 }
681 
682 
683 
684 
685 // =====================================================================
686 //
687 // Function Name: DRA_Clone_Instantiate
688 //
689 // Description: Instantiate all the clones found in the TIR table
690 // that correspond to the passed PU.
691 //
692 // =====================================================================
693 
694 static void
696  BOOL pu_has_feedback,
697  STRING_LIST *tir_list,
698  DRA_HASH_TABLE *dra_table)
699 {
700  // The cloner cannot handle routines with alternate entry points
701  //
702  if (ONST(SYMTAB_has_altentry(Current_Symtab),
705  WN_Get_Linenum(PU_Info_tree_ptr(orig_pu)));
706  return;
707  }
708 
709  // Iterate over the string list
710  //
711  STRING_ITER tir_iter(tir_list);
712  STRING_NODE *n;
713 
714  for (n = tir_iter.First(); !tir_iter.Is_Empty(); n = tir_iter.Next()) {
715 
716  STR_IDX clone_name = n->String();
717 
718  // Get clone argument signature that ignores formal parameters
719  // that already have DISTRIBUTE_RESHAPE specification.
720  //
721  char *arg_sig = DRA_New_Clone_Sig(PU_Info_tree_ptr(orig_pu),
722  Index_To_Str(clone_name),
723  dra_table);
724 
725  // NULL signature is used to flag inconsistent cloning requests
726  //
727  if (arg_sig != NULL) {
728  DRA_Add_Clone(orig_pu,
729  DRA_clone_pool_ptr,
730  clone_name,
731  arg_sig,
732  pu_has_feedback);
733  }
734  }
735 }
736 
737 
738 
739 
740 // =====================================================================
741 //
742 // Function Name: DRA_New_Clone_Sig
743 //
744 // Description: Given a PU and an instantiation request, return the
745 // clone argument signature that ignores formal parameters
746 // that already have DISTRIBUTE_RESHAPE directive. In case
747 // of errors, return NULL.
748 //
749 // =====================================================================
750 
751 static char*
753  char *clone_name,
754  DRA_HASH_TABLE *dra_table)
755 {
756  Set_Error_Phase("Instantiating DRA Clones");
757 
758  FmtAssert(strncmp(clone_name, DRA_MANGLE_SIG, DRA_MANGLE_SIG_LEN) == 0,
759  ("The name of a DRA clone does not have DRA_MANGLE_SIG prefix"));
760 
761  char *arg_sig = strstr(clone_name + DRA_MANGLE_SIG_LEN, DRA_MANGLE_SIG);
762 
763  FmtAssert(arg_sig != NULL,
764  ("The name of a DRA clone does not have DRA_MANGLE_SIG postfix"));
765 
766  arg_sig += DRA_MANGLE_SIG_LEN;
767 
768  char *buf = CXX_NEW_ARRAY(char, strlen(arg_sig)+1, DRA_name_pool_ptr);
769  char *bufptr = buf;
770 
771  char *dim_sig;
772 
773 
774  INT16 arg_pos;
775  for ( arg_pos = 0; *arg_sig; arg_sig++, arg_pos++ ) {
776 
777  ST *arg_st = WN_st(WN_kid(pu_wn, arg_pos));
778 
779  if (arg_st == NULL) {
780  // This warning should be deleted once the testing is finished
781  //
783  WN_Get_Linenum(pu_wn),
784  DRA_Demangle(clone_name, DRA_DIMS_COLUMNWISE),
785  "cannot be satisfied -- too many arguments passed or types mismatch");
786  // Do not clone in the presence of errors!
787  //
788  return NULL;
789  }
790 
791  // Extract the number of dimensions
792  //
793  TY_IDX arg_ty = Get_Array_Type(arg_st);
794  DRA_INFO *dra = dra_table->Find(arg_st);
795  INT16 num_dims = (INT16) strtol (arg_sig, &dim_sig, 10);
796 
797  // Do some consistency checking
798  //
799  if (num_dims == 0) {
800  if (dra != NULL) {
801  // This warning should be deleted once the testing is finished
802  //
804  WN_Get_Linenum(pu_wn),
805  DRA_Demangle(clone_name, DRA_DIMS_COLUMNWISE),
806  "cannot be satisfied -- non-reshaped argument passed to reshaped formal parameter");
807  // Do not clone in the presence of errors!
808  //
809  return NULL;
810  }
811  else {
812  arg_sig = strchr(arg_sig, DRA_ARG_SEPARATOR);
813  *bufptr++ = '0';
814  *bufptr++ = DRA_ARG_SEPARATOR;
815  continue;
816  }
817  }
818 
819  // From now on num_dims must be > 0
820  //
821 
822  if (TY_kind(arg_ty) != KIND_ARRAY) {
823  // This warning should be deleted once the testing is finished
824  //
826  WN_Get_Linenum(pu_wn),
827  DRA_Demangle(clone_name, DRA_DIMS_COLUMNWISE),
828  "cannot be satisfied -- reshaped argument passed to a non-array formal parameter");
829  // Do not clone in the presence of errors!
830  //
831  return NULL;
832  }
833 
834  if (num_dims != TY_AR_ndims(arg_ty) ||
835  (dra != NULL && num_dims != dra->Num_Dims())) {
836  // This warning should be deleted once the testing is finished
837  //
839  WN_Get_Linenum(pu_wn),
840  DRA_Demangle(clone_name, DRA_DIMS_COLUMNWISE),
841  "cannot be satisfied -- reshaped argument and matching formal parameter have different ranks");
842  // Do not clone in the presence of errors!
843  //
844  return NULL;
845  }
846 
847 
848  INT64 elem_size = (INT64) strtol(dim_sig+1, &dim_sig, 10);
849 
850  if (elem_size != TY_size(TY_AR_etype(arg_ty)) ||
851  (dra != NULL && elem_size != dra->Element_Size())) {
852  // This warning should be deleted once the testing is finished
853  //
855  WN_Get_Linenum(pu_wn),
856  DRA_Demangle(clone_name, DRA_DIMS_COLUMNWISE),
857  "cannot be satisfied -- reshaped argument and matching formal parameter have different element sizes");
858  // Do not clone in the presence of errors!
859  //
860  return NULL;
861  }
862 
863 
864  if (dra != NULL) {
865  // dim_sig points to 'D'; skip it to process element size first
866  //
867  if (!DRA_Info_Matches_Encoding(dra, dim_sig+1)) {
868  // This warning should be deleted once the testing is finished
869  //
871  WN_Get_Linenum(pu_wn),
872  DRA_Demangle(clone_name, DRA_DIMS_COLUMNWISE),
873  "cannot be satisfied -- reshaping distributions of arguments and formal parameters do not match");
874  // Do not clone in the presence of errors!
875  //
876  return NULL;
877  }
878  else {
879  // Ignore this DRA because it's already specified
880  //
881  arg_sig = strchr(arg_sig, DRA_ARG_SEPARATOR);
882  *bufptr++ = '0';
883  *bufptr++ = DRA_ARG_SEPARATOR;
884  continue;
885  }
886  }
887 
888  // dra is NULL, and we need to insert pragma for this parameter
889 
890  // Copy ndims (digits before 'D')
891  //
892  while (*arg_sig != DRA_NDIMS_END) {
893  *bufptr++ = *arg_sig++;
894  }
895 
896  // Skip D<esize>E
897  //
898  arg_sig++;
899  while (*arg_sig++ != DRA_ESIZE_END);
900 
901  // Copy distribution encodings
902  //
903  while (*arg_sig != DRA_ARG_SEPARATOR) {
904  *bufptr++ = *arg_sig++;
905  }
906  *bufptr++ = DRA_ARG_SEPARATOR;
907  }
908 
909  // Do not clone if no new pragmas are needed
910  //
911  if (bufptr == buf) {
912  return NULL;
913  }
914 
915  *bufptr = '\0';
916 
917 
918  // If the number of actual arguments is less than the number of
919  // formal parameters, we still clone but also warn the user
920  //
921  if (arg_pos < WN_num_formals(pu_wn)) {
923  WN_Get_Linenum(pu_wn),
924  DRA_Demangle(clone_name, DRA_DIMS_COLUMNWISE),
925  "has incomplete argument list");
926  }
927 
928  return buf;
929 }
930 
931 
932 
933 
934 // =====================================================================
935 //
936 // Function Name: DRA_Add_Clone
937 //
938 // Description: Clone the PU whose PU_Info structure is passed in
939 // and add it to the PU list.
940 //
941 // The assumption is that WT_SYMTAB, WT_TREE, and
942 // WT_PROC_SYM sections of the orig_pu are in state
943 // Subsect_InMem.
944 //
945 // Returned PU_Info structure is allocated in the
946 // Malloc_Mem_Pool.
947 //
948 // Local objects that disappear after the cloning
949 // is finished are allocated from MEM_local_pool.
950 //
951 // Everything else (tree, map tables, symtabs (?),
952 // DSTs) is allocated from the mem_pool that is
953 // passed in, and the client has control over its
954 // life-time.
955 //
956 // =====================================================================
957 
958 static void
961  STR_IDX clone_name,
962  char *arg_sig,
963  BOOL pu_has_feedback)
964 {
965  // Save current pointers to standard memory pools and scope table
966  //
967  MEM_POOL *save_pu_pool_ptr = MEM_pu_pool_ptr;
968  MEM_POOL *save_wn_pool_ptr = WN_mem_pool_ptr;
969 
970  // Save local symbol table of the original PU, since
971  // cloning will overwrite its Scope_tab entry
972  //
973  Set_PU_Info_symtab_ptr(orig_pu, NULL);
975 
976  // Use the given mem_pool for WN, ST, etc.
977  //
978  MEM_pu_pool_ptr = mem_pool;
979  WN_mem_pool_ptr = mem_pool;
980 
981  // Define a new IPO_CLONE object
982  //
983  IPO_CLONE clone(PU_Info_tree_ptr(orig_pu),
984  Scope_tab,
986  PU_Info_maptab(orig_pu),
987  mem_pool,
988  mem_pool);
989 
990  ST* orig_st = ST_ptr(PU_Info_proc_sym(orig_pu));
991 
992  // Lookup the clone name in the table of mangled names
993  //
994  MANGLED_FUNC *clone_desc = DRA_func_table->Find(clone_name);
995 
996  // If not found, the new ST entry should be created
997  //
998  if (clone_desc == NULL) {
999  clone_desc = CXX_NEW(MANGLED_FUNC, &MEM_src_pool);
1000 
1001  // Create a PU
1002  PU_IDX pu_idx;
1003  PU& pu = New_PU (pu_idx);
1004  Pu_Table[pu_idx] = Pu_Table[ST_pu(orig_st)];
1005 
1006  // Make an ST: add function to global symbol table
1007  clone_desc->st = New_ST (ST_level(orig_st));
1008  ST_Init (clone_desc->st,
1009  clone_name,
1010  CLASS_FUNC,
1011  SCLASS_TEXT,
1012  ST_export(orig_st),
1013  pu_idx);
1014 
1015  clone_desc->is_called = FALSE;
1016  DRA_func_table->Enter(clone_name, clone_desc);
1017  }
1018 
1019  clone_desc->is_clone = TRUE;
1020  Set_ST_sclass (clone_desc->st, SCLASS_TEXT);
1021  if (Run_cg) {
1022  Set_ST_base (clone_desc->st, ST_base(orig_st));
1023  }
1024 
1025  // This performs actual cloning
1026  //
1027  clone.New_Clone(clone_desc->st);
1028 
1029  // Set frequencies to be the same as in the original PU
1030  //
1031  if (pu_has_feedback) {
1032  DevWarn("Need to fix up feedback in DRA_Add_Clone\n");
1033  }
1034 #if TODO
1035  FEEDBACK cloned_fb(clone.Get_Cloned_PU(), mem_pool);
1036  FB_IPA_Clone(Cur_PU_Feedback, clone_node()->Feedback,
1037  WN_func_body(Callee_Wn ()), clone.Get_Cloned_PU(),
1038  1.0f);
1039 #endif
1040 
1041  // Set the current scope entry to point to the clone
1042  //
1045  Scope_tab[CURRENT_SYMTAB].st = clone_desc->st;
1046 
1047  // Insert DISTRIBUTE_RESHAPE pragmas based on the argument signature
1048  //
1049  DRA_Insert_Pragmas(clone.Get_Cloned_PU(), arg_sig);
1050 
1051  // Generate DST information for the clone
1052  //
1054  DST_IDX new_pu_dst =
1056  PU_Info_pu_dst(orig_pu),
1057  clone.Get_Func_ST(),
1058  Current_DST,
1059  clone.Get_sym());
1060 
1061  // Alocate and initialize PU_Info structure for the clone
1062  //
1063  PU_Info *new_pu = CXX_NEW(PU_Info, Malloc_Mem_Pool);
1064  PU_Info_init(new_pu);
1065 
1066  // Add new pu right after the original pu
1067  //
1068  PU_Info_next(new_pu) = PU_Info_next(orig_pu);
1069  PU_Info_next(orig_pu) = new_pu;
1070 
1071  // Update the PU pointers and state information
1072  //
1075  Set_PU_Info_pu_dst(new_pu, new_pu_dst);
1076 
1077  Set_PU_Info_tree_ptr(new_pu, clone.Get_Cloned_PU());
1078  PU_Info_proc_sym(new_pu) = ST_st_idx(clone.Get_Func_ST());
1079  PU_Info_maptab(new_pu) = clone.Get_Cloned_maptab();
1080 
1084 #if 0
1086  Set_PU_Info_depgraph_ptr(new_pu, NULL);
1087 #endif
1088 
1089  if (pu_has_feedback) {
1091  }
1092 
1093  // Mark that clone requires LNO processing
1094  //
1095  Set_PU_mp_needs_lno(PU_Info_pu(new_pu));
1096 
1097  // Restore Curent_Map_Tab and Current_Symtab to those of the original PU
1098  //
1099  Current_Map_Tab = PU_Info_maptab(orig_pu);
1100 
1101  // Restore pointers to standard memory pools
1102  //
1103  MEM_pu_pool_ptr = save_pu_pool_ptr;
1104  WN_mem_pool_ptr = save_wn_pool_ptr;
1105 
1106  // Save local symbol table of the clone
1107  //
1108  Set_PU_Info_symtab_ptr(new_pu, NULL);
1110 
1111  // Restore local symbol table of the original PU
1112  //
1113  Restore_Local_Symtab(orig_pu);
1114 }
1115 
1116 
1117 
1118 // =====================================================================
1119 //
1120 // Function Name: Find_Insertion_Point
1121 //
1122 // Description: Find the place in the PU where we should start
1123 // inserting distribute_reshape pragmas. Ordinarily
1124 // it would be after the preamble, but in C/C++
1125 // there are assignments to __vla_bound variables
1126 // that can occur after the PREAMBLE. In which case the
1127 // insertion point must be after the STIDs to those variables.
1128 //
1129 // =====================================================================
1130 
1131 static WN*
1133  char *arg_sig)
1134 {
1135  WN *preamble_wn = Get_Preamble_End(pu_wn);
1136 
1137  if (ONST (SYMTAB_src_lang(Current_Symtab) != SYMTAB_C_LANG &&
1138  SYMTAB_src_lang(Current_Symtab) != SYMTAB_CXX_LANG,
1141  return preamble_wn;
1142  }
1143 
1144  WN *current_wn = preamble_wn;
1145 
1146  for (INT16 arg_pos = 0; *arg_sig; arg_sig++, arg_pos++ ) {
1147 
1148  // Extract the number of dimensions
1149  //
1150  INT16 num_dims = (INT16) strtol (arg_sig, &arg_sig, 10);
1151  ST *arg_st = WN_st(WN_kid(pu_wn, arg_pos));
1152  TY_IDX arg_ty = Get_Array_Type(arg_st);
1153 
1154  for (INT16 dim = 0; dim < num_dims; dim++) {
1155 
1156  if (*arg_sig++ == DRA_CYCLIC_CODE) {
1157  INT64 chunk = (INT64) strtol (arg_sig, &arg_sig, 10);
1158  }
1159  // For each dimension see if the bound is __vla_bound
1160  //
1161  if (!TY_AR_const_ubnd(arg_ty, num_dims-1-dim) &&
1162  TY_AR_ubnd_val(arg_ty, num_dims-1-dim) &&
1163  strcmp(ST_name(TY_AR_ubnd_var(arg_ty, num_dims-1-dim)),
1164  "__vla_bound") == 0) {
1165 
1166  ST* vlabound_st = ONST(WN_st(TY_AR_ubnd_tree(arg_ty, dim)),
1167  &(St_Table[TY_AR_ubnd_var(arg_ty, num_dims-1-dim)]));
1168 
1169  // simple LDID for upper bound of __vla_bound
1170  // Find the STID in the tree
1171  BOOL saw_preamble = FALSE;
1172  BOOL saw_current = FALSE;
1173  WN *wn = WN_first(WN_func_body(pu_wn));
1174 
1175  while (wn) {
1176 
1177  if (WN_operator(wn) == OPR_PRAGMA &&
1179  saw_preamble = TRUE;
1180  }
1181  if (wn == current_wn) saw_current = TRUE;
1182 
1183  if (WN_operator(wn) == OPR_STID &&
1184  WN_st(wn) == vlabound_st) {
1185 
1186  if (saw_preamble && saw_current) {
1187  // we must move current_wn
1188  //
1189  current_wn = wn;
1190 
1191  // see if we're followed by an XPRAGMA-COPYIN
1192  if (WN_next(wn) &&
1193  WN_operator(WN_next(wn)) == OPR_XPRAGMA &&
1195  WN_st(WN_kid0(WN_next(wn))) == vlabound_st) {
1196 
1197  current_wn = WN_next(wn);
1198  }
1199  }
1200  else {
1201  // don't need to do anything
1202  }
1203  break;
1204  }
1205  wn = WN_next(wn);
1206  }
1207 
1208  FmtAssert (wn,
1209  ("Find_Insertion_Point: No STID vla_bound for %s\n",
1210  ST_name(arg_st)));
1211  }
1212  }
1213  }
1214  return current_wn;
1215 }
1216 
1217 
1218 // =====================================================================
1219 //
1220 // Function Name: DRA_Insert_Pragmas
1221 //
1222 // Description: Insert DISTRIBUTE_RESHAPE pragmas into the passed tree
1223 // based on the argument signature given by arg_sig.
1224 //
1225 // =====================================================================
1226 
1227 static void
1229  char *arg_sig)
1230 {
1231  // strtol (char *str, char *ptr, INT base) returns as a long integer
1232  // the value represented by the character string pointed to by str.
1233  // The string is scanned up to the first character inconsistent with
1234  // the base. If the value of ptr is not (char **)NULL, a pointer to
1235  // the character terminating the scan is returned in the location
1236  // pointed to by ptr. If no integer can be formed, that location is
1237  // set to str, and zero is returned.
1238 
1239  WN *block = WN_func_body(pu_wn);
1240  // WN *current = Get_Preamble_End(pu_wn);
1241  WN *current = Find_Insertion_Point(pu_wn, arg_sig);
1242 
1243  for (INT16 arg_pos = 0; *arg_sig; arg_sig++, arg_pos++ ) {
1244 
1245  // Extract the number of dimensions
1246  //
1247  INT16 num_dims = (INT16) strtol (arg_sig, &arg_sig, 10);
1248  ST *arg_st = WN_st(WN_kid(pu_wn, arg_pos));
1249  TY_IDX arg_ty = Get_Array_Type(arg_st);
1250 
1251  for (INT16 dim = 0; dim < num_dims; dim++) {
1252 
1253  // For each dimension create a pragma node
1254  //
1255  WN *pwn = WN_CreatePragma(WN_PRAGMA_DISTRIBUTE_RESHAPE, arg_st, 0, 0);
1256  WN_pragma_index(pwn) = dim;
1257 
1259  WN_INSERT_BlockAfter(block, current, pwn); // Need to fix this
1260  current = pwn;
1261 
1262  switch (*arg_sig++) {
1263 
1264  case DRA_BLOCK_CODE:
1266  break;
1267 
1268  case DRA_STAR_CODE:
1270  break;
1271 
1272  case DRA_CYCLIC_CODE:
1273  {
1274  INT64 chunk = (INT64) strtol (arg_sig, &arg_sig, 10);
1275  if (chunk != 0) {
1277  WN_pragma_arg2(pwn) = chunk;
1278  }
1279  else {
1280  // For CYCLIC_EXPR create an additional XPRAGMA node
1281  //
1284  arg_st, 1);
1285  WN_kid(xpwn, 0) = WN_Intconst(MTYPE_I8, 0);
1286 
1288  WN_INSERT_BlockAfter(block, current, xpwn);
1289  current = xpwn;
1290  }
1291  }
1292  break;
1293 
1294  default:
1295  FmtAssert(FALSE,
1296  ("Unrecognized distribution in the mangled name"));
1297  }
1298 
1299  // Finally, create an XPRAGMA node for array size
1300  //
1301  WN *xpwn = WN_CreateXpragma(WN_PRAGMA_DISTRIBUTE_RESHAPE, arg_st, 1);
1302 
1303  INT16 st_dim = dim;
1304 
1305  WN *lb;
1306  if (TY_AR_const_lbnd(arg_ty, st_dim)) {
1307  lb = WN_Intconst(MTYPE_I8, TY_AR_lbnd_val(arg_ty, st_dim));
1308  }
1309  else {
1310  ST_IDX lb_st = TY_AR_lbnd_var(arg_ty, st_dim);
1311  TY_IDX lb_ty = ST_type(lb_st);
1313  TY_mtype(lb_ty),
1314  TY_mtype(lb_ty)),
1315  0,
1316  lb_st,
1317  lb_ty);
1318  }
1319 
1320  WN *ub;
1321  if (TY_AR_const_ubnd(arg_ty, st_dim)) {
1322  ub = WN_Intconst(MTYPE_I8, TY_AR_ubnd_val(arg_ty, st_dim));
1323  }
1324  else {
1325  ST_IDX ub_st = TY_AR_ubnd_var(arg_ty, st_dim);
1326  TY_IDX ub_ty = ST_type(ub_st);
1328  TY_mtype(ub_ty),
1329  TY_mtype(ub_ty)),
1330  0,
1331  ub_st,
1332  ub_ty);
1333  }
1334 
1335  WN_kid(xpwn, 0) = WN_Add(MTYPE_I8,
1336  WN_Sub(MTYPE_I8, ub, lb),
1337  WN_Intconst(MTYPE_I8, 1));
1338 
1340  WN_INSERT_BlockAfter(block, current, xpwn);
1341  current = xpwn;
1342  }
1343  }
1344 }
1345 
1346 
1347 
1348 // =====================================================================
1349 //
1350 // Function Name: DRA_Collect_Commons
1351 //
1352 // Description: Given a WHIRL tree and a hash-table, (recursively) collect all
1353 // the base COMMON STs referenced in the tree into the hash-table.
1354 //
1355 // =====================================================================
1356 
1357 static void
1359 {
1360  if (wn == NULL) return;
1361 
1362  OPCODE opc = WN_opcode(wn);
1363 
1364  ST *st = OPCODE_has_sym(opc) ? WN_st(wn) : NULL;
1365 
1366  if (st &&
1367  (ST_base(st) != st) &&
1368  (ST_sclass(st) == SCLASS_COMMON || ST_sclass(st) == SCLASS_DGLOBAL) &&
1369  (ST_class(ST_base(st)) == CLASS_VAR &&
1370  TY_kind(ST_type(ST_base(st))) == KIND_STRUCT)) {
1371  // smells like a common
1372  dra_common_ht->Enter_If_Unique (ST_st_idx(ST_base(st)), TRUE);
1373  }
1374 
1375  // recurse
1376  //
1377  if (opc == OPC_BLOCK) {
1378  WN *kid = WN_first(wn);
1379  while (kid) {
1380  DRA_Collect_Commons (kid, dra_common_ht);
1381  kid = WN_next(kid);
1382  }
1383  }
1384  else {
1385  for (INT i=0; i<WN_kid_count(wn); i++) {
1386  DRA_Collect_Commons (WN_kid(wn,i), dra_common_ht);
1387  }
1388  }
1389 }
1390 
1391 
1392 // =====================================================================
1393 //
1394 // Function Name: DRA_Process_Commons
1395 //
1396 // Description: Write the information related to distribute-reshaped
1397 // arrays appearing in common blocks into .rii file that
1398 // will be consumed by the prelinker in order to do
1399 // consistency checks.
1400 //
1401 // =====================================================================
1402 
1403 static void
1405  DRA_COMMON_HASH_TABLE *dra_common_ht)
1406 {
1407  BOOL seen_common = FALSE;
1408  BOOL new_common = FALSE;
1409  UINT bufsize = 1024;
1410  char *buf = (char *) alloca(bufsize);
1411  char *bufptr = buf;
1412  char *common_name = NULL;
1413  INT64 common_offset;
1414  INT64 non_dra_start = 0;
1415  INT64 non_dra_end = 0;
1416  ST *st;
1417  INT i;
1418 
1419  /* COMMON blocks are now in global symtab */
1420  FOREACH_SYMBOL (GLOBAL_SYMTAB, st, i) {
1421 
1422  // Common blocks and their fields are listed consecutively in ST
1423  //
1424  ST_SCLASS st_sclass = ST_sclass(st);
1425 
1426  if (st_sclass == SCLASS_COMMON &&
1427  ST_st_idx(st) == ST_base_idx(st) &&
1428  dra_common_ht->Find(ST_st_idx(st))) {
1429 
1430  // COMMON and not based, so must be the base of the COMMON block
1431 
1432  char *st_name = ST_name(st);
1433 
1434  // Names of split commons: BaseName.BaseOffset (Try to find '.')
1435  //
1436  char *dot = strchr(st_name, '.');
1437 
1438  // Full common name
1439  //
1440  if (dot == NULL) {
1441  if (common_name == NULL ||
1442  strcmp(st_name, common_name) != 0) {
1443  common_name = strcpy((char *) alloca(strlen(st_name)+1),
1444  st_name);
1445  new_common = TRUE;
1446  }
1447  common_offset = 0;
1448  }
1449 
1450  // Split common name
1451  //
1452  else {
1453  if (common_name == NULL ||
1454  strncmp(st_name, common_name, dot-st_name) != 0) {
1455  common_name = strncpy((char *) alloca(dot-st_name+1),
1456  st_name, dot-st_name);
1457  common_name[dot-st_name] = '\0';
1458  new_common = TRUE;
1459  }
1460  common_offset = strtol(dot+1, NULL, 10);
1461  }
1462 
1463  if (new_common) {
1464 
1465  // Write the last chunk of the previous common (if it existed)
1466  //
1467  if (non_dra_end - non_dra_start > 0) {
1468  bufptr += sprintf(bufptr, " %lld\n", non_dra_end - non_dra_start);
1469  }
1470  else if (seen_common) {
1471  *bufptr++ = '\n';
1472  }
1473 
1474  // Write the name of the new common
1475  //
1476  INT name_len = strlen(common_name);
1477 
1478  if (bufptr - buf + name_len + 21 >= bufsize) {
1479  bufsize *= 2;
1480  char *newbuf = (char *) alloca(bufsize);
1481  buf = strcpy(newbuf, buf);
1482  bufptr = buf + strlen(buf);
1483  }
1484 
1485  (void) strcpy(bufptr, common_name);
1486  bufptr += name_len;
1487 
1488  non_dra_end = non_dra_start = 0;
1489  new_common = FALSE;
1490  }
1491 
1492  seen_common = TRUE;
1493  }
1494 
1495  else if (ST_st_idx(st) != ST_base_idx(st) &&
1496  ST_sclass(ST_base(st)) == SCLASS_COMMON &&
1497  dra_common_ht->Find(ST_st_idx(ST_base(st)))) {
1498 
1499  TY_IDX ty = ST_type(st);
1500 
1501  DRA_INFO *dra = (dra_table ? dra_table->Find(st) : NULL);
1502 
1503  if (dra != NULL) { // reshaped array
1504 
1505  INT16 ndims = TY_AR_ndims(ty);
1506 
1507  // Reallocate if necessary (double the buffer size)
1508  // We need space to write this reshaped array and
1509  // possibly a non-reshaped chunk size that follows it
1510  // 31 chars prefix: DRA_ndims(5)_esize(21)
1511  // 69 chars per dimension: _lb(22):ub(22):distr(1)chunk(21)
1512  // 21 chars for the next non-reshaped chunk
1513  //
1514  if (bufptr - buf + 31 + ndims*69 + 21 >= bufsize) {
1515  bufsize *= 2;
1516  char *newbuf = (char *) alloca(bufsize);
1517  buf = strcpy(newbuf, buf);
1518  bufptr = buf + strlen(buf);
1519  }
1520 
1521  if (non_dra_end - non_dra_start > 0) {
1522  bufptr += sprintf(bufptr, " %lld", non_dra_end - non_dra_start);
1523  }
1524  non_dra_start = common_offset + ST_ofst(st) + TY_size(ty);
1525  non_dra_end = non_dra_start;
1526 
1527  bufptr +=
1528  sprintf(bufptr, " DRA_%lld_%d", TY_size(TY_AR_etype(ty)), ndims);
1529 
1530  for (INT16 dim = 0; dim < ndims; ++dim) {
1531 
1532  bufptr += sprintf(bufptr,
1533  "_%lld:%lld:",
1534  TY_AR_lbnd_val(ty, ndims-1-dim),
1535  TY_AR_ubnd_val(ty, ndims-1-dim));
1536 
1537  switch (dra->Distr_Type(dim)) {
1538  case DISTRIBUTE_STAR:
1539  *bufptr++ = DRA_STAR_CODE;
1540  break;
1541  case DISTRIBUTE_BLOCK:
1542  *bufptr++ = DRA_BLOCK_CODE;
1543  break;
1545  *bufptr++ = DRA_CYCLIC_CODE;
1546  bufptr += sprintf(bufptr, "%lld", dra->Chunk_Const_Val(dim));
1547  break;
1549  *bufptr++ = DRA_CYCLIC_CODE;
1550  break;
1551  }
1552  }
1553  }
1554 
1555  else if (common_offset + ST_ofst(st) + TY_size(ty) > non_dra_end) {
1556  non_dra_end = common_offset + ST_ofst(st) + TY_size(ty);
1557  }
1558  }
1559  }
1560 
1561  if (bufptr != buf) {
1562  if (non_dra_end - non_dra_start > 0) {
1563  bufptr += sprintf(bufptr, " %lld\n", non_dra_end - non_dra_start);
1564  }
1565  else {
1566  *bufptr++ = '\n';
1567  }
1568  write(DRA_file_desc, (void*)buf, bufptr-buf);
1569  }
1570 }
1571 
1572 
1573 
1574 // =====================================================================
1575 //
1576 // Function Name: DRA_Process_Globals
1577 //
1578 // Description: Write the information related to distribute-reshaped
1579 // global arrays into .rii file that
1580 // will be consumed by the prelinker in order to do
1581 // consistency checks.
1582 //
1583 // =====================================================================
1584 
1585 static void
1587 {
1588  UINT bufsize = 1024;
1589  char *buf = (char *) alloca(bufsize);
1590  char *bufptr = buf;
1591  ST *st;
1592  INT i;
1593 
1594  {
1595  // process globals just once per file, not once per PU
1596  static BOOL done_globals = FALSE;
1597  if (done_globals) return;
1598  done_globals = TRUE;
1599  }
1600 
1601  FOREACH_SYMBOL (GLOBAL_SYMTAB, st, i) {
1602 
1603  if (ST_class(st) != CLASS_VAR) continue;
1604 
1605  // skip commons.
1606  //
1607  if ((ST_sclass(st) == SCLASS_COMMON) || // common
1608  (ST_sclass(st) == SCLASS_DGLOBAL && // might be common
1609  // if this st or
1610  // the base is kind struct
1611  (TY_kind(ST_type(st)) == KIND_STRUCT ||
1612  (ST_class(ST_base(st)) == CLASS_VAR &&
1613  TY_kind(ST_type(ST_base(st))) == KIND_STRUCT)))) {
1614  continue;
1615  }
1616 
1617  bufptr = buf;
1618 
1619  // is it a global array? if so, write it out
1620  //
1621  TY_IDX ty = Get_Original_Type(st);
1622  if (ty && TY_kind(ty) == KIND_ARRAY) {
1623 
1624  char* st_name = ST_name(st);
1625  INT name_len = strlen(st_name);
1626 
1627  if (bufptr - buf + name_len + 21 >= bufsize) {
1628  bufsize *= 2;
1629  char *newbuf = (char *) alloca(bufsize);
1630  buf = strcpy(newbuf, buf);
1631  bufptr = buf + strlen(buf);
1632  }
1633 
1634  strcpy (bufptr, st_name);
1635  bufptr += name_len;
1636 
1637  DRA_INFO* dra = (dra_table ? dra_table->Find(st) : NULL);
1638 
1639  if (dra != NULL) {
1640  // reshaped
1641  //
1642 
1643  INT16 ndims = TY_AR_ndims(ty);
1644 
1645  // Reallocate if necessary (double the buffer size)
1646  // We need space to write this reshaped array
1647  // 31 chars prefix: DRA_ndims(5)_esize(21)
1648  // 69 chars per dimension: _lb(22):ub(22):distr(1)chunk(21)
1649  //
1650  if (bufptr - buf + 31 + ndims*69 >= bufsize) {
1651  bufsize *= 2;
1652  char *newbuf = (char *) alloca(bufsize);
1653  buf = strcpy(newbuf, buf);
1654  bufptr = buf + strlen(buf);
1655  }
1656 
1657  bufptr +=
1658  sprintf(bufptr, " DRA_%lld_%d", TY_size(TY_AR_etype(ty)), ndims);
1659 
1660  // emit dimensions consistently: i.e. stride-one dimension first
1661  //
1662  for (INT16 dim = 0; dim < ndims; ++dim) {
1663 
1664  bufptr += sprintf(bufptr,
1665  "_%lld:%lld:",
1666  TY_AR_lbnd_val(ty, ndims-1-dim),
1667  TY_AR_ubnd_val(ty, ndims-1-dim));
1668 
1669  switch (dra->Distr_Type(dim)) {
1670  case DISTRIBUTE_STAR:
1671  *bufptr++ = DRA_STAR_CODE;
1672  break;
1673  case DISTRIBUTE_BLOCK:
1674  *bufptr++ = DRA_BLOCK_CODE;
1675  break;
1677  *bufptr++ = DRA_CYCLIC_CODE;
1678  bufptr += sprintf(bufptr, "%lld", dra->Chunk_Const_Val(dim));
1679  break;
1681  *bufptr++ = DRA_CYCLIC_CODE;
1682  break;
1683  }
1684  }
1685  *bufptr++ = '\n';
1686  }
1687  else {
1688  // not reshaped
1689  //
1690  bufptr += sprintf (bufptr, " %lld", TY_size(ty));
1691  *bufptr++ = '\n';
1692  }
1693  write(DRA_file_desc, (void*)buf, bufptr-buf);
1694  }
1695  }
1696 }
1697 
1698 
1699 
1700 // =====================================================================
1701 //
1702 // Function Name: DRA_Info_Matches_Encoding
1703 //
1704 // Description: Check if the DISTRIBUTE_RESHAPE information from
1705 // DRA_INFO matches that of the encoded argument.
1706 //
1707 // =====================================================================
1708 
1709 static BOOL
1711  char *arg_sig)
1712 {
1713  INT16 num_dims = dra->Num_Dims();
1714  for (INT16 dim = 0; dim < num_dims; dim++) {
1715 
1716  switch (*arg_sig++) {
1717 
1718  case DRA_BLOCK_CODE:
1719  if (dra->Distr_Type(dim) != DISTRIBUTE_BLOCK) {
1720  return FALSE;
1721  }
1722  break;
1723 
1724  case DRA_STAR_CODE:
1725  if (dra->Distr_Type(dim) != DISTRIBUTE_STAR) {
1726  return FALSE;
1727  }
1728  break;
1729 
1730  case DRA_CYCLIC_CODE:
1731  {
1732  INT64 chunk = (INT64) strtol (arg_sig, &arg_sig, 10);
1733  if (chunk != 0) {
1734  if (dra->Distr_Type(dim) != DISTRIBUTE_CYCLIC_CONST ||
1735  dra->Chunk_Const_Val(dim) != chunk) {
1736  return FALSE;
1737  }
1738  }
1739  else {
1740  if (dra->Distr_Type(dim) != DISTRIBUTE_CYCLIC_EXPR) {
1741  return FALSE;
1742  }
1743  }
1744  }
1745  break;
1746 
1747  default:
1748  FmtAssert(FALSE,
1749  ("Uncrecognized distribution in the mangled name"));
1750  }
1751  }
1752  return TRUE;
1753 }