1 /*
2  * Copyright (c) 2015-2019, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 /* llmputil.c: OpenMP utility routines for our LLVM compilers */
19 
20 #include "llmputil.h"
21 #include "error.h"
22 #include "symtab.h"
23 #include "dtypeutl.h"
24 #ifndef FE90
25 #include "iliutil.h"
26 #endif
27 
28 /* Global container of uplevel pointers */
29 static struct {
30   LLUplevel *base; /* Pointer to the allocated array of items */
31   int size;        /* Total size including unused items */
32   int avl;         /* Total items in use */
33 } llmp_all_uplevels;
34 
35 /* Global container of task pointers */
36 static struct {
37   LLTask *base; /* Pointer to the allocated array of items */
38   int size;     /* Total size including unused items */
39   int avl;      /* Total items in use */
40 } llmp_all_tasks;
41 
42 static LLUplevel *
get_uplevel(int stblock_sptr)43 get_uplevel(int stblock_sptr)
44 {
45   int key;
46   LLUplevel *up;
47   assert(STYPEG(stblock_sptr) == ST_BLOCK, "Uplevel key must be an ST_BLOCK",
48          stblock_sptr, ERR_Fatal);
49 
50   /* Index */
51   key = PARSYMSG(stblock_sptr);
52 
53   /* Locate uplevel pointer */
54   up = NULL;
55   if (key <= llmp_all_uplevels.avl)
56     up = (LLUplevel *)(&llmp_all_uplevels.base[key]);
57 
58   assert(up && key, "Could not locate uplevel instance for stblock",
59          stblock_sptr, ERR_Fatal);
60 
61   return up;
62 }
63 
64 LLUplevel *
llmp_has_uplevel(int stblock_sptr)65 llmp_has_uplevel(int stblock_sptr)
66 {
67   int key;
68   LLUplevel *up;
69   assert(STYPEG(stblock_sptr) == ST_BLOCK, "Uplevel key must be an ST_BLOCK",
70          stblock_sptr, ERR_Fatal);
71 
72   /* Index */
73   key = PARSYMSG(stblock_sptr);
74 
75   /* Locate uplevel pointer */
76   up = NULL;
77   if (key && key <= llmp_all_uplevels.avl)
78     up = (LLUplevel *)(&llmp_all_uplevels.base[key]);
79 
80   return up;
81 }
82 
83 LLUplevel *
llmp_create_uplevel(int stblock_sptr)84 llmp_create_uplevel(int stblock_sptr)
85 {
86   int key;
87   LLUplevel *up;
88 
89   assert(STYPEG(stblock_sptr) == ST_BLOCK, "Uplevel key must be an ST_BLOCK",
90          stblock_sptr, ERR_Fatal);
91 
92   /* Avoid processing an already created uplevel */
93   if (PARSYMSG(stblock_sptr))
94     return get_uplevel(stblock_sptr);
95 
96   /* Make room if necessary */
97   if (llmp_all_uplevels.avl == 0) {
98     llmp_all_uplevels.avl = 2;
99     key = 1;
100   } else {
101     key = llmp_all_uplevels.avl;
102     ++llmp_all_uplevels.avl;
103   }
104   NEED(llmp_all_uplevels.avl, llmp_all_uplevels.base, LLUplevel,
105        llmp_all_uplevels.size, llmp_all_uplevels.size + 8);
106 
107   up = (LLUplevel *)(&llmp_all_uplevels.base[key]);
108   memset(up, 0, sizeof(LLUplevel));
109 
110   /* Add key and map it to stblock */
111   PARSYMSP(stblock_sptr, key);
112 
113   return up;
114 }
115 
116 LLUplevel *
llmp_get_uplevel(int stblock_sptr)117 llmp_get_uplevel(int stblock_sptr)
118 {
119   return get_uplevel(stblock_sptr);
120 }
121 
122 void
llmp_uplevel_set_dtype(LLUplevel * up,DTYPE dtype)123 llmp_uplevel_set_dtype(LLUplevel *up, DTYPE dtype)
124 {
125   up->dtype = dtype;
126 }
127 
128 void
llmp_uplevel_set_parent(SPTR stblock_sptr,SPTR parent_sptr)129 llmp_uplevel_set_parent(SPTR stblock_sptr, SPTR parent_sptr)
130 {
131   LLUplevel *up = llmp_create_uplevel(stblock_sptr);
132   up->parent = parent_sptr;
133   if (llmp_has_uplevel(parent_sptr) == NULL)
134     up = llmp_create_uplevel(parent_sptr);
135 }
136 
137 /* Uniquely add shared_sptr to up */
138 int
llmp_add_shared_var(LLUplevel * up,int shared_sptr)139 llmp_add_shared_var(LLUplevel *up, int shared_sptr)
140 {
141   int i;
142   const int idx = up->vals_count;
143 
144   /* Unique add: I really wanted to make this a hashset... */
145   for (i = 0; i < up->vals_count; ++i) {
146     if (shared_sptr == 0)
147       break;
148     if (up->vals[i] == shared_sptr)
149       return 0;
150   }
151 
152   ++up->vals_count;
153   NEED(up->vals_count, up->vals, int, up->vals_size, up->vals_size + 8);
154   up->vals[idx] = shared_sptr;
155   return 1;
156 }
157 
158 /* add 0 as placeholder for character len sptr for shared_sptr */
159 void
llmp_add_shared_var_charlen(LLUplevel * up,int shared_sptr)160 llmp_add_shared_var_charlen(LLUplevel *up, int shared_sptr)
161 {
162   int i;
163   const int idx = up->vals_count;
164 
165   /* Unique add: I really wanted to make this a hashset... */
166   for (i = 0; i < up->vals_count; ++i)
167     if (up->vals[i] == shared_sptr) {
168       ++up->vals_count;
169       NEED(up->vals_count, up->vals, int, up->vals_size, up->vals_size + 8);
170       up->vals[idx] = 0;
171     }
172 }
173 
174 /* Return a new key (index) into our table of all uplevels */
175 int
llmp_get_next_key(void)176 llmp_get_next_key(void)
177 {
178   int key;
179   if (llmp_all_uplevels.avl == 0) {
180     llmp_all_uplevels.avl = 2;
181     key = 1;
182   } else {
183     key = llmp_all_uplevels.avl;
184     ++llmp_all_uplevels.avl;
185   }
186   NEED(llmp_all_uplevels.avl, llmp_all_uplevels.base, LLUplevel,
187        llmp_all_uplevels.size, llmp_all_uplevels.size + 8);
188   return key;
189 }
190 
191 /* Return the uplevel for a specific key (index into our table of uplevels) */
192 LLUplevel *
llmp_create_uplevel_bykey(int key)193 llmp_create_uplevel_bykey(int key)
194 {
195   LLUplevel *up;
196 
197   assert(key <= llmp_all_uplevels.avl, "Invalid uplevel key", key, ERR_Fatal);
198 
199   up = (LLUplevel *)(&llmp_all_uplevels.base[key]);
200   memset(up, 0, sizeof(LLUplevel));
201 
202   return up;
203 }
204 
205 void
llmp_reset_uplevel(void)206 llmp_reset_uplevel(void)
207 {
208   int i, j;
209   LLUplevel *up;
210   LLTask *task;
211   if (llmp_all_uplevels.avl) {
212     for (i = 1; i < llmp_all_uplevels.avl; ++i) {
213       up = (LLUplevel *)(&llmp_all_uplevels.base[i]);
214       if (up->vals_count)
215         FREE(up->vals);
216     }
217     FREE(llmp_all_uplevels.base);
218     memset(&llmp_all_uplevels, 0, sizeof(llmp_all_uplevels));
219   }
220   if (llmp_all_tasks.avl) {
221     for (i = 0; llmp_all_tasks.avl; ++i) {
222       task = (LLTask *)(&llmp_all_tasks.base[i]);
223       if (task->privs_count) {
224         FREE(task->privs);
225       }
226       FREE(llmp_all_tasks.base);
227       memset(&llmp_all_tasks, 0, sizeof(llmp_all_tasks));
228     }
229   }
230   llmp_all_uplevels.avl = 0;
231   llmp_all_tasks.avl = 0;
232 }
233 
234 LLUplevel *
llmp_outermost_uplevel(SPTR child)235 llmp_outermost_uplevel(SPTR child)
236 {
237   LLUplevel *up = get_uplevel(child);
238   while (up->parent) {
239     up = llmp_get_uplevel(up->parent);
240   }
241   return up;
242 }
243 
244 LLUplevel *
llmp_parent_uplevel(SPTR child)245 llmp_parent_uplevel(SPTR child)
246 {
247   LLUplevel *up = get_uplevel(child);
248   if (up->parent) {
249     up = llmp_get_uplevel(up->parent);
250   } else {
251     up = NULL;
252   }
253   return up;
254 }
255 
256 SPTR
llmp_get_parent_sptr(SPTR child)257 llmp_get_parent_sptr(SPTR child)
258 {
259   LLUplevel *up = get_uplevel(child);
260   return up->parent;
261 }
262 
263 LLTask *
llmp_get_task(int scope_sptr)264 llmp_get_task(int scope_sptr)
265 {
266   int i;
267   for (i = 0; i < llmp_all_tasks.avl; ++i) {
268     LLTask *task = (LLTask *)&llmp_all_tasks.base[i];
269     if (task->scope_sptr == scope_sptr)
270       return task;
271   }
272   return NULL;
273 }
274 
275 LLTask *
llmp_create_task(int scope_sptr)276 llmp_create_task(int scope_sptr)
277 {
278   int key;
279   LLTask *task;
280 
281   NEED(llmp_all_tasks.avl + 1, llmp_all_tasks.base, LLTask, llmp_all_tasks.size,
282        llmp_all_tasks.size + 4);
283 
284   task = (LLTask *)(&llmp_all_tasks.base[llmp_all_tasks.avl]);
285   ++llmp_all_tasks.avl;
286   memset(task, 0, sizeof(LLTask));
287   task->actual_size = llmp_task_get_base_task_size();
288   task->scope_sptr = scope_sptr;
289   return task;
290 }
291 
292 /* Return the size of an empty KMPC task (no shared variables):
293  * Pointer + Pointer + int32(+pad) +
294  * kmp_cmplrdata_t(data1) + kmp_cmplrdata_t(data2)
295  * see kmp.h
296  */
297 int
llmp_task_get_base_task_size(void)298 llmp_task_get_base_task_size(void)
299 {
300   int pad = sizeof(void *) - sizeof(int);
301 #ifdef TARGET_WIN
302   return sizeof(void *) + sizeof(void *) + sizeof(int) + pad +
303          sizeof(void *) * 2;
304 #else
305   return sizeof(void *) + sizeof(void *) + sizeof(int32_t) + pad +
306          sizeof(void *) * 2;
307 #endif
308 }
309 
310 /* Return the size of a KMPC equivalent task (base + size of privates) */
311 int
llmp_task_get_size(LLTask * task)312 llmp_task_get_size(LLTask *task)
313 {
314   return task->actual_size;
315 }
316 
317 /* Set the fnsptr that belongs to the outlined task */
318 void
llmp_task_set_fnsptr(LLTask * task,int task_sptr)319 llmp_task_set_fnsptr(LLTask *task, int task_sptr)
320 {
321   task->task_sptr = task_sptr;
322 }
323 
324 /* Return the task object associated with 'task_sptr' */
325 LLTask *
llmp_task_get_by_fnsptr(int task_sptr)326 llmp_task_get_by_fnsptr(int task_sptr)
327 {
328   int i;
329   LLTask *task;
330 
331   for (i = 0; i < llmp_all_tasks.avl; ++i) {
332     LLTask *task = (LLTask *)&llmp_all_tasks.base[i];
333     if (task->task_sptr == task_sptr) {
334       return task;
335     }
336   }
337 
338   return NULL;
339 }
340 
341 int
llmp_task_add_private(LLTask * task,int shared_sptr,SPTR private_sptr)342 llmp_task_add_private(LLTask *task, int shared_sptr, SPTR private_sptr)
343 {
344   int pad = 0;
345   int size;
346   int align;
347   int offset = 0;
348   DTYPE dtype;
349   LLFirstPrivate *fp;
350   int idx = task->privs_count;
351 
352   NEED(++task->privs_count, task->privs, LLFirstPrivate, task->privs_size,
353        task->privs_size + 4);
354 
355   /* Create the private object */
356   fp = (LLFirstPrivate *)&(task->privs[idx]);
357   fp->private_sptr = private_sptr;
358   fp->shared_sptr = shared_sptr;
359 
360 /* Bump up the size of the task to contain private_sptr */
361 #ifdef FE90
362   task->actual_size += size_of_var(private_sptr);
363 #else
364   dtype = DTYPEG(private_sptr);
365   if (dtype) {
366     size = zsize_of(dtype);
367     align = alignment(dtype);
368     pad = ALIGN(task->actual_size, align) - task->actual_size;
369     task->actual_size += pad;
370   }
371   offset = task->actual_size;
372   task->actual_size += size_of_sym(private_sptr);
373 #endif
374   return offset;
375 }
376 
377 int
llmp_task_add_loopvar(LLTask * task,int num,DTYPE dtype)378 llmp_task_add_loopvar(LLTask *task, int num, DTYPE dtype)
379 /* put loop variables on task_alloc array after private vars */
380 {
381   int pad = 0;
382   int size;
383   int align;
384   int offset = 0;
385 #ifdef FE90
386   /* we add it to backend only */
387 #else
388   /* Bump up the size of the task to contain loop var and make sure
389    * it is integer*64 aligned.
390    */
391   size = zsize_of(dtype) * num;
392   align = alignment(dtype);
393   pad = ALIGN(task->actual_size, align) - task->actual_size;
394   task->actual_size += pad;
395   offset = task->actual_size;
396   task->actual_size += size;
397 #endif
398   return offset;
399 }
400 
401 void
llmp_task_add(int scope_sptr,int shared_sptr,SPTR private_sptr)402 llmp_task_add(int scope_sptr, int shared_sptr, SPTR private_sptr)
403 {
404   LLTask *task;
405   assert(scope_sptr && STYPEG(scope_sptr) == ST_BLOCK,
406          "Task key must be a scope sptr (ST_BLOCK)", scope_sptr, ERR_Fatal);
407 
408   task = llmp_get_task(scope_sptr);
409   if (!task)
410     task = llmp_create_task(scope_sptr);
411   llmp_task_add_private(task, shared_sptr, private_sptr);
412 }
413 
414 int
llmp_task_get_private(const LLTask * task,int sptr,int encl)415 llmp_task_get_private(const LLTask *task, int sptr, int encl)
416 {
417   int i;
418 
419   for (i = 0; i < task->privs_count; ++i) {
420     const int pr = task->privs[i].private_sptr;
421     if (sptr == pr && TASKG(sptr)
422 #ifndef FE90
423         && is_llvm_local_private(sptr)
424 #endif
425     )
426       return pr;
427   }
428 
429   return 0;
430 }
431 
432 /* should call in taskdup only */
433 INT
llmp_task_get_privoff(int sptr,const LLTask * task)434 llmp_task_get_privoff(int sptr, const LLTask *task)
435 {
436   int i;
437 
438   for (i = 0; i < task->privs_count; ++i) {
439     const int pr = task->privs[i].shared_sptr;
440     if (sptr == pr)
441       return ADDRESSG(task->privs[i].private_sptr);
442   }
443 
444   return 0;
445 }
446 
447 void
llmp_concur_add_shared_var(int stblock_sptr,int shared_sptr)448 llmp_concur_add_shared_var(int stblock_sptr, int shared_sptr)
449 {
450   int dtype;
451   LLUplevel *up;
452 
453   up = llmp_create_uplevel(stblock_sptr);
454   (void)llmp_add_shared_var(up, shared_sptr);
455 }
456 
is_omp_mode_target(OMP_TARGET_MODE mode)457 bool is_omp_mode_target(OMP_TARGET_MODE mode) {
458   switch (mode)
459   {
460     case mode_target:
461     case mode_target_teams:
462     case mode_target_teams_distribute:
463     case mode_target_teams_distribute_simd:
464     case mode_target_teams_distribute_parallel_for:
465     case mode_target_teams_distribute_parallel_for_simd:
466     case mode_target_parallel:
467     case mode_target_parallel_for:
468     case mode_target_parallel_for_simd:
469       return true;
470     default:
471       return false;
472   }
473 }
474