/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/lib/External/isl/isl_schedule_band.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2013-2014 Ecole Normale Superieure |
3 | | * Copyright 2014 INRIA Rocquencourt |
4 | | * |
5 | | * Use of this software is governed by the MIT license |
6 | | * |
7 | | * Written by Sven Verdoolaege, |
8 | | * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France |
9 | | * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, |
10 | | * B.P. 105 - 78153 Le Chesnay, France |
11 | | */ |
12 | | |
13 | | #include <string.h> |
14 | | #include <isl/val.h> |
15 | | #include <isl/space.h> |
16 | | #include <isl/map.h> |
17 | | #include <isl/schedule_node.h> |
18 | | #include <isl_schedule_band.h> |
19 | | #include <isl_schedule_private.h> |
20 | | |
21 | | isl_ctx *isl_schedule_band_get_ctx(__isl_keep isl_schedule_band *band) |
22 | 3.61k | { |
23 | 3.61k | return band ? isl_multi_union_pw_aff_get_ctx(band->mupa) : NULL; |
24 | 3.61k | } |
25 | | |
26 | | /* Return a new uninitialized isl_schedule_band. |
27 | | */ |
28 | | static __isl_give isl_schedule_band *isl_schedule_band_alloc(isl_ctx *ctx) |
29 | 3.43k | { |
30 | 3.43k | isl_schedule_band *band; |
31 | 3.43k | |
32 | 3.43k | band = isl_calloc_type(ctx, isl_schedule_band); |
33 | 3.43k | if (!band) |
34 | 0 | return NULL; |
35 | 3.43k | |
36 | 3.43k | band->ref = 1; |
37 | 3.43k | |
38 | 3.43k | return band; |
39 | 3.43k | } |
40 | | |
41 | | /* Return a new isl_schedule_band with partial schedule "mupa". |
42 | | * First replace "mupa" by its greatest integer part to ensure |
43 | | * that the schedule is always integral. |
44 | | * The band is not marked permutable, the dimensions are not |
45 | | * marked coincident and the AST build options are empty. |
46 | | * Since there are no build options, the node is not anchored. |
47 | | */ |
48 | | __isl_give isl_schedule_band *isl_schedule_band_from_multi_union_pw_aff( |
49 | | __isl_take isl_multi_union_pw_aff *mupa) |
50 | 2.06k | { |
51 | 2.06k | isl_ctx *ctx; |
52 | 2.06k | isl_schedule_band *band; |
53 | 2.06k | isl_space *space; |
54 | 2.06k | |
55 | 2.06k | mupa = isl_multi_union_pw_aff_floor(mupa); |
56 | 2.06k | if (!mupa) |
57 | 0 | return NULL; |
58 | 2.06k | ctx = isl_multi_union_pw_aff_get_ctx(mupa); |
59 | 2.06k | band = isl_schedule_band_alloc(ctx); |
60 | 2.06k | if (!band) |
61 | 0 | goto error; |
62 | 2.06k | |
63 | 2.06k | band->n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set); |
64 | 2.06k | band->coincident = isl_calloc_array(ctx, int, band->n); |
65 | 2.06k | band->mupa = mupa; |
66 | 2.06k | space = isl_space_params_alloc(ctx, 0); |
67 | 2.06k | band->ast_build_options = isl_union_set_empty(space); |
68 | 2.06k | band->anchored = 0; |
69 | 2.06k | |
70 | 2.06k | if ((band->n && !band->coincident) || !band->ast_build_options) |
71 | 0 | return isl_schedule_band_free(band); |
72 | 2.06k | |
73 | 2.06k | return band; |
74 | 0 | error: |
75 | 0 | isl_multi_union_pw_aff_free(mupa); |
76 | 0 | return NULL; |
77 | 2.06k | } |
78 | | |
79 | | /* Create a duplicate of the given isl_schedule_band. |
80 | | */ |
81 | | __isl_give isl_schedule_band *isl_schedule_band_dup( |
82 | | __isl_keep isl_schedule_band *band) |
83 | 1.37k | { |
84 | 1.37k | int i; |
85 | 1.37k | isl_ctx *ctx; |
86 | 1.37k | isl_schedule_band *dup; |
87 | 1.37k | |
88 | 1.37k | if (!band) |
89 | 0 | return NULL; |
90 | 1.37k | |
91 | 1.37k | ctx = isl_schedule_band_get_ctx(band); |
92 | 1.37k | dup = isl_schedule_band_alloc(ctx); |
93 | 1.37k | if (!dup) |
94 | 0 | return NULL; |
95 | 1.37k | |
96 | 1.37k | dup->n = band->n; |
97 | 1.37k | dup->coincident = isl_alloc_array(ctx, int, band->n); |
98 | 1.37k | if (band->n && !dup->coincident) |
99 | 0 | return isl_schedule_band_free(dup); |
100 | 1.37k | |
101 | 3.58k | for (i = 0; 1.37k i < band->n; ++i2.21k ) |
102 | 2.21k | dup->coincident[i] = band->coincident[i]; |
103 | 1.37k | dup->permutable = band->permutable; |
104 | 1.37k | |
105 | 1.37k | dup->mupa = isl_multi_union_pw_aff_copy(band->mupa); |
106 | 1.37k | dup->ast_build_options = isl_union_set_copy(band->ast_build_options); |
107 | 1.37k | if (!dup->mupa || !dup->ast_build_options) |
108 | 0 | return isl_schedule_band_free(dup); |
109 | 1.37k | |
110 | 1.37k | if (band->loop_type) { |
111 | 18 | dup->loop_type = isl_alloc_array(ctx, |
112 | 18 | enum isl_ast_loop_type, band->n); |
113 | 18 | if (band->n && !dup->loop_type) |
114 | 0 | return isl_schedule_band_free(dup); |
115 | 62 | for (i = 0; 18 i < band->n; ++i44 ) |
116 | 44 | dup->loop_type[i] = band->loop_type[i]; |
117 | 18 | } |
118 | 1.37k | if (band->isolate_loop_type) { |
119 | 0 | dup->isolate_loop_type = isl_alloc_array(ctx, |
120 | 0 | enum isl_ast_loop_type, band->n); |
121 | 0 | if (band->n && !dup->isolate_loop_type) |
122 | 0 | return isl_schedule_band_free(dup); |
123 | 0 | for (i = 0; i < band->n; ++i) |
124 | 0 | dup->isolate_loop_type[i] = band->isolate_loop_type[i]; |
125 | 0 | } |
126 | 1.37k | |
127 | 1.37k | return dup; |
128 | 1.37k | } |
129 | | |
130 | | /* Return an isl_schedule_band that is equal to "band" and that has only |
131 | | * a single reference. |
132 | | */ |
133 | | __isl_give isl_schedule_band *isl_schedule_band_cow( |
134 | | __isl_take isl_schedule_band *band) |
135 | 1.45k | { |
136 | 1.45k | if (!band) |
137 | 0 | return NULL; |
138 | 1.45k | |
139 | 1.45k | if (band->ref == 1) |
140 | 74 | return band; |
141 | 1.37k | band->ref--; |
142 | 1.37k | return isl_schedule_band_dup(band); |
143 | 1.37k | } |
144 | | |
145 | | /* Return a new reference to "band". |
146 | | */ |
147 | | __isl_give isl_schedule_band *isl_schedule_band_copy( |
148 | | __isl_keep isl_schedule_band *band) |
149 | 3.50k | { |
150 | 3.50k | if (!band) |
151 | 0 | return NULL; |
152 | 3.50k | |
153 | 3.50k | band->ref++; |
154 | 3.50k | return band; |
155 | 3.50k | } |
156 | | |
157 | | /* Free a reference to "band" and return NULL. |
158 | | */ |
159 | | __isl_null isl_schedule_band *isl_schedule_band_free( |
160 | | __isl_take isl_schedule_band *band) |
161 | 5.53k | { |
162 | 5.53k | if (!band) |
163 | 0 | return NULL; |
164 | 5.53k | |
165 | 5.53k | if (--band->ref > 0) |
166 | 2.12k | return NULL; |
167 | 3.40k | |
168 | 3.40k | isl_multi_union_pw_aff_free(band->mupa); |
169 | 3.40k | isl_union_set_free(band->ast_build_options); |
170 | 3.40k | free(band->loop_type); |
171 | 3.40k | free(band->isolate_loop_type); |
172 | 3.40k | free(band->coincident); |
173 | 3.40k | free(band); |
174 | 3.40k | |
175 | 3.40k | return NULL; |
176 | 3.40k | } |
177 | | |
178 | | /* Are "band1" and "band2" obviously equal? |
179 | | */ |
180 | | isl_bool isl_schedule_band_plain_is_equal(__isl_keep isl_schedule_band *band1, |
181 | | __isl_keep isl_schedule_band *band2) |
182 | 0 | { |
183 | 0 | int i; |
184 | 0 | isl_bool equal; |
185 | 0 |
|
186 | 0 | if (!band1 || !band2) |
187 | 0 | return isl_bool_error; |
188 | 0 | if (band1 == band2) |
189 | 0 | return isl_bool_true; |
190 | 0 | |
191 | 0 | if (band1->n != band2->n) |
192 | 0 | return isl_bool_false; |
193 | 0 | for (i = 0; i < band1->n; ++i) |
194 | 0 | if (band1->coincident[i] != band2->coincident[i]) |
195 | 0 | return isl_bool_false; |
196 | 0 | if (band1->permutable != band2->permutable) |
197 | 0 | return isl_bool_false; |
198 | 0 | |
199 | 0 | equal = isl_multi_union_pw_aff_plain_is_equal(band1->mupa, band2->mupa); |
200 | 0 | if (equal < 0 || !equal) |
201 | 0 | return equal; |
202 | 0 | |
203 | 0 | if (!band1->loop_type != !band2->loop_type) |
204 | 0 | return isl_bool_false; |
205 | 0 | if (band1->loop_type) |
206 | 0 | for (i = 0; i < band1->n; ++i) |
207 | 0 | if (band1->loop_type[i] != band2->loop_type[i]) |
208 | 0 | return isl_bool_false; |
209 | 0 |
|
210 | 0 | if (!band1->isolate_loop_type != !band2->isolate_loop_type) |
211 | 0 | return isl_bool_false; |
212 | 0 | if (band1->isolate_loop_type) |
213 | 0 | for (i = 0; i < band1->n; ++i) |
214 | 0 | if (band1->isolate_loop_type[i] != |
215 | 0 | band2->isolate_loop_type[i]) |
216 | 0 | return isl_bool_false; |
217 | 0 |
|
218 | 0 | return isl_union_set_is_equal(band1->ast_build_options, |
219 | 0 | band2->ast_build_options); |
220 | 0 | } |
221 | | |
222 | | /* Return the number of scheduling dimensions in the band. |
223 | | */ |
224 | | int isl_schedule_band_n_member(__isl_keep isl_schedule_band *band) |
225 | 79.0k | { |
226 | 79.0k | return band ? band->n : 00 ; |
227 | 79.0k | } |
228 | | |
229 | | /* Is the given scheduling dimension coincident within the band and |
230 | | * with respect to the coincidence constraints? |
231 | | */ |
232 | | isl_bool isl_schedule_band_member_get_coincident( |
233 | | __isl_keep isl_schedule_band *band, int pos) |
234 | 1.53k | { |
235 | 1.53k | if (!band) |
236 | 0 | return isl_bool_error; |
237 | 1.53k | |
238 | 1.53k | if (pos < 0 || pos >= band->n) |
239 | 1.53k | isl_die0 (isl_schedule_band_get_ctx(band), isl_error_invalid, |
240 | 1.53k | "invalid member position", return isl_bool_error); |
241 | 1.53k | |
242 | 1.53k | return band->coincident[pos]; |
243 | 1.53k | } |
244 | | |
245 | | /* Mark the given scheduling dimension as being coincident or not |
246 | | * according to "coincident". |
247 | | */ |
248 | | __isl_give isl_schedule_band *isl_schedule_band_member_set_coincident( |
249 | | __isl_take isl_schedule_band *band, int pos, int coincident) |
250 | 227 | { |
251 | 227 | if (!band) |
252 | 0 | return NULL; |
253 | 227 | if (isl_schedule_band_member_get_coincident(band, pos) == coincident) |
254 | 0 | return band; |
255 | 227 | band = isl_schedule_band_cow(band); |
256 | 227 | if (!band) |
257 | 0 | return NULL; |
258 | 227 | |
259 | 227 | if (pos < 0 || pos >= band->n) |
260 | 227 | isl_die0 (isl_schedule_band_get_ctx(band), isl_error_invalid, |
261 | 227 | "invalid member position", |
262 | 227 | return isl_schedule_band_free(band)); |
263 | 227 | |
264 | 227 | band->coincident[pos] = coincident; |
265 | 227 | |
266 | 227 | return band; |
267 | 227 | } |
268 | | |
269 | | /* Is the schedule band mark permutable? |
270 | | */ |
271 | | isl_bool isl_schedule_band_get_permutable(__isl_keep isl_schedule_band *band) |
272 | 928 | { |
273 | 928 | if (!band) |
274 | 0 | return isl_bool_error; |
275 | 928 | return band->permutable; |
276 | 928 | } |
277 | | |
278 | | /* Mark the schedule band permutable or not according to "permutable"? |
279 | | */ |
280 | | __isl_give isl_schedule_band *isl_schedule_band_set_permutable( |
281 | | __isl_take isl_schedule_band *band, int permutable) |
282 | 150 | { |
283 | 150 | if (!band) |
284 | 0 | return NULL; |
285 | 150 | if (band->permutable == permutable) |
286 | 0 | return band; |
287 | 150 | band = isl_schedule_band_cow(band); |
288 | 150 | if (!band) |
289 | 0 | return NULL; |
290 | 150 | |
291 | 150 | band->permutable = permutable; |
292 | 150 | |
293 | 150 | return band; |
294 | 150 | } |
295 | | |
296 | | /* Is the band node "node" anchored? That is, does it reference |
297 | | * the outer band nodes? |
298 | | */ |
299 | | int isl_schedule_band_is_anchored(__isl_keep isl_schedule_band *band) |
300 | 5.33k | { |
301 | 5.33k | return band ? band->anchored : -10 ; |
302 | 5.33k | } |
303 | | |
304 | | /* Return the schedule space of the band. |
305 | | */ |
306 | | __isl_give isl_space *isl_schedule_band_get_space( |
307 | | __isl_keep isl_schedule_band *band) |
308 | 2.81k | { |
309 | 2.81k | if (!band) |
310 | 0 | return NULL; |
311 | 2.81k | return isl_multi_union_pw_aff_get_space(band->mupa); |
312 | 2.81k | } |
313 | | |
314 | | /* Intersect the domain of the band schedule of "band" with "domain". |
315 | | */ |
316 | | __isl_give isl_schedule_band *isl_schedule_band_intersect_domain( |
317 | | __isl_take isl_schedule_band *band, __isl_take isl_union_set *domain) |
318 | 2 | { |
319 | 2 | band = isl_schedule_band_cow(band); |
320 | 2 | if (!band || !domain) |
321 | 0 | goto error; |
322 | 2 | |
323 | 2 | band->mupa = isl_multi_union_pw_aff_intersect_domain(band->mupa, |
324 | 2 | domain); |
325 | 2 | if (!band->mupa) |
326 | 0 | return isl_schedule_band_free(band); |
327 | 2 | |
328 | 2 | return band; |
329 | 0 | error: |
330 | 0 | isl_schedule_band_free(band); |
331 | 0 | isl_union_set_free(domain); |
332 | 0 | return NULL; |
333 | 2 | } |
334 | | |
335 | | /* Return the schedule of the band in isolation. |
336 | | */ |
337 | | __isl_give isl_multi_union_pw_aff *isl_schedule_band_get_partial_schedule( |
338 | | __isl_keep isl_schedule_band *band) |
339 | 12.5k | { |
340 | 12.5k | return band ? isl_multi_union_pw_aff_copy(band->mupa) : NULL; |
341 | 12.5k | } |
342 | | |
343 | | /* Replace the schedule of "band" by "schedule". |
344 | | */ |
345 | | __isl_give isl_schedule_band *isl_schedule_band_set_partial_schedule( |
346 | | __isl_take isl_schedule_band *band, |
347 | | __isl_take isl_multi_union_pw_aff *schedule) |
348 | 2 | { |
349 | 2 | band = isl_schedule_band_cow(band); |
350 | 2 | if (!band || !schedule) |
351 | 0 | goto error; |
352 | 2 | |
353 | 2 | isl_multi_union_pw_aff_free(band->mupa); |
354 | 2 | band->mupa = schedule; |
355 | 2 | |
356 | 2 | return band; |
357 | 0 | error: |
358 | 0 | isl_schedule_band_free(band); |
359 | 0 | isl_multi_union_pw_aff_free(schedule); |
360 | 0 | return NULL; |
361 | 2 | } |
362 | | |
363 | | /* Return the loop AST generation type for the band member of "band" |
364 | | * at position "pos". |
365 | | */ |
366 | | enum isl_ast_loop_type isl_schedule_band_member_get_ast_loop_type( |
367 | | __isl_keep isl_schedule_band *band, int pos) |
368 | 861 | { |
369 | 861 | if (!band) |
370 | 0 | return isl_ast_loop_error; |
371 | 861 | |
372 | 861 | if (pos < 0 || pos >= band->n) |
373 | 861 | isl_die0 (isl_schedule_band_get_ctx(band), isl_error_invalid, |
374 | 861 | "invalid member position", return isl_ast_loop_error); |
375 | 861 | |
376 | 861 | if (!band->loop_type) |
377 | 738 | return isl_ast_loop_default; |
378 | 123 | |
379 | 123 | return band->loop_type[pos]; |
380 | 123 | } |
381 | | |
382 | | /* Set the loop AST generation type for the band member of "band" |
383 | | * at position "pos" to "type". |
384 | | */ |
385 | | __isl_give isl_schedule_band *isl_schedule_band_member_set_ast_loop_type( |
386 | | __isl_take isl_schedule_band *band, int pos, |
387 | | enum isl_ast_loop_type type) |
388 | 0 | { |
389 | 0 | if (!band) |
390 | 0 | return NULL; |
391 | 0 | if (isl_schedule_band_member_get_ast_loop_type(band, pos) == type) |
392 | 0 | return band; |
393 | 0 | |
394 | 0 | if (pos < 0 || pos >= band->n) |
395 | 0 | isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, |
396 | 0 | "invalid member position", |
397 | 0 | return isl_schedule_band_free(band)); |
398 | 0 |
|
399 | 0 | band = isl_schedule_band_cow(band); |
400 | 0 | if (!band) |
401 | 0 | return isl_schedule_band_free(band); |
402 | 0 | |
403 | 0 | if (!band->loop_type) { |
404 | 0 | isl_ctx *ctx; |
405 | 0 |
|
406 | 0 | ctx = isl_schedule_band_get_ctx(band); |
407 | 0 | band->loop_type = isl_calloc_array(ctx, |
408 | 0 | enum isl_ast_loop_type, band->n); |
409 | 0 | if (band->n && !band->loop_type) |
410 | 0 | return isl_schedule_band_free(band); |
411 | 0 | } |
412 | 0 | |
413 | 0 | band->loop_type[pos] = type; |
414 | 0 |
|
415 | 0 | return band; |
416 | 0 | } |
417 | | |
418 | | /* Return the loop AST generation type for the band member of "band" |
419 | | * at position "pos" for the part that has been isolated by the isolate option. |
420 | | */ |
421 | | enum isl_ast_loop_type isl_schedule_band_member_get_isolate_ast_loop_type( |
422 | | __isl_keep isl_schedule_band *band, int pos) |
423 | 917 | { |
424 | 917 | if (!band) |
425 | 0 | return isl_ast_loop_error; |
426 | 917 | |
427 | 917 | if (pos < 0 || pos >= band->n) |
428 | 917 | isl_die0 (isl_schedule_band_get_ctx(band), isl_error_invalid, |
429 | 917 | "invalid member position", return isl_ast_loop_error); |
430 | 917 | |
431 | 917 | if (!band->isolate_loop_type) |
432 | 50 | return isl_ast_loop_default; |
433 | 867 | |
434 | 867 | return band->isolate_loop_type[pos]; |
435 | 867 | } |
436 | | |
437 | | /* Set the loop AST generation type for the band member of "band" |
438 | | * at position "pos" to "type" for the part that has been isolated |
439 | | * by the isolate option. |
440 | | */ |
441 | | __isl_give isl_schedule_band * |
442 | | isl_schedule_band_member_set_isolate_ast_loop_type( |
443 | | __isl_take isl_schedule_band *band, int pos, |
444 | | enum isl_ast_loop_type type) |
445 | 0 | { |
446 | 0 | if (!band) |
447 | 0 | return NULL; |
448 | 0 | if (isl_schedule_band_member_get_isolate_ast_loop_type(band, pos) == |
449 | 0 | type) |
450 | 0 | return band; |
451 | 0 | |
452 | 0 | if (pos < 0 || pos >= band->n) |
453 | 0 | isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, |
454 | 0 | "invalid member position", |
455 | 0 | return isl_schedule_band_free(band)); |
456 | 0 |
|
457 | 0 | band = isl_schedule_band_cow(band); |
458 | 0 | if (!band) |
459 | 0 | return isl_schedule_band_free(band); |
460 | 0 | |
461 | 0 | if (!band->isolate_loop_type) { |
462 | 0 | isl_ctx *ctx; |
463 | 0 |
|
464 | 0 | ctx = isl_schedule_band_get_ctx(band); |
465 | 0 | band->isolate_loop_type = isl_calloc_array(ctx, |
466 | 0 | enum isl_ast_loop_type, band->n); |
467 | 0 | if (band->n && !band->isolate_loop_type) |
468 | 0 | return isl_schedule_band_free(band); |
469 | 0 | } |
470 | 0 | |
471 | 0 | band->isolate_loop_type[pos] = type; |
472 | 0 |
|
473 | 0 | return band; |
474 | 0 | } |
475 | | |
476 | | static const char *option_str[] = { |
477 | | [isl_ast_loop_atomic] = "atomic", |
478 | | [isl_ast_loop_unroll] = "unroll", |
479 | | [isl_ast_loop_separate] = "separate" |
480 | | }; |
481 | | |
482 | | /* Given a parameter space "space", extend it to a set space |
483 | | * |
484 | | * { type[x] } |
485 | | * |
486 | | * or |
487 | | * |
488 | | * { [isolate[] -> type[x]] } |
489 | | * |
490 | | * depending on whether "isolate" is set. |
491 | | * These can be used to encode loop AST generation options of the given type. |
492 | | */ |
493 | | static __isl_give isl_space *loop_type_space(__isl_take isl_space *space, |
494 | | enum isl_ast_loop_type type, int isolate) |
495 | 1.18k | { |
496 | 1.18k | const char *name; |
497 | 1.18k | |
498 | 1.18k | name = option_str[type]; |
499 | 1.18k | space = isl_space_set_from_params(space); |
500 | 1.18k | space = isl_space_add_dims(space, isl_dim_set, 1); |
501 | 1.18k | space = isl_space_set_tuple_name(space, isl_dim_set, name); |
502 | 1.18k | if (!isolate) |
503 | 888 | return space; |
504 | 300 | space = isl_space_from_range(space); |
505 | 300 | space = isl_space_set_tuple_name(space, isl_dim_in, "isolate"); |
506 | 300 | space = isl_space_wrap(space); |
507 | 300 | |
508 | 300 | return space; |
509 | 300 | } |
510 | | |
511 | | /* Add encodings of the "n" loop AST generation options "type" to "options". |
512 | | * If "isolate" is set, then these options refer to the isolated part. |
513 | | * |
514 | | * In particular, for each sequence of consecutive identical types "t", |
515 | | * different from the default, add an option |
516 | | * |
517 | | * { t[x] : first <= x <= last } |
518 | | * |
519 | | * or |
520 | | * |
521 | | * { [isolate[] -> t[x]] : first <= x <= last } |
522 | | */ |
523 | | static __isl_give isl_union_set *add_loop_types( |
524 | | __isl_take isl_union_set *options, int n, enum isl_ast_loop_type *type, |
525 | | int isolate) |
526 | 112 | { |
527 | 112 | int i; |
528 | 112 | |
529 | 112 | if (!type) |
530 | 76 | return options; |
531 | 36 | if (!options) |
532 | 0 | return NULL; |
533 | 36 | |
534 | 72 | for (i = 0; 36 i < n; ++i36 ) { |
535 | 36 | int first; |
536 | 36 | isl_space *space; |
537 | 36 | isl_set *option; |
538 | 36 | |
539 | 36 | if (type[i] == isl_ast_loop_default) |
540 | 0 | continue; |
541 | 36 | |
542 | 36 | first = i; |
543 | 108 | while (i + 1 < n && type[i + 1] == type[i]72 ) |
544 | 72 | ++i; |
545 | 36 | |
546 | 36 | space = isl_union_set_get_space(options); |
547 | 36 | space = loop_type_space(space, type[i], isolate); |
548 | 36 | option = isl_set_universe(space); |
549 | 36 | option = isl_set_lower_bound_si(option, isl_dim_set, 0, first); |
550 | 36 | option = isl_set_upper_bound_si(option, isl_dim_set, 0, i); |
551 | 36 | options = isl_union_set_add_set(options, option); |
552 | 36 | } |
553 | 36 | |
554 | 36 | return options; |
555 | 36 | } |
556 | | |
557 | | /* Return the AST build options associated to "band". |
558 | | */ |
559 | | __isl_give isl_union_set *isl_schedule_band_get_ast_build_options( |
560 | | __isl_keep isl_schedule_band *band) |
561 | 56 | { |
562 | 56 | isl_union_set *options; |
563 | 56 | |
564 | 56 | if (!band) |
565 | 0 | return NULL; |
566 | 56 | |
567 | 56 | options = isl_union_set_copy(band->ast_build_options); |
568 | 56 | options = add_loop_types(options, band->n, band->loop_type, 0); |
569 | 56 | options = add_loop_types(options, band->n, band->isolate_loop_type, 1); |
570 | 56 | |
571 | 56 | return options; |
572 | 56 | } |
573 | | |
574 | | /* Does "uset" contain any set that satisfies "is"? |
575 | | * "is" is assumed to set its integer argument to 1 if it is satisfied. |
576 | | */ |
577 | | static int has_any(__isl_keep isl_union_set *uset, |
578 | | isl_stat (*is)(__isl_take isl_set *set, void *user)) |
579 | 390 | { |
580 | 390 | int found = 0; |
581 | 390 | |
582 | 390 | if (isl_union_set_foreach_set(uset, is, &found) < 0 && !found170 ) |
583 | 0 | return -1; |
584 | 390 | |
585 | 390 | return found; |
586 | 390 | } |
587 | | |
588 | | /* Does "set" live in a space of the form |
589 | | * |
590 | | * isolate[[...] -> [...]] |
591 | | * |
592 | | * ? |
593 | | * |
594 | | * If so, set *found and abort the search. |
595 | | */ |
596 | | static isl_stat is_isolate(__isl_take isl_set *set, void *user) |
597 | 107 | { |
598 | 107 | int *found = user; |
599 | 107 | |
600 | 107 | if (isl_set_has_tuple_name(set)) { |
601 | 85 | const char *name; |
602 | 85 | name = isl_set_get_tuple_name(set); |
603 | 85 | if (isl_set_is_wrapping(set) && !strcmp(name, "isolate")65 ) |
604 | 65 | *found = 1; |
605 | 85 | } |
606 | 107 | isl_set_free(set); |
607 | 107 | |
608 | 107 | return *found ? isl_stat_error65 : isl_stat_ok42 ; |
609 | 107 | } |
610 | | |
611 | | /* Does "options" include an option of the ofrm |
612 | | * |
613 | | * isolate[[...] -> [...]] |
614 | | * |
615 | | * ? |
616 | | */ |
617 | | static int has_isolate_option(__isl_keep isl_union_set *options) |
618 | 130 | { |
619 | 130 | return has_any(options, &is_isolate); |
620 | 130 | } |
621 | | |
622 | | /* Does "set" encode a loop AST generation option? |
623 | | */ |
624 | | static isl_stat is_loop_type_option(__isl_take isl_set *set, void *user) |
625 | 164 | { |
626 | 164 | int *found = user; |
627 | 164 | |
628 | 164 | if (isl_set_dim(set, isl_dim_set) == 1 && |
629 | 164 | isl_set_has_tuple_name(set)103 ) { |
630 | 81 | const char *name; |
631 | 81 | enum isl_ast_loop_type type; |
632 | 81 | name = isl_set_get_tuple_name(set); |
633 | 81 | for (type = isl_ast_loop_atomic; |
634 | 169 | type <= isl_ast_loop_separate; ++type88 ) { |
635 | 169 | if (strcmp(name, option_str[type])) |
636 | 88 | continue; |
637 | 81 | *found = 1; |
638 | 81 | break; |
639 | 81 | } |
640 | 81 | } |
641 | 164 | isl_set_free(set); |
642 | 164 | |
643 | 164 | return *found ? isl_stat_error81 : isl_stat_ok83 ; |
644 | 164 | } |
645 | | |
646 | | /* Does "set" encode a loop AST generation option for the isolated part? |
647 | | * That is, is of the form |
648 | | * |
649 | | * { [isolate[] -> t[x]] } |
650 | | * |
651 | | * with t equal to "atomic", "unroll" or "separate"? |
652 | | */ |
653 | | static isl_stat is_isolate_loop_type_option(__isl_take isl_set *set, void *user) |
654 | 126 | { |
655 | 126 | int *found = user; |
656 | 126 | const char *name; |
657 | 126 | enum isl_ast_loop_type type; |
658 | 126 | isl_map *map; |
659 | 126 | |
660 | 126 | if (!isl_set_is_wrapping(set)) { |
661 | 59 | isl_set_free(set); |
662 | 59 | return isl_stat_ok; |
663 | 59 | } |
664 | 67 | map = isl_set_unwrap(set); |
665 | 67 | if (!isl_map_has_tuple_name(map, isl_dim_in) || |
666 | 67 | !isl_map_has_tuple_name(map, isl_dim_out)24 ) { |
667 | 43 | isl_map_free(map); |
668 | 43 | return isl_stat_ok; |
669 | 43 | } |
670 | 24 | name = isl_map_get_tuple_name(map, isl_dim_in); |
671 | 24 | if (!strcmp(name, "isolate")) { |
672 | 24 | name = isl_map_get_tuple_name(map, isl_dim_out); |
673 | 24 | for (type = isl_ast_loop_atomic; |
674 | 48 | type <= isl_ast_loop_separate; ++type24 ) { |
675 | 48 | if (strcmp(name, option_str[type])) |
676 | 24 | continue; |
677 | 24 | *found = 1; |
678 | 24 | break; |
679 | 24 | } |
680 | 24 | } |
681 | 24 | isl_map_free(map); |
682 | 24 | |
683 | 24 | return *found ? isl_stat_error : isl_stat_ok0 ; |
684 | 24 | } |
685 | | |
686 | | /* Does "options" encode any loop AST generation options |
687 | | * for the isolated part? |
688 | | */ |
689 | | static int has_isolate_loop_type_options(__isl_keep isl_union_set *options) |
690 | 130 | { |
691 | 130 | return has_any(options, &is_isolate_loop_type_option); |
692 | 130 | } |
693 | | |
694 | | /* Does "options" encode any loop AST generation options? |
695 | | */ |
696 | | static int has_loop_type_options(__isl_keep isl_union_set *options) |
697 | 130 | { |
698 | 130 | return has_any(options, &is_loop_type_option); |
699 | 130 | } |
700 | | |
701 | | /* Extract the loop AST generation type for the band member |
702 | | * at position "pos" from "options". |
703 | | * If "isolate" is set, then extract the loop types for the isolated part. |
704 | | */ |
705 | | static enum isl_ast_loop_type extract_loop_type( |
706 | | __isl_keep isl_union_set *options, int pos, int isolate) |
707 | 279 | { |
708 | 279 | isl_ctx *ctx; |
709 | 279 | enum isl_ast_loop_type type, res = isl_ast_loop_default; |
710 | 279 | |
711 | 279 | ctx = isl_union_set_get_ctx(options); |
712 | 279 | for (type = isl_ast_loop_atomic; |
713 | 1.11k | type <= isl_ast_loop_separate; ++type837 ) { |
714 | 837 | isl_space *space; |
715 | 837 | isl_set *option; |
716 | 837 | int empty; |
717 | 837 | |
718 | 837 | space = isl_union_set_get_space(options); |
719 | 837 | space = loop_type_space(space, type, isolate); |
720 | 837 | option = isl_union_set_extract_set(options, space); |
721 | 837 | option = isl_set_fix_si(option, isl_dim_set, 0, pos); |
722 | 837 | empty = isl_set_is_empty(option); |
723 | 837 | isl_set_free(option); |
724 | 837 | |
725 | 837 | if (empty < 0) |
726 | 0 | return isl_ast_loop_error; |
727 | 837 | if (empty) |
728 | 558 | continue; |
729 | 279 | if (res != isl_ast_loop_default) |
730 | 279 | isl_die0 (ctx, isl_error_invalid, |
731 | 279 | "conflicting loop type options", |
732 | 279 | return isl_ast_loop_error); |
733 | 279 | res = type; |
734 | 279 | } |
735 | 279 | |
736 | 279 | return res; |
737 | 279 | } |
738 | | |
739 | | /* Extract the loop AST generation types for the members of "band" |
740 | | * from "options" and store them in band->loop_type. |
741 | | * Return -1 on error. |
742 | | */ |
743 | | static int extract_loop_types(__isl_keep isl_schedule_band *band, |
744 | | __isl_keep isl_union_set *options) |
745 | 81 | { |
746 | 81 | int i; |
747 | 81 | |
748 | 81 | if (!band->loop_type) { |
749 | 68 | isl_ctx *ctx = isl_schedule_band_get_ctx(band); |
750 | 68 | band->loop_type = isl_alloc_array(ctx, |
751 | 68 | enum isl_ast_loop_type, band->n); |
752 | 68 | if (band->n && !band->loop_type) |
753 | 0 | return -1; |
754 | 81 | } |
755 | 288 | for (i = 0; 81 i < band->n; ++i207 ) { |
756 | 207 | band->loop_type[i] = extract_loop_type(options, i, 0); |
757 | 207 | if (band->loop_type[i] == isl_ast_loop_error) |
758 | 0 | return -1; |
759 | 207 | } |
760 | 81 | |
761 | 81 | return 0; |
762 | 81 | } |
763 | | |
764 | | /* Extract the loop AST generation types for the members of "band" |
765 | | * from "options" for the isolated part and |
766 | | * store them in band->isolate_loop_type. |
767 | | * Return -1 on error. |
768 | | */ |
769 | | static int extract_isolate_loop_types(__isl_keep isl_schedule_band *band, |
770 | | __isl_keep isl_union_set *options) |
771 | 24 | { |
772 | 24 | int i; |
773 | 24 | |
774 | 24 | if (!band->isolate_loop_type) { |
775 | 24 | isl_ctx *ctx = isl_schedule_band_get_ctx(band); |
776 | 24 | band->isolate_loop_type = isl_alloc_array(ctx, |
777 | 24 | enum isl_ast_loop_type, band->n); |
778 | 24 | if (band->n && !band->isolate_loop_type) |
779 | 0 | return -1; |
780 | 24 | } |
781 | 96 | for (i = 0; 24 i < band->n; ++i72 ) { |
782 | 72 | band->isolate_loop_type[i] = extract_loop_type(options, i, 1); |
783 | 72 | if (band->isolate_loop_type[i] == isl_ast_loop_error) |
784 | 0 | return -1; |
785 | 72 | } |
786 | 24 | |
787 | 24 | return 0; |
788 | 24 | } |
789 | | |
790 | | /* Construct universe sets of the spaces that encode loop AST generation |
791 | | * types (for the isolated part if "isolate" is set). That is, construct |
792 | | * |
793 | | * { atomic[x]; separate[x]; unroll[x] } |
794 | | * |
795 | | * or |
796 | | * |
797 | | * { [isolate[] -> atomic[x]]; [isolate[] -> separate[x]]; |
798 | | * [isolate[] -> unroll[x]] } |
799 | | */ |
800 | | static __isl_give isl_union_set *loop_types(__isl_take isl_space *space, |
801 | | int isolate) |
802 | 105 | { |
803 | 105 | enum isl_ast_loop_type type; |
804 | 105 | isl_union_set *types; |
805 | 105 | |
806 | 105 | types = isl_union_set_empty(space); |
807 | 105 | for (type = isl_ast_loop_atomic; |
808 | 420 | type <= isl_ast_loop_separate; ++type315 ) { |
809 | 315 | isl_set *set; |
810 | 315 | |
811 | 315 | space = isl_union_set_get_space(types); |
812 | 315 | space = loop_type_space(space, type, isolate); |
813 | 315 | set = isl_set_universe(space); |
814 | 315 | types = isl_union_set_add_set(types, set); |
815 | 315 | } |
816 | 105 | |
817 | 105 | return types; |
818 | 105 | } |
819 | | |
820 | | /* Remove all elements from spaces that encode loop AST generation types |
821 | | * from "options". |
822 | | */ |
823 | | static __isl_give isl_union_set *clear_loop_types( |
824 | | __isl_take isl_union_set *options) |
825 | 81 | { |
826 | 81 | isl_union_set *types; |
827 | 81 | |
828 | 81 | types = loop_types(isl_union_set_get_space(options), 0); |
829 | 81 | options = isl_union_set_subtract(options, types); |
830 | 81 | |
831 | 81 | return options; |
832 | 81 | } |
833 | | |
834 | | /* Remove all elements from spaces that encode loop AST generation types |
835 | | * for the isolated part from "options". |
836 | | */ |
837 | | static __isl_give isl_union_set *clear_isolate_loop_types( |
838 | | __isl_take isl_union_set *options) |
839 | 24 | { |
840 | 24 | isl_union_set *types; |
841 | 24 | |
842 | 24 | types = loop_types(isl_union_set_get_space(options), 1); |
843 | 24 | options = isl_union_set_subtract(options, types); |
844 | 24 | |
845 | 24 | return options; |
846 | 24 | } |
847 | | |
848 | | /* Replace the AST build options associated to "band" by "options". |
849 | | * If there are any loop AST generation type options, then they |
850 | | * are extracted and stored in band->loop_type. Otherwise, |
851 | | * band->loop_type is removed to indicate that the default applies |
852 | | * to all members. Similarly for the loop AST generation type options |
853 | | * for the isolated part, which are stored in band->isolate_loop_type. |
854 | | * The remaining options are stored in band->ast_build_options. |
855 | | * |
856 | | * Set anchored if the options include an isolate option since the |
857 | | * domain of the wrapped map references the outer band node schedules. |
858 | | */ |
859 | | __isl_give isl_schedule_band *isl_schedule_band_set_ast_build_options( |
860 | | __isl_take isl_schedule_band *band, __isl_take isl_union_set *options) |
861 | 130 | { |
862 | 130 | int has_isolate, has_loop_type, has_isolate_loop_type; |
863 | 130 | |
864 | 130 | band = isl_schedule_band_cow(band); |
865 | 130 | if (!band || !options) |
866 | 0 | goto error; |
867 | 130 | has_isolate = has_isolate_option(options); |
868 | 130 | if (has_isolate < 0) |
869 | 0 | goto error; |
870 | 130 | has_loop_type = has_loop_type_options(options); |
871 | 130 | if (has_loop_type < 0) |
872 | 0 | goto error; |
873 | 130 | has_isolate_loop_type = has_isolate_loop_type_options(options); |
874 | 130 | if (has_isolate_loop_type < 0) |
875 | 0 | goto error; |
876 | 130 | |
877 | 130 | if (!has_loop_type) { |
878 | 49 | free(band->loop_type); |
879 | 49 | band->loop_type = NULL; |
880 | 81 | } else { |
881 | 81 | if (extract_loop_types(band, options) < 0) |
882 | 0 | goto error; |
883 | 81 | options = clear_loop_types(options); |
884 | 81 | if (!options) |
885 | 0 | goto error; |
886 | 130 | } |
887 | 130 | |
888 | 130 | if (!has_isolate_loop_type) { |
889 | 106 | free(band->isolate_loop_type); |
890 | 106 | band->isolate_loop_type = NULL; |
891 | 106 | } else { |
892 | 24 | if (extract_isolate_loop_types(band, options) < 0) |
893 | 0 | goto error; |
894 | 24 | options = clear_isolate_loop_types(options); |
895 | 24 | if (!options) |
896 | 0 | goto error; |
897 | 130 | } |
898 | 130 | |
899 | 130 | isl_union_set_free(band->ast_build_options); |
900 | 130 | band->ast_build_options = options; |
901 | 130 | band->anchored = has_isolate; |
902 | 130 | |
903 | 130 | return band; |
904 | 0 | error: |
905 | 0 | isl_schedule_band_free(band); |
906 | 0 | isl_union_set_free(options); |
907 | 0 | return NULL; |
908 | 130 | } |
909 | | |
910 | | /* Return the "isolate" option associated to "band", assuming |
911 | | * it at appears at schedule depth "depth". |
912 | | * |
913 | | * The isolate option is of the form |
914 | | * |
915 | | * isolate[[flattened outer bands] -> band] |
916 | | */ |
917 | | __isl_give isl_set *isl_schedule_band_get_ast_isolate_option( |
918 | | __isl_keep isl_schedule_band *band, int depth) |
919 | 2.49k | { |
920 | 2.49k | isl_space *space; |
921 | 2.49k | isl_set *isolate; |
922 | 2.49k | |
923 | 2.49k | if (!band) |
924 | 0 | return NULL; |
925 | 2.49k | |
926 | 2.49k | space = isl_schedule_band_get_space(band); |
927 | 2.49k | space = isl_space_from_range(space); |
928 | 2.49k | space = isl_space_add_dims(space, isl_dim_in, depth); |
929 | 2.49k | space = isl_space_wrap(space); |
930 | 2.49k | space = isl_space_set_tuple_name(space, isl_dim_set, "isolate"); |
931 | 2.49k | |
932 | 2.49k | isolate = isl_union_set_extract_set(band->ast_build_options, space); |
933 | 2.49k | |
934 | 2.49k | return isolate; |
935 | 2.49k | } |
936 | | |
937 | | /* Replace the option "drop" in the AST build options by "add". |
938 | | * That is, remove "drop" and add "add". |
939 | | */ |
940 | | __isl_give isl_schedule_band *isl_schedule_band_replace_ast_build_option( |
941 | | __isl_take isl_schedule_band *band, __isl_take isl_set *drop, |
942 | | __isl_take isl_set *add) |
943 | 72 | { |
944 | 72 | isl_union_set *options; |
945 | 72 | |
946 | 72 | band = isl_schedule_band_cow(band); |
947 | 72 | if (!band) |
948 | 0 | goto error; |
949 | 72 | |
950 | 72 | options = band->ast_build_options; |
951 | 72 | options = isl_union_set_subtract(options, isl_union_set_from_set(drop)); |
952 | 72 | options = isl_union_set_union(options, isl_union_set_from_set(add)); |
953 | 72 | band->ast_build_options = options; |
954 | 72 | |
955 | 72 | if (!band->ast_build_options) |
956 | 0 | return isl_schedule_band_free(band); |
957 | 72 | |
958 | 72 | return band; |
959 | 0 | error: |
960 | 0 | isl_schedule_band_free(band); |
961 | 0 | isl_set_free(drop); |
962 | 0 | isl_set_free(add); |
963 | 0 | return NULL; |
964 | 72 | } |
965 | | |
966 | | /* Multiply the partial schedule of "band" with the factors in "mv". |
967 | | * Replace the result by its greatest integer part to ensure |
968 | | * that the schedule is always integral. |
969 | | */ |
970 | | __isl_give isl_schedule_band *isl_schedule_band_scale( |
971 | | __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv) |
972 | 0 | { |
973 | 0 | band = isl_schedule_band_cow(band); |
974 | 0 | if (!band || !mv) |
975 | 0 | goto error; |
976 | 0 | band->mupa = isl_multi_union_pw_aff_scale_multi_val(band->mupa, mv); |
977 | 0 | band->mupa = isl_multi_union_pw_aff_floor(band->mupa); |
978 | 0 | if (!band->mupa) |
979 | 0 | return isl_schedule_band_free(band); |
980 | 0 | return band; |
981 | 0 | error: |
982 | 0 | isl_schedule_band_free(band); |
983 | 0 | isl_multi_val_free(mv); |
984 | 0 | return NULL; |
985 | 0 | } |
986 | | |
987 | | /* Divide the partial schedule of "band" by the factors in "mv". |
988 | | * Replace the result by its greatest integer part to ensure |
989 | | * that the schedule is always integral. |
990 | | */ |
991 | | __isl_give isl_schedule_band *isl_schedule_band_scale_down( |
992 | | __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv) |
993 | 0 | { |
994 | 0 | band = isl_schedule_band_cow(band); |
995 | 0 | if (!band || !mv) |
996 | 0 | goto error; |
997 | 0 | band->mupa = isl_multi_union_pw_aff_scale_down_multi_val(band->mupa, |
998 | 0 | mv); |
999 | 0 | band->mupa = isl_multi_union_pw_aff_floor(band->mupa); |
1000 | 0 | if (!band->mupa) |
1001 | 0 | return isl_schedule_band_free(band); |
1002 | 0 | return band; |
1003 | 0 | error: |
1004 | 0 | isl_schedule_band_free(band); |
1005 | 0 | isl_multi_val_free(mv); |
1006 | 0 | return NULL; |
1007 | 0 | } |
1008 | | |
1009 | | /* Reduce the partial schedule of "band" modulo the factors in "mv". |
1010 | | */ |
1011 | | __isl_give isl_schedule_band *isl_schedule_band_mod( |
1012 | | __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv) |
1013 | 0 | { |
1014 | 0 | band = isl_schedule_band_cow(band); |
1015 | 0 | if (!band || !mv) |
1016 | 0 | goto error; |
1017 | 0 | band->mupa = isl_multi_union_pw_aff_mod_multi_val(band->mupa, mv); |
1018 | 0 | if (!band->mupa) |
1019 | 0 | return isl_schedule_band_free(band); |
1020 | 0 | return band; |
1021 | 0 | error: |
1022 | 0 | isl_schedule_band_free(band); |
1023 | 0 | isl_multi_val_free(mv); |
1024 | 0 | return NULL; |
1025 | 0 | } |
1026 | | |
1027 | | /* Shift the partial schedule of "band" by "shift" after checking |
1028 | | * that the domain of the partial schedule would not be affected |
1029 | | * by this shift. |
1030 | | */ |
1031 | | __isl_give isl_schedule_band *isl_schedule_band_shift( |
1032 | | __isl_take isl_schedule_band *band, |
1033 | | __isl_take isl_multi_union_pw_aff *shift) |
1034 | 0 | { |
1035 | 0 | isl_union_set *dom1, *dom2; |
1036 | 0 | isl_bool subset; |
1037 | 0 |
|
1038 | 0 | band = isl_schedule_band_cow(band); |
1039 | 0 | if (!band || !shift) |
1040 | 0 | goto error; |
1041 | 0 | dom1 = isl_multi_union_pw_aff_domain( |
1042 | 0 | isl_multi_union_pw_aff_copy(band->mupa)); |
1043 | 0 | dom2 = isl_multi_union_pw_aff_domain( |
1044 | 0 | isl_multi_union_pw_aff_copy(shift)); |
1045 | 0 | subset = isl_union_set_is_subset(dom1, dom2); |
1046 | 0 | isl_union_set_free(dom1); |
1047 | 0 | isl_union_set_free(dom2); |
1048 | 0 | if (subset < 0) |
1049 | 0 | goto error; |
1050 | 0 | if (!subset) |
1051 | 0 | isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, |
1052 | 0 | "domain of shift needs to include domain of " |
1053 | 0 | "partial schedule", goto error); |
1054 | 0 | band->mupa = isl_multi_union_pw_aff_add(band->mupa, shift); |
1055 | 0 | if (!band->mupa) |
1056 | 0 | return isl_schedule_band_free(band); |
1057 | 0 | return band; |
1058 | 0 | error: |
1059 | 0 | isl_schedule_band_free(band); |
1060 | 0 | isl_multi_union_pw_aff_free(shift); |
1061 | 0 | return NULL; |
1062 | 0 | } |
1063 | | |
1064 | | /* Given the schedule of a band, construct the corresponding |
1065 | | * schedule for the tile loops based on the given tile sizes |
1066 | | * and return the result. |
1067 | | * |
1068 | | * If the scale tile loops options is set, then the tile loops |
1069 | | * are scaled by the tile sizes. |
1070 | | * |
1071 | | * That is replace each schedule dimension "i" by either |
1072 | | * "floor(i/s)" or "s * floor(i/s)". |
1073 | | */ |
1074 | | static isl_multi_union_pw_aff *isl_multi_union_pw_aff_tile( |
1075 | | __isl_take isl_multi_union_pw_aff *sched, |
1076 | | __isl_take isl_multi_val *sizes) |
1077 | 80 | { |
1078 | 80 | isl_ctx *ctx; |
1079 | 80 | int i, n; |
1080 | 80 | isl_val *v; |
1081 | 80 | int scale; |
1082 | 80 | |
1083 | 80 | ctx = isl_multi_val_get_ctx(sizes); |
1084 | 80 | scale = isl_options_get_tile_scale_tile_loops(ctx); |
1085 | 80 | |
1086 | 80 | n = isl_multi_union_pw_aff_dim(sched, isl_dim_set); |
1087 | 256 | for (i = 0; i < n; ++i176 ) { |
1088 | 176 | isl_union_pw_aff *upa; |
1089 | 176 | |
1090 | 176 | upa = isl_multi_union_pw_aff_get_union_pw_aff(sched, i); |
1091 | 176 | v = isl_multi_val_get_val(sizes, i); |
1092 | 176 | |
1093 | 176 | upa = isl_union_pw_aff_scale_down_val(upa, isl_val_copy(v)); |
1094 | 176 | upa = isl_union_pw_aff_floor(upa); |
1095 | 176 | if (scale) |
1096 | 4 | upa = isl_union_pw_aff_scale_val(upa, isl_val_copy(v)); |
1097 | 176 | isl_val_free(v); |
1098 | 176 | |
1099 | 176 | sched = isl_multi_union_pw_aff_set_union_pw_aff(sched, i, upa); |
1100 | 176 | } |
1101 | 80 | |
1102 | 80 | isl_multi_val_free(sizes); |
1103 | 80 | return sched; |
1104 | 80 | } |
1105 | | |
1106 | | /* Replace "band" by a band corresponding to the tile loops of a tiling |
1107 | | * with the given tile sizes. |
1108 | | */ |
1109 | | __isl_give isl_schedule_band *isl_schedule_band_tile( |
1110 | | __isl_take isl_schedule_band *band, __isl_take isl_multi_val *sizes) |
1111 | 80 | { |
1112 | 80 | band = isl_schedule_band_cow(band); |
1113 | 80 | if (!band || !sizes) |
1114 | 0 | goto error; |
1115 | 80 | band->mupa = isl_multi_union_pw_aff_tile(band->mupa, sizes); |
1116 | 80 | if (!band->mupa) |
1117 | 0 | return isl_schedule_band_free(band); |
1118 | 80 | return band; |
1119 | 0 | error: |
1120 | 0 | isl_schedule_band_free(band); |
1121 | 0 | isl_multi_val_free(sizes); |
1122 | 0 | return NULL; |
1123 | 80 | } |
1124 | | |
1125 | | /* Replace "band" by a band corresponding to the point loops of a tiling |
1126 | | * with the given tile sizes. |
1127 | | * "tile" is the corresponding tile loop band. |
1128 | | * |
1129 | | * If the shift point loops option is set, then the point loops |
1130 | | * are shifted to start at zero. That is, each schedule dimension "i" |
1131 | | * is replaced by "i - s * floor(i/s)". |
1132 | | * The expression "floor(i/s)" (or "s * floor(i/s)") is extracted from |
1133 | | * the tile band. |
1134 | | * |
1135 | | * Otherwise, the band is left untouched. |
1136 | | */ |
1137 | | __isl_give isl_schedule_band *isl_schedule_band_point( |
1138 | | __isl_take isl_schedule_band *band, __isl_keep isl_schedule_band *tile, |
1139 | | __isl_take isl_multi_val *sizes) |
1140 | 80 | { |
1141 | 80 | isl_ctx *ctx; |
1142 | 80 | isl_multi_union_pw_aff *scaled; |
1143 | 80 | |
1144 | 80 | if (!band || !sizes) |
1145 | 0 | goto error; |
1146 | 80 | |
1147 | 80 | ctx = isl_schedule_band_get_ctx(band); |
1148 | 80 | if (!isl_options_get_tile_shift_point_loops(ctx)) { |
1149 | 2 | isl_multi_val_free(sizes); |
1150 | 2 | return band; |
1151 | 2 | } |
1152 | 78 | band = isl_schedule_band_cow(band); |
1153 | 78 | if (!band) |
1154 | 0 | goto error; |
1155 | 78 | |
1156 | 78 | scaled = isl_schedule_band_get_partial_schedule(tile); |
1157 | 78 | if (!isl_options_get_tile_scale_tile_loops(ctx)) |
1158 | 77 | scaled = isl_multi_union_pw_aff_scale_multi_val(scaled, sizes); |
1159 | 1 | else |
1160 | 1 | isl_multi_val_free(sizes); |
1161 | 78 | band->mupa = isl_multi_union_pw_aff_sub(band->mupa, scaled); |
1162 | 78 | if (!band->mupa) |
1163 | 0 | return isl_schedule_band_free(band); |
1164 | 78 | return band; |
1165 | 0 | error: |
1166 | 0 | isl_schedule_band_free(band); |
1167 | 0 | isl_multi_val_free(sizes); |
1168 | 0 | return NULL; |
1169 | 78 | } |
1170 | | |
1171 | | /* Drop the "n" dimensions starting at "pos" from "band". |
1172 | | * |
1173 | | * We apply the transformation even if "n" is zero to ensure consistent |
1174 | | * behavior with respect to changes in the schedule space. |
1175 | | * |
1176 | | * The caller is responsible for updating the isolate option. |
1177 | | */ |
1178 | | __isl_give isl_schedule_band *isl_schedule_band_drop( |
1179 | | __isl_take isl_schedule_band *band, int pos, int n) |
1180 | 72 | { |
1181 | 72 | int i; |
1182 | 72 | |
1183 | 72 | if (pos < 0 || n < 0 || pos + n > band->n) |
1184 | 72 | isl_die0 (isl_schedule_band_get_ctx(band), isl_error_internal, |
1185 | 72 | "range out of bounds", |
1186 | 72 | return isl_schedule_band_free(band)); |
1187 | 72 | |
1188 | 72 | band = isl_schedule_band_cow(band); |
1189 | 72 | if (!band) |
1190 | 0 | return NULL; |
1191 | 72 | |
1192 | 72 | band->mupa = isl_multi_union_pw_aff_drop_dims(band->mupa, |
1193 | 72 | isl_dim_set, pos, n); |
1194 | 72 | if (!band->mupa) |
1195 | 0 | return isl_schedule_band_free(band); |
1196 | 72 | |
1197 | 115 | for (i = pos + n; 72 i < band->n; ++i43 ) |
1198 | 43 | band->coincident[i - n] = band->coincident[i]; |
1199 | 72 | if (band->loop_type) |
1200 | 3 | for (i = pos + n; 2 i < band->n; ++i1 ) |
1201 | 1 | band->loop_type[i - n] = band->loop_type[i]; |
1202 | 72 | if (band->isolate_loop_type) |
1203 | 0 | for (i = pos + n; i < band->n; ++i) |
1204 | 0 | band->isolate_loop_type[i - n] = |
1205 | 0 | band->isolate_loop_type[i]; |
1206 | 72 | |
1207 | 72 | band->n -= n; |
1208 | 72 | |
1209 | 72 | return band; |
1210 | 72 | } |
1211 | | |
1212 | | /* Reset the user pointer on all identifiers of parameters and tuples |
1213 | | * in "band". |
1214 | | */ |
1215 | | __isl_give isl_schedule_band *isl_schedule_band_reset_user( |
1216 | | __isl_take isl_schedule_band *band) |
1217 | 0 | { |
1218 | 0 | band = isl_schedule_band_cow(band); |
1219 | 0 | if (!band) |
1220 | 0 | return NULL; |
1221 | 0 | |
1222 | 0 | band->mupa = isl_multi_union_pw_aff_reset_user(band->mupa); |
1223 | 0 | band->ast_build_options = |
1224 | 0 | isl_union_set_reset_user(band->ast_build_options); |
1225 | 0 | if (!band->mupa || !band->ast_build_options) |
1226 | 0 | return isl_schedule_band_free(band); |
1227 | 0 | |
1228 | 0 | return band; |
1229 | 0 | } |
1230 | | |
1231 | | /* Align the parameters of "band" to those of "space". |
1232 | | */ |
1233 | | __isl_give isl_schedule_band *isl_schedule_band_align_params( |
1234 | | __isl_take isl_schedule_band *band, __isl_take isl_space *space) |
1235 | 0 | { |
1236 | 0 | band = isl_schedule_band_cow(band); |
1237 | 0 | if (!band || !space) |
1238 | 0 | goto error; |
1239 | 0 | |
1240 | 0 | band->mupa = isl_multi_union_pw_aff_align_params(band->mupa, |
1241 | 0 | isl_space_copy(space)); |
1242 | 0 | band->ast_build_options = |
1243 | 0 | isl_union_set_align_params(band->ast_build_options, space); |
1244 | 0 | if (!band->mupa || !band->ast_build_options) |
1245 | 0 | return isl_schedule_band_free(band); |
1246 | 0 | |
1247 | 0 | return band; |
1248 | 0 | error: |
1249 | 0 | isl_space_free(space); |
1250 | 0 | isl_schedule_band_free(band); |
1251 | 0 | return NULL; |
1252 | 0 | } |
1253 | | |
1254 | | /* Compute the pullback of "band" by the function represented by "upma". |
1255 | | * In other words, plug in "upma" in the iteration domains of "band". |
1256 | | */ |
1257 | | __isl_give isl_schedule_band *isl_schedule_band_pullback_union_pw_multi_aff( |
1258 | | __isl_take isl_schedule_band *band, |
1259 | | __isl_take isl_union_pw_multi_aff *upma) |
1260 | 322 | { |
1261 | 322 | band = isl_schedule_band_cow(band); |
1262 | 322 | if (!band || !upma) |
1263 | 0 | goto error; |
1264 | 322 | |
1265 | 322 | band->mupa = |
1266 | 322 | isl_multi_union_pw_aff_pullback_union_pw_multi_aff(band->mupa, |
1267 | 322 | upma); |
1268 | 322 | if (!band->mupa) |
1269 | 0 | return isl_schedule_band_free(band); |
1270 | 322 | |
1271 | 322 | return band; |
1272 | 0 | error: |
1273 | 0 | isl_union_pw_multi_aff_free(upma); |
1274 | 0 | isl_schedule_band_free(band); |
1275 | 0 | return NULL; |
1276 | 322 | } |
1277 | | |
1278 | | /* Compute the gist of "band" with respect to "context". |
1279 | | * In particular, compute the gist of the associated partial schedule. |
1280 | | */ |
1281 | | __isl_give isl_schedule_band *isl_schedule_band_gist( |
1282 | | __isl_take isl_schedule_band *band, __isl_take isl_union_set *context) |
1283 | 315 | { |
1284 | 315 | if (!band || !context) |
1285 | 0 | goto error; |
1286 | 315 | if (band->n == 0) { |
1287 | 0 | isl_union_set_free(context); |
1288 | 0 | return band; |
1289 | 0 | } |
1290 | 315 | band = isl_schedule_band_cow(band); |
1291 | 315 | if (!band) |
1292 | 0 | goto error; |
1293 | 315 | band->mupa = isl_multi_union_pw_aff_gist(band->mupa, context); |
1294 | 315 | if (!band->mupa) |
1295 | 0 | return isl_schedule_band_free(band); |
1296 | 315 | return band; |
1297 | 0 | error: |
1298 | 0 | isl_union_set_free(context); |
1299 | 0 | isl_schedule_band_free(band); |
1300 | 0 | return NULL; |
1301 | 315 | } |