1 /* Copyright (C) 2013-2016 Free Software Foundation, Inc.
3 Contributed by Mentor Embedded.
5 This file is part of the GNU Offloading and Multi Processing Library
8 Libgomp is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. */
27 /* This file handles OpenACC constructs. */
31 #include "libgomp_g.h"
32 #include "gomp-constants.h"
34 #ifdef HAVE_INTTYPES_H
35 # include <inttypes.h> /* For PRIu64. */
42 find_pset (int pos
, size_t mapnum
, unsigned short *kinds
)
44 if (pos
+ 1 >= mapnum
)
47 unsigned char kind
= kinds
[pos
+1] & 0xff;
49 return kind
== GOMP_MAP_TO_PSET
;
52 static void goacc_wait (int async
, int num_waits
, va_list *ap
);
55 /* Launch a possibly offloaded function on DEVICE. FN is the host fn
56 address. MAPNUM, HOSTADDRS, SIZES & KINDS describe the memory
57 blocks to be copied to/from the device. Varadic arguments are
58 keyed optional parameters terminated with a zero. */
61 GOACC_parallel_keyed (int device
, void (*fn
) (void *),
62 size_t mapnum
, void **hostaddrs
, size_t *sizes
,
63 unsigned short *kinds
, ...)
65 bool host_fallback
= device
== GOMP_DEVICE_HOST_FALLBACK
;
67 struct goacc_thread
*thr
;
68 struct gomp_device_descr
*acc_dev
;
69 struct target_mem_desc
*tgt
;
72 struct splay_tree_key_s k
;
73 splay_tree_key tgt_fn_key
;
75 int async
= GOMP_ASYNC_SYNC
;
76 unsigned dims
[GOMP_DIM_MAX
];
79 #ifdef HAVE_INTTYPES_H
80 gomp_debug (0, "%s: mapnum=%"PRIu64
", hostaddrs=%p, size=%p, kinds=%p\n",
81 __FUNCTION__
, (uint64_t) mapnum
, hostaddrs
, sizes
, kinds
);
83 gomp_debug (0, "%s: mapnum=%lu, hostaddrs=%p, sizes=%p, kinds=%p\n",
84 __FUNCTION__
, (unsigned long) mapnum
, hostaddrs
, sizes
, kinds
);
86 goacc_lazy_initialize ();
88 thr
= goacc_thread ();
91 /* Host fallback if "if" clause is false or if the current device is set to
95 goacc_save_and_set_bind (acc_device_host
);
97 goacc_restore_bind ();
100 else if (acc_device_type (acc_dev
->type
) == acc_device_host
)
106 /* Default: let the runtime choose. */
107 for (i
= 0; i
!= GOMP_DIM_MAX
; i
++)
110 va_start (ap
, kinds
);
111 /* TODO: This will need amending when device_type is implemented. */
112 while ((tag
= va_arg (ap
, unsigned)) != 0)
114 if (GOMP_LAUNCH_DEVICE (tag
))
115 gomp_fatal ("device_type '%d' offload parameters, libgomp is too old",
116 GOMP_LAUNCH_DEVICE (tag
));
118 switch (GOMP_LAUNCH_CODE (tag
))
120 case GOMP_LAUNCH_DIM
:
122 unsigned mask
= GOMP_LAUNCH_OP (tag
);
124 for (i
= 0; i
!= GOMP_DIM_MAX
; i
++)
125 if (mask
& GOMP_DIM_MASK (i
))
126 dims
[i
] = va_arg (ap
, unsigned);
130 case GOMP_LAUNCH_ASYNC
:
132 /* Small constant values are encoded in the operand. */
133 async
= GOMP_LAUNCH_OP (tag
);
135 if (async
== GOMP_LAUNCH_OP_MAX
)
136 async
= va_arg (ap
, unsigned);
140 case GOMP_LAUNCH_WAIT
:
142 unsigned num_waits
= GOMP_LAUNCH_OP (tag
);
145 goacc_wait (async
, num_waits
, &ap
);
150 gomp_fatal ("unrecognized offload code '%d',"
151 " libgomp is too old", GOMP_LAUNCH_CODE (tag
));
156 acc_dev
->openacc
.async_set_async_func (async
);
158 if (!(acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_NATIVE_EXEC
))
160 k
.host_start
= (uintptr_t) fn
;
161 k
.host_end
= k
.host_start
+ 1;
162 gomp_mutex_lock (&acc_dev
->lock
);
163 tgt_fn_key
= splay_tree_lookup (&acc_dev
->mem_map
, &k
);
164 gomp_mutex_unlock (&acc_dev
->lock
);
166 if (tgt_fn_key
== NULL
)
167 gomp_fatal ("target function wasn't mapped");
169 tgt_fn
= (void (*)) tgt_fn_key
->tgt_offset
;
172 tgt_fn
= (void (*)) fn
;
174 tgt
= gomp_map_vars (acc_dev
, mapnum
, hostaddrs
, NULL
, sizes
, kinds
, true,
175 GOMP_MAP_VARS_OPENACC
);
177 devaddrs
= gomp_alloca (sizeof (void *) * mapnum
);
178 for (i
= 0; i
< mapnum
; i
++)
179 devaddrs
[i
] = (void *) (tgt
->list
[i
].key
->tgt
->tgt_start
180 + tgt
->list
[i
].key
->tgt_offset
);
182 acc_dev
->openacc
.exec_func (tgt_fn
, mapnum
, hostaddrs
, devaddrs
,
185 /* If running synchronously, unmap immediately. */
186 if (async
< acc_async_noval
)
187 gomp_unmap_vars (tgt
, true);
189 tgt
->device_descr
->openacc
.register_async_cleanup_func (tgt
, async
);
191 acc_dev
->openacc
.async_set_async_func (acc_async_sync
);
194 /* Legacy entry point, only provide host execution. */
197 GOACC_parallel (int device
, void (*fn
) (void *),
198 size_t mapnum
, void **hostaddrs
, size_t *sizes
,
199 unsigned short *kinds
,
200 int num_gangs
, int num_workers
, int vector_length
,
201 int async
, int num_waits
, ...)
203 goacc_save_and_set_bind (acc_device_host
);
205 goacc_restore_bind ();
209 GOACC_data_start (int device
, size_t mapnum
,
210 void **hostaddrs
, size_t *sizes
, unsigned short *kinds
)
212 bool host_fallback
= device
== GOMP_DEVICE_HOST_FALLBACK
;
213 struct target_mem_desc
*tgt
;
215 #ifdef HAVE_INTTYPES_H
216 gomp_debug (0, "%s: mapnum=%"PRIu64
", hostaddrs=%p, size=%p, kinds=%p\n",
217 __FUNCTION__
, (uint64_t) mapnum
, hostaddrs
, sizes
, kinds
);
219 gomp_debug (0, "%s: mapnum=%lu, hostaddrs=%p, sizes=%p, kinds=%p\n",
220 __FUNCTION__
, (unsigned long) mapnum
, hostaddrs
, sizes
, kinds
);
223 goacc_lazy_initialize ();
225 struct goacc_thread
*thr
= goacc_thread ();
226 struct gomp_device_descr
*acc_dev
= thr
->dev
;
228 /* Host fallback or 'do nothing'. */
229 if ((acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
232 tgt
= gomp_map_vars (NULL
, 0, NULL
, NULL
, NULL
, NULL
, true,
233 GOMP_MAP_VARS_OPENACC
);
234 tgt
->prev
= thr
->mapped_data
;
235 thr
->mapped_data
= tgt
;
240 gomp_debug (0, " %s: prepare mappings\n", __FUNCTION__
);
241 tgt
= gomp_map_vars (acc_dev
, mapnum
, hostaddrs
, NULL
, sizes
, kinds
, true,
242 GOMP_MAP_VARS_OPENACC
);
243 gomp_debug (0, " %s: mappings prepared\n", __FUNCTION__
);
244 tgt
->prev
= thr
->mapped_data
;
245 thr
->mapped_data
= tgt
;
249 GOACC_data_end (void)
251 struct goacc_thread
*thr
= goacc_thread ();
252 struct target_mem_desc
*tgt
= thr
->mapped_data
;
254 gomp_debug (0, " %s: restore mappings\n", __FUNCTION__
);
255 thr
->mapped_data
= tgt
->prev
;
256 gomp_unmap_vars (tgt
, true);
257 gomp_debug (0, " %s: mappings restored\n", __FUNCTION__
);
261 GOACC_enter_exit_data (int device
, size_t mapnum
,
262 void **hostaddrs
, size_t *sizes
, unsigned short *kinds
,
263 int async
, int num_waits
, ...)
265 struct goacc_thread
*thr
;
266 struct gomp_device_descr
*acc_dev
;
267 bool host_fallback
= device
== GOMP_DEVICE_HOST_FALLBACK
;
268 bool data_enter
= false;
271 goacc_lazy_initialize ();
273 thr
= goacc_thread ();
276 if ((acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
284 va_start (ap
, num_waits
);
285 goacc_wait (async
, num_waits
, &ap
);
289 acc_dev
->openacc
.async_set_async_func (async
);
291 /* Determine if this is an "acc enter data". */
292 for (i
= 0; i
< mapnum
; ++i
)
294 unsigned char kind
= kinds
[i
] & 0xff;
296 if (kind
== GOMP_MAP_POINTER
|| kind
== GOMP_MAP_TO_PSET
)
299 if (kind
== GOMP_MAP_FORCE_ALLOC
300 || kind
== GOMP_MAP_FORCE_PRESENT
301 || kind
== GOMP_MAP_FORCE_TO
)
307 if (kind
== GOMP_MAP_DELETE
308 || kind
== GOMP_MAP_FORCE_FROM
)
311 gomp_fatal (">>>> GOACC_enter_exit_data UNHANDLED kind 0x%.2x",
317 for (i
= 0; i
< mapnum
; i
++)
319 unsigned char kind
= kinds
[i
] & 0xff;
321 /* Scan for PSETs. */
322 int psets
= find_pset (i
, mapnum
, kinds
);
328 case GOMP_MAP_POINTER
:
329 gomp_acc_insert_pointer (1, &hostaddrs
[i
], &sizes
[i
],
332 case GOMP_MAP_FORCE_ALLOC
:
333 acc_create (hostaddrs
[i
], sizes
[i
]);
335 case GOMP_MAP_FORCE_PRESENT
:
336 acc_present_or_copyin (hostaddrs
[i
], sizes
[i
]);
338 case GOMP_MAP_FORCE_TO
:
339 acc_present_or_copyin (hostaddrs
[i
], sizes
[i
]);
342 gomp_fatal (">>>> GOACC_enter_exit_data UNHANDLED kind 0x%.2x",
349 gomp_acc_insert_pointer (3, &hostaddrs
[i
], &sizes
[i
], &kinds
[i
]);
350 /* Increment 'i' by two because OpenACC requires fortran
351 arrays to be contiguous, so each PSET is associated with
352 one of MAP_FORCE_ALLOC/MAP_FORCE_PRESET/MAP_FORCE_TO, and
359 for (i
= 0; i
< mapnum
; ++i
)
361 unsigned char kind
= kinds
[i
] & 0xff;
363 int psets
= find_pset (i
, mapnum
, kinds
);
369 case GOMP_MAP_POINTER
:
370 gomp_acc_remove_pointer (hostaddrs
[i
], (kinds
[i
] & 0xff)
371 == GOMP_MAP_FORCE_FROM
,
374 case GOMP_MAP_DELETE
:
375 acc_delete (hostaddrs
[i
], sizes
[i
]);
377 case GOMP_MAP_FORCE_FROM
:
378 acc_copyout (hostaddrs
[i
], sizes
[i
]);
381 gomp_fatal (">>>> GOACC_enter_exit_data UNHANDLED kind 0x%.2x",
388 gomp_acc_remove_pointer (hostaddrs
[i
], (kinds
[i
] & 0xff)
389 == GOMP_MAP_FORCE_FROM
, async
, 3);
390 /* See the above comment. */
395 acc_dev
->openacc
.async_set_async_func (acc_async_sync
);
399 goacc_wait (int async
, int num_waits
, va_list *ap
)
401 struct goacc_thread
*thr
= goacc_thread ();
402 struct gomp_device_descr
*acc_dev
= thr
->dev
;
406 int qid
= va_arg (*ap
, int);
408 if (acc_async_test (qid
))
411 if (async
== acc_async_sync
)
413 else if (qid
== async
)
414 ;/* If we're waiting on the same asynchronous queue as we're
415 launching on, the queue itself will order work as
416 required, so there's no need to wait explicitly. */
418 acc_dev
->openacc
.async_wait_async_func (qid
, async
);
423 GOACC_update (int device
, size_t mapnum
,
424 void **hostaddrs
, size_t *sizes
, unsigned short *kinds
,
425 int async
, int num_waits
, ...)
427 bool host_fallback
= device
== GOMP_DEVICE_HOST_FALLBACK
;
430 goacc_lazy_initialize ();
432 struct goacc_thread
*thr
= goacc_thread ();
433 struct gomp_device_descr
*acc_dev
= thr
->dev
;
435 if ((acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
443 va_start (ap
, num_waits
);
444 goacc_wait (async
, num_waits
, &ap
);
448 acc_dev
->openacc
.async_set_async_func (async
);
450 for (i
= 0; i
< mapnum
; ++i
)
452 unsigned char kind
= kinds
[i
] & 0xff;
456 case GOMP_MAP_POINTER
:
457 case GOMP_MAP_TO_PSET
:
460 case GOMP_MAP_FORCE_TO
:
461 acc_update_device (hostaddrs
[i
], sizes
[i
]);
464 case GOMP_MAP_FORCE_FROM
:
465 acc_update_self (hostaddrs
[i
], sizes
[i
]);
469 gomp_fatal (">>>> GOACC_update UNHANDLED kind 0x%.2x", kind
);
474 acc_dev
->openacc
.async_set_async_func (acc_async_sync
);
478 GOACC_wait (int async
, int num_waits
, ...)
484 va_start (ap
, num_waits
);
485 goacc_wait (async
, num_waits
, &ap
);
488 else if (async
== acc_async_sync
)
490 else if (async
== acc_async_noval
)
491 goacc_thread ()->dev
->openacc
.async_wait_all_async_func (acc_async_noval
);
495 GOACC_get_num_threads (void)
501 GOACC_get_thread_num (void)
507 GOACC_declare (int device
, size_t mapnum
,
508 void **hostaddrs
, size_t *sizes
, unsigned short *kinds
)
512 for (i
= 0; i
< mapnum
; i
++)
514 unsigned char kind
= kinds
[i
] & 0xff;
516 if (kind
== GOMP_MAP_POINTER
|| kind
== GOMP_MAP_TO_PSET
)
521 case GOMP_MAP_FORCE_ALLOC
:
522 case GOMP_MAP_FORCE_FROM
:
523 case GOMP_MAP_FORCE_TO
:
524 case GOMP_MAP_POINTER
:
525 case GOMP_MAP_DELETE
:
526 GOACC_enter_exit_data (device
, 1, &hostaddrs
[i
], &sizes
[i
],
530 case GOMP_MAP_FORCE_DEVICEPTR
:
534 if (!acc_is_present (hostaddrs
[i
], sizes
[i
]))
535 GOACC_enter_exit_data (device
, 1, &hostaddrs
[i
], &sizes
[i
],
540 GOACC_enter_exit_data (device
, 1, &hostaddrs
[i
], &sizes
[i
],
546 kinds
[i
] = GOMP_MAP_FORCE_FROM
;
547 GOACC_enter_exit_data (device
, 1, &hostaddrs
[i
], &sizes
[i
],
551 case GOMP_MAP_FORCE_PRESENT
:
552 if (!acc_is_present (hostaddrs
[i
], sizes
[i
]))
553 gomp_fatal ("[%p,%ld] is not mapped", hostaddrs
[i
],
554 (unsigned long) sizes
[i
]);