1 /* Copyright (C) 2017-2024 Free Software Foundation, Inc.
2 Contributed by Mentor Embedded.
4 This file is part of the GNU Offloading and Multi Processing Library
7 Libgomp is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
27 #include "libgomp-gcn.h"
30 extern volatile struct gomp_offload_icvs GOMP_ADDITIONAL_ICVS
;
32 /* Implement OpenMP 'teams' construct.
34 Initialize upon FIRST call. Return whether this invocation is active.
35 Depending on whether NUM_TEAMS_LOWER asks for more teams than are provided
36 in hardware, we may need to loop multiple times; in that case make sure to
37 update the team-level variable used by 'omp_get_team_num', as we then can't
38 just use '__builtin_gcn_dim_pos (0)'. */
41 GOMP_teams4 (unsigned int num_teams_lower
, unsigned int num_teams_upper
,
42 unsigned int thread_limit
, bool first
)
44 int __lds
*gomp_team_num
= (int __lds
*) GOMP_TEAM_NUM
;
45 unsigned int num_workgroups
= __builtin_gcn_dim_size (0);
48 unsigned int team_num
;
49 if (num_workgroups
> gomp_num_teams_var
)
51 team_num
= *gomp_team_num
;
52 if (team_num
> gomp_num_teams_var
- num_workgroups
)
54 *gomp_team_num
= team_num
+ num_workgroups
;
59 struct gomp_task_icv
*icv
= gomp_icv (true);
61 = thread_limit
> INT_MAX
? UINT_MAX
: thread_limit
;
64 num_teams_upper
= ((GOMP_ADDITIONAL_ICVS
.nteams
> 0
65 && num_workgroups
> GOMP_ADDITIONAL_ICVS
.nteams
)
66 ? GOMP_ADDITIONAL_ICVS
.nteams
: num_workgroups
);
67 else if (num_workgroups
< num_teams_lower
)
68 num_teams_upper
= num_teams_lower
;
69 else if (num_workgroups
< num_teams_upper
)
70 num_teams_upper
= num_workgroups
;
71 unsigned int workgroup_id
= __builtin_gcn_dim_pos (0);
72 if (workgroup_id
>= num_teams_upper
)
74 *gomp_team_num
= workgroup_id
;
75 gomp_num_teams_var
= num_teams_upper
- 1;
80 omp_pause_resource (omp_pause_resource_t kind
, int device_num
)
88 omp_pause_resource_all (omp_pause_resource_t kind
)
94 ialias (omp_pause_resource
)
95 ialias (omp_pause_resource_all
)
98 GOMP_target_ext (int device
, void (*fn
) (void *), size_t mapnum
,
99 void **hostaddrs
, size_t *sizes
, unsigned short *kinds
,
100 unsigned int flags
, void **depend
, void **args
)
106 if (device
!= GOMP_DEVICE_HOST_FALLBACK
|| fn
== NULL
)
109 /* The output data is at ((void*) kernargs)[2]. */
110 register void **kernargs
= (void**) __builtin_gcn_kernarg_ptr ();
111 struct output
*data
= (struct output
*) kernargs
[2];
112 /* Reserve one slot. */
113 unsigned int index
= __atomic_fetch_add (&data
->next_output
, 1,
116 if ((unsigned int) (index
+ 1) < data
->consumed
)
117 abort (); /* Overflow. */
119 /* Spinlock while the host catches up. */
121 while (__atomic_load_n (&data
->consumed
, __ATOMIC_ACQUIRE
)
125 unsigned int slot
= index
% 1024;
126 data
->queue
[slot
].value_u64
[0] = (uint64_t) fn
;
127 data
->queue
[slot
].value_u64
[1] = (uint64_t) mapnum
;
128 data
->queue
[slot
].value_u64
[2] = (uint64_t) hostaddrs
;
129 data
->queue
[slot
].value_u64
[3] = (uint64_t) sizes
;
130 data
->queue
[slot
].value_u64
[4] = (uint64_t) kinds
;
131 data
->queue
[slot
].value_u64
[5] = (uint64_t) GOMP_ADDITIONAL_ICVS
.device_num
;
133 data
->queue
[slot
].type
= 4; /* Reverse offload. */
134 __atomic_store_n (&data
->queue
[slot
].written
, 1, __ATOMIC_RELEASE
);
136 /* Spinlock while the host catches up. */
137 while (__atomic_load_n (&data
->queue
[slot
].written
, __ATOMIC_ACQUIRE
) != 0)
142 GOMP_target_data_ext (int device
, size_t mapnum
, void **hostaddrs
,
143 size_t *sizes
, unsigned short *kinds
)
150 __builtin_unreachable ();
154 GOMP_target_end_data (void)
156 __builtin_unreachable ();
160 GOMP_target_update_ext (int device
, size_t mapnum
, void **hostaddrs
,
161 size_t *sizes
, unsigned short *kinds
,
162 unsigned int flags
, void **depend
)
171 __builtin_unreachable ();
175 GOMP_target_enter_exit_data (int device
, size_t mapnum
, void **hostaddrs
,
176 size_t *sizes
, unsigned short *kinds
,
177 unsigned int flags
, void **depend
)
186 __builtin_unreachable ();
190 omp_get_num_interop_properties (const omp_interop_t interop
191 __attribute__ ((unused
)))
197 omp_get_interop_int (const omp_interop_t interop
,
198 omp_interop_property_t property_id
,
199 omp_interop_rc_t
*ret_code
)
201 if (ret_code
== NULL
)
203 if (property_id
< omp_ipr_first
|| property_id
>= 0)
204 *ret_code
= omp_irc_out_of_range
;
205 else if (interop
== omp_interop_none
)
206 *ret_code
= omp_irc_empty
;
208 *ret_code
= omp_irc_other
;
213 omp_get_interop_ptr (const omp_interop_t interop
,
214 omp_interop_property_t property_id
,
215 omp_interop_rc_t
*ret_code
)
217 if (ret_code
== NULL
)
219 if (property_id
< omp_ipr_first
|| property_id
>= 0)
220 *ret_code
= omp_irc_out_of_range
;
221 else if (interop
== omp_interop_none
)
222 *ret_code
= omp_irc_empty
;
224 *ret_code
= omp_irc_other
;
229 omp_get_interop_str (const omp_interop_t interop
,
230 omp_interop_property_t property_id
,
231 omp_interop_rc_t
*ret_code
)
233 if (ret_code
== NULL
)
235 if (property_id
< omp_ipr_first
|| property_id
>= 0)
236 *ret_code
= omp_irc_out_of_range
;
237 else if (interop
== omp_interop_none
)
238 *ret_code
= omp_irc_empty
;
240 *ret_code
= omp_irc_other
;
245 omp_get_interop_name (const omp_interop_t interop
__attribute__ ((unused
)),
246 omp_interop_property_t property_id
)
248 static const char *prop_string
[0 - omp_ipr_first
]
249 = {"fr_id", "fr_name", "vendor", "vendor_name", "device_num", "platform",
250 "device", "device_context", "targetsync"};
251 if (property_id
< omp_ipr_first
|| property_id
>= 0)
253 return prop_string
[omp_ipr_fr_id
- property_id
];
257 omp_get_interop_type_desc (const omp_interop_t interop
__attribute__ ((unused
)),
258 omp_interop_property_t property_id
259 __attribute__ ((unused
)))
265 omp_get_interop_rc_desc (const omp_interop_t interop
__attribute__ ((unused
)),
266 omp_interop_rc_t ret_code
)
268 static const char *rc_strings
[omp_irc_no_value
- omp_irc_other
+ 1]
269 = {"no meaningful value available",
271 "provided interoperability object is equal to omp_interop_none",
272 "property ID is out of range",
273 "property type is integer; use omp_get_interop_int",
274 "property type is pointer; use omp_get_interop_ptr",
275 "property type is string; use omp_get_interop_str",
276 "obtaining properties is only supported on the initial device"};
277 /* omp_irc_other is returned by device-side omp_get_interop_{int,ptr,str};
278 the host returns for omp_irc_other NULL as it is not used. Besides the
279 three omp_interop_rc_t values used on the device side, handle host values
280 leaked to the device side. */
281 if (ret_code
> omp_irc_no_value
|| ret_code
< omp_irc_other
)
283 return rc_strings
[omp_irc_no_value
- ret_code
];
287 omp_get_uid_from_device (int device_num
__attribute__ ((unused
)))
293 omp_get_device_from_uid (const char *uid
__attribute__ ((unused
)))
295 return omp_invalid_device
;
298 ialias (omp_get_num_interop_properties
)
299 ialias (omp_get_interop_int
)
300 ialias (omp_get_interop_ptr
)
301 ialias (omp_get_interop_str
)
302 ialias (omp_get_interop_name
)
303 ialias (omp_get_interop_type_desc
)
304 ialias (omp_get_interop_rc_desc
)
305 ialias (omp_get_uid_from_device
)
306 ialias (omp_get_device_from_uid
)