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