]>
Commit | Line | Data |
---|---|---|
a945c346 | 1 | /* Copyright (C) 2017-2024 Free Software Foundation, Inc. |
fa499995 AS |
2 | Contributed by Mentor Embedded. |
3 | ||
4 | This file is part of the GNU Offloading and Multi Processing Library | |
5 | (libgomp). | |
6 | ||
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) | |
10 | any later version. | |
11 | ||
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 | |
15 | more details. | |
16 | ||
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. | |
20 | ||
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/>. */ | |
25 | ||
26 | #include "libgomp.h" | |
8c05d8cd | 27 | #include "libgomp-gcn.h" |
fa499995 AS |
28 | #include <limits.h> |
29 | ||
8c05d8cd TB |
30 | extern volatile struct gomp_offload_icvs GOMP_ADDITIONAL_ICVS; |
31 | ||
a95c1911 TS |
32 | /* Implement OpenMP 'teams' construct. |
33 | ||
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)'. */ | |
39 | ||
7d6da11f JJ |
40 | bool |
41 | GOMP_teams4 (unsigned int num_teams_lower, unsigned int num_teams_upper, | |
42 | unsigned int thread_limit, bool first) | |
fa499995 | 43 | { |
f9119948 TS |
44 | int __lds *gomp_team_num = (int __lds *) GOMP_TEAM_NUM; |
45 | unsigned int num_workgroups = __builtin_gcn_dim_size (0); | |
7d6da11f | 46 | if (!first) |
f9119948 TS |
47 | { |
48 | unsigned int team_num; | |
49 | if (num_workgroups > gomp_num_teams_var) | |
50 | return false; | |
51 | team_num = *gomp_team_num; | |
52 | if (team_num > gomp_num_teams_var - num_workgroups) | |
53 | return false; | |
54 | *gomp_team_num = team_num + num_workgroups; | |
55 | return true; | |
56 | } | |
fa499995 AS |
57 | if (thread_limit) |
58 | { | |
59 | struct gomp_task_icv *icv = gomp_icv (true); | |
60 | icv->thread_limit_var | |
61 | = thread_limit > INT_MAX ? UINT_MAX : thread_limit; | |
62 | } | |
f9119948 | 63 | if (!num_teams_upper) |
ad0f80d9 TB |
64 | num_teams_upper = ((GOMP_ADDITIONAL_ICVS.nteams > 0 |
65 | && num_workgroups > GOMP_ADDITIONAL_ICVS.nteams) | |
66 | ? GOMP_ADDITIONAL_ICVS.nteams : num_workgroups); | |
f9119948 TS |
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) | |
7d6da11f | 73 | return false; |
f9119948 | 74 | *gomp_team_num = workgroup_id; |
7d6da11f JJ |
75 | gomp_num_teams_var = num_teams_upper - 1; |
76 | return true; | |
fa499995 AS |
77 | } |
78 | ||
79 | int | |
80 | omp_pause_resource (omp_pause_resource_t kind, int device_num) | |
81 | { | |
82 | (void) kind; | |
83 | (void) device_num; | |
84 | return -1; | |
85 | } | |
86 | ||
87 | int | |
88 | omp_pause_resource_all (omp_pause_resource_t kind) | |
89 | { | |
90 | (void) kind; | |
91 | return -1; | |
92 | } | |
93 | ||
94 | ialias (omp_pause_resource) | |
95 | ialias (omp_pause_resource_all) | |
95d67762 JJ |
96 | |
97 | void | |
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) | |
101 | { | |
95d67762 JJ |
102 | (void) flags; |
103 | (void) depend; | |
104 | (void) args; | |
8c05d8cd TB |
105 | |
106 | if (device != GOMP_DEVICE_HOST_FALLBACK || fn == NULL) | |
107 | return; | |
108 | ||
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, | |
114 | __ATOMIC_ACQUIRE); | |
115 | ||
116 | if ((unsigned int) (index + 1) < data->consumed) | |
117 | abort (); /* Overflow. */ | |
118 | ||
119 | /* Spinlock while the host catches up. */ | |
120 | if (index >= 1024) | |
121 | while (__atomic_load_n (&data->consumed, __ATOMIC_ACQUIRE) | |
122 | <= (index - 1024)) | |
123 | asm ("s_sleep 64"); | |
124 | ||
125 | unsigned int slot = index % 1024; | |
6edcb5dc TB |
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; | |
8c05d8cd TB |
132 | |
133 | data->queue[slot].type = 4; /* Reverse offload. */ | |
134 | __atomic_store_n (&data->queue[slot].written, 1, __ATOMIC_RELEASE); | |
135 | ||
136 | /* Spinlock while the host catches up. */ | |
137 | while (__atomic_load_n (&data->queue[slot].written, __ATOMIC_ACQUIRE) != 0) | |
138 | asm ("s_sleep 64"); | |
95d67762 JJ |
139 | } |
140 | ||
141 | void | |
142 | GOMP_target_data_ext (int device, size_t mapnum, void **hostaddrs, | |
143 | size_t *sizes, unsigned short *kinds) | |
144 | { | |
145 | (void) device; | |
146 | (void) mapnum; | |
147 | (void) hostaddrs; | |
148 | (void) sizes; | |
149 | (void) kinds; | |
150 | __builtin_unreachable (); | |
151 | } | |
152 | ||
153 | void | |
154 | GOMP_target_end_data (void) | |
155 | { | |
156 | __builtin_unreachable (); | |
157 | } | |
158 | ||
159 | void | |
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) | |
163 | { | |
164 | (void) device; | |
165 | (void) mapnum; | |
166 | (void) hostaddrs; | |
167 | (void) sizes; | |
168 | (void) kinds; | |
169 | (void) flags; | |
170 | (void) depend; | |
171 | __builtin_unreachable (); | |
172 | } | |
173 | ||
174 | void | |
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) | |
178 | { | |
179 | (void) device; | |
180 | (void) mapnum; | |
181 | (void) hostaddrs; | |
182 | (void) sizes; | |
183 | (void) kinds; | |
184 | (void) flags; | |
185 | (void) depend; | |
186 | __builtin_unreachable (); | |
187 | } | |
0beac1db TB |
188 | |
189 | int | |
190 | omp_get_num_interop_properties (const omp_interop_t interop | |
191 | __attribute__ ((unused))) | |
192 | { | |
193 | return 0; | |
194 | } | |
195 | ||
196 | omp_intptr_t | |
197 | omp_get_interop_int (const omp_interop_t interop, | |
198 | omp_interop_property_t property_id, | |
199 | omp_interop_rc_t *ret_code) | |
200 | { | |
201 | if (ret_code == NULL) | |
202 | return 0; | |
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; | |
207 | else | |
208 | *ret_code = omp_irc_other; | |
209 | return 0; | |
210 | } | |
211 | ||
212 | void * | |
213 | omp_get_interop_ptr (const omp_interop_t interop, | |
214 | omp_interop_property_t property_id, | |
215 | omp_interop_rc_t *ret_code) | |
216 | { | |
217 | if (ret_code == NULL) | |
218 | return 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; | |
223 | else | |
224 | *ret_code = omp_irc_other; | |
225 | return NULL; | |
226 | } | |
227 | ||
228 | const char * | |
229 | omp_get_interop_str (const omp_interop_t interop, | |
230 | omp_interop_property_t property_id, | |
231 | omp_interop_rc_t *ret_code) | |
232 | { | |
233 | if (ret_code == NULL) | |
234 | return 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; | |
239 | else | |
240 | *ret_code = omp_irc_other; | |
241 | return NULL; | |
242 | } | |
243 | ||
244 | const char * | |
245 | omp_get_interop_name (const omp_interop_t interop __attribute__ ((unused)), | |
246 | omp_interop_property_t property_id) | |
247 | { | |
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) | |
252 | return NULL; | |
253 | return prop_string[omp_ipr_fr_id - property_id]; | |
254 | } | |
255 | ||
256 | const char * | |
257 | omp_get_interop_type_desc (const omp_interop_t interop __attribute__ ((unused)), | |
258 | omp_interop_property_t property_id | |
259 | __attribute__ ((unused))) | |
260 | { | |
261 | return NULL; | |
262 | } | |
263 | ||
264 | const char * | |
265 | omp_get_interop_rc_desc (const omp_interop_t interop __attribute__ ((unused)), | |
266 | omp_interop_rc_t ret_code) | |
267 | { | |
268 | static const char *rc_strings[omp_irc_no_value - omp_irc_other + 1] | |
269 | = {"no meaningful value available", | |
270 | "successful", | |
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) | |
282 | return NULL; | |
283 | return rc_strings[omp_irc_no_value - ret_code]; | |
284 | } | |
285 | ||
bf4a5efa TB |
286 | const char * |
287 | omp_get_uid_from_device (int device_num __attribute__ ((unused))) | |
288 | { | |
289 | return NULL; | |
290 | } | |
291 | ||
292 | int | |
293 | omp_get_device_from_uid (const char *uid __attribute__ ((unused))) | |
294 | { | |
295 | return omp_invalid_device; | |
296 | } | |
297 | ||
0beac1db TB |
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) | |
bf4a5efa TB |
305 | ialias (omp_get_uid_from_device) |
306 | ialias (omp_get_device_from_uid) |