pet_expr_filter: avoid introduction of constraints in index expression
[pet.git] / context.c
blobcb4fb26bc5a3d89ffecd64adb4fa7fba3d01eb1f
1 /*
2 * Copyright 2011 Leiden University. All rights reserved.
3 * Copyright 2014 Ecole Normale Superieure. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials provided
15 * with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY LEIDEN UNIVERSITY ''AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LEIDEN UNIVERSITY OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * The views and conclusions contained in the software and documentation
30 * are those of the authors and should not be interpreted as
31 * representing official policies, either expressed or implied, of
32 * Leiden University.
35 #include <isl/aff.h>
37 #include "context.h"
38 #include "expr.h"
39 #include "nest.h"
41 /* A pet_context represents the context in which a pet_expr
42 * in converted to an affine expression.
44 * "domain" prescribes the domain of the affine expressions.
46 * "assignments" maps variable names to their currently known values.
47 * The domains of the values are equal to the space of "domain".
48 * If a variable has been assigned an unknown value (possibly because
49 * it may be assigned a different expression in each iteration) or a value
50 * that is not an affine expression, then the corresponding isl_pw_aff
51 * is set to NaN.
53 * If "allow_nested" is set, then the affine expression created
54 * in this context may involve new parameters that encode a pet_expr.
56 struct pet_context {
57 int ref;
59 isl_set *domain;
60 isl_id_to_pw_aff *assignments;
61 int allow_nested;
64 /* Create a pet_context with the given domain, assignments,
65 * and value for allow_nested.
67 static __isl_give pet_context *context_alloc(__isl_take isl_set *domain,
68 __isl_take isl_id_to_pw_aff *assignments, int allow_nested)
70 pet_context *pc;
72 if (!domain || !assignments)
73 goto error;
75 pc = isl_calloc_type(isl_set_get_ctx(domain), struct pet_context);
76 if (!pc)
77 goto error;
79 pc->ref = 1;
80 pc->domain = domain;
81 pc->assignments = assignments;
82 pc->allow_nested = allow_nested;
84 return pc;
85 error:
86 isl_set_free(domain);
87 isl_id_to_pw_aff_free(assignments);
88 return NULL;
91 /* Create a pet_context with the given domain.
93 * Initially, there are no assigned values and parameters that
94 * encode a pet_expr are not allowed.
96 __isl_give pet_context *pet_context_alloc(__isl_take isl_set *domain)
98 isl_id_to_pw_aff *assignments;
100 if (!domain)
101 return NULL;
103 assignments = isl_id_to_pw_aff_alloc(isl_set_get_ctx(domain), 0);;
104 return context_alloc(domain, assignments, 0);
107 /* Return an independent duplicate of "pc".
109 static __isl_give pet_context *pet_context_dup(__isl_keep pet_context *pc)
111 pet_context *dup;
113 if (!pc)
114 return NULL;
116 dup = context_alloc(isl_set_copy(pc->domain),
117 isl_id_to_pw_aff_copy(pc->assignments),
118 pc->allow_nested);
120 return dup;
123 /* Return a pet_context that is equal to "pc" and that has only one reference.
125 static __isl_give pet_context *pet_context_cow(__isl_take pet_context *pc)
127 if (!pc)
128 return NULL;
130 if (pc->ref == 1)
131 return pc;
132 pc->ref--;
133 return pet_context_dup(pc);
136 /* Return an extra reference to "pc".
138 __isl_give pet_context *pet_context_copy(__isl_keep pet_context *pc)
140 if (!pc)
141 return NULL;
143 pc->ref++;
144 return pc;
147 /* Free a reference to "pc" and return NULL.
149 __isl_null pet_context *pet_context_free(__isl_take pet_context *pc)
151 if (!pc)
152 return NULL;
153 if (--pc->ref > 0)
154 return NULL;
156 isl_set_free(pc->domain);
157 isl_id_to_pw_aff_free(pc->assignments);
158 free(pc);
159 return NULL;
162 /* Return the isl_ctx in which "pc" was created.
164 isl_ctx *pet_context_get_ctx(__isl_keep pet_context *pc)
166 return pc ? isl_set_get_ctx(pc->domain) : NULL;
169 /* Return the domain of "pc".
171 __isl_give isl_set *pet_context_get_domain(__isl_keep pet_context *pc)
173 if (!pc)
174 return NULL;
175 return isl_set_copy(pc->domain);
178 /* Return the domain space of "pc".
180 * The domain of "pc" may have constraints involving parameters
181 * that encode a pet_expr. These parameters are not relevant
182 * outside this domain. Furthermore, they need to be resolved
183 * from the final result, so we do not want to propagate them needlessly.
185 __isl_give isl_space *pet_context_get_space(__isl_keep pet_context *pc)
187 isl_space *space;
189 if (!pc)
190 return NULL;
192 space = isl_set_get_space(pc->domain);
193 space = pet_nested_remove_from_space(space);
194 return space;
197 /* Return the dimension of the domain space of "pc".
199 unsigned pet_context_dim(__isl_keep pet_context *pc)
201 if (!pc)
202 return 0;
203 return isl_set_dim(pc->domain, isl_dim_set);
206 /* Return the assignments of "pc".
208 __isl_give isl_id_to_pw_aff *pet_context_get_assignments(
209 __isl_keep pet_context *pc)
211 if (!pc)
212 return NULL;
213 return isl_id_to_pw_aff_copy(pc->assignments);
216 /* Is "id" assigned any value in "pc"?
218 int pet_context_is_assigned(__isl_keep pet_context *pc, __isl_keep isl_id *id)
220 if (!pc || !id)
221 return -1;
222 return isl_id_to_pw_aff_has(pc->assignments, id);
225 /* Return the value assigned to "id" in "pc".
227 __isl_give isl_pw_aff *pet_context_get_value(__isl_keep pet_context *pc,
228 __isl_take isl_id *id)
230 if (!pc || !id)
231 goto error;
233 return isl_id_to_pw_aff_get(pc->assignments, id);
234 error:
235 isl_id_free(id);
236 return NULL;
239 /* Assign the value "value" to "id" in "pc", replacing the previously
240 * assigned value, if any.
242 __isl_give pet_context *pet_context_set_value(__isl_take pet_context *pc,
243 __isl_take isl_id *id, isl_pw_aff *value)
245 pc = pet_context_cow(pc);
246 if (!pc)
247 goto error;
248 pc->assignments = isl_id_to_pw_aff_set(pc->assignments, id, value);
249 if (!pc->assignments)
250 return pet_context_free(pc);
251 return pc;
252 error:
253 isl_id_free(id);
254 isl_pw_aff_free(value);
255 return NULL;
258 /* Remove any assignment to "id" in "pc".
260 __isl_give pet_context *pet_context_clear_value(__isl_keep pet_context *pc,
261 __isl_take isl_id *id)
263 pc = pet_context_cow(pc);
264 if (!pc)
265 goto error;
266 pc->assignments = isl_id_to_pw_aff_drop(pc->assignments, id);
267 if (!pc->assignments)
268 return pet_context_free(pc);
269 return pc;
270 error:
271 isl_id_free(id);
272 return NULL;
275 /* Return a piecewise affine expression defined on the specified domain
276 * that represents NaN.
278 static __isl_give isl_pw_aff *nan_on_domain(__isl_take isl_space *space)
280 return isl_pw_aff_nan_on_domain(isl_local_space_from_space(space));
283 /* Assign the value NaN to "id" in "pc", marked it as having an unknown
284 * value.
286 __isl_give pet_context *pet_context_mark_unknown(__isl_take pet_context *pc,
287 __isl_take isl_id *id)
289 isl_pw_aff *pa;
291 pa = nan_on_domain(pet_context_get_space(pc));
292 pc = pet_context_set_value(pc, id, pa);
294 return pc;
297 /* Internal data structure used inside clear_assigned_parameter.
299 * "pc" is the context that is updated by clear_assigned_parameter.
300 * "id" is the identifier that was assigned an unknown value.
302 struct pet_context_mark_assigned_parameter_data {
303 pet_context *pc;
304 isl_id *id;
307 /* This function is called for each assignment in a pet_context
308 * when data->id is assigned an unknown value where it was not
309 * assigned any value before.
310 * Since it was not assigned any value before, it may have been
311 * treated as a parameter.
313 * If the value "value" does indeed refer to data->id as a parameter,
314 * then it is marked as unknown in data->pc since data->id can no
315 * longer be treated as a parameter and the current value has
316 * therefore been invalidated.
318 static int mark_assigned_parameter(__isl_take isl_id *id,
319 __isl_take isl_pw_aff *value, void *user)
321 struct pet_context_mark_assigned_parameter_data *data;
322 isl_space *space;
324 data = (struct pet_context_mark_assigned_parameter_data *) user;
326 space = isl_pw_aff_get_space(value);
327 if (isl_space_find_dim_by_id(space, isl_dim_param, data->id) >= 0)
328 data->pc = pet_context_mark_unknown(data->pc, id);
329 else
330 isl_id_free(id);
332 isl_space_free(space);
333 isl_pw_aff_free(value);
335 return 0;
338 /* This function is called when "id" may have been assigned some value.
340 * Mark "id" as having an unknown value in "pc".
342 * Furthermore, if no (known or unknown) value was assigned to "id" before,
343 * then it may have been treated as a parameter before and may
344 * therefore appear in a value assigned to another variable.
345 * If so, this assignment needs to be turned into an unknown value too.
347 __isl_give pet_context *pet_context_mark_assigned(__isl_take pet_context *pc,
348 __isl_take isl_id *id)
350 int was_assigned;
351 isl_id_to_pw_aff *assignments;
352 struct pet_context_mark_assigned_parameter_data data;
354 was_assigned = pet_context_is_assigned(pc, id);
356 pc = pet_context_mark_unknown(pc, isl_id_copy(id));
358 if (was_assigned) {
359 isl_id_free(id);
360 return pc;
363 assignments = pet_context_get_assignments(pc);
364 data.pc = pc;
365 data.id = id;
366 if (isl_id_to_pw_aff_foreach(assignments,
367 &mark_assigned_parameter, &data) < 0)
368 data.pc = pet_context_free(data.pc);
369 isl_id_to_pw_aff_free(assignments);
371 isl_id_free(id);
372 return data.pc;
375 /* Are affine expressions created in this context allowed to involve
376 * parameters that encode a pet_expr?
378 int pet_context_allow_nesting(__isl_keep pet_context *pc)
380 if (!pc)
381 return -1;
382 return pc->allow_nested;
385 /* Allow affine expressions created in this context to involve
386 * parameters that encode a pet_expr based on the value of "allow_nested".
388 __isl_give pet_context *pet_context_set_allow_nested(__isl_take pet_context *pc,
389 int allow_nested)
391 if (!pc)
392 return NULL;
393 if (pc->allow_nested == allow_nested)
394 return pc;
395 pc = pet_context_cow(pc);
396 if (!pc)
397 return NULL;
398 pc->allow_nested = allow_nested;
399 return pc;
402 /* If the access expression "expr" writes to a (non-virtual) scalar,
403 * then mark the scalar as having an unknown value in "pc".
405 static int clear_write(__isl_keep pet_expr *expr, void *user)
407 isl_id *id;
408 pet_context **pc = (pet_context **) user;
410 if (!pet_expr_access_is_write(expr))
411 return 0;
412 if (!pet_expr_is_scalar_access(expr))
413 return 0;
415 id = pet_expr_access_get_id(expr);
416 if (isl_id_get_user(id))
417 *pc = pet_context_mark_assigned(*pc, id);
418 else
419 isl_id_free(id);
421 return 0;
424 /* Look for any writes to scalar variables in "expr" and
425 * mark them as having an unknown value in "pc".
427 __isl_give pet_context *pet_context_clear_writes_in_expr(
428 __isl_take pet_context *pc, __isl_keep pet_expr *expr)
430 if (pet_expr_foreach_access_expr(expr, &clear_write, &pc) < 0)
431 pc = pet_context_free(pc);
433 return pc;
436 /* Look for any writes to scalar variables in "tree" and
437 * mark them as having an unknown value in "pc".
439 __isl_give pet_context *pet_context_clear_writes_in_tree(
440 __isl_take pet_context *pc, __isl_keep pet_tree *tree)
442 if (pet_tree_foreach_access_expr(tree, &clear_write, &pc) < 0)
443 pc = pet_context_free(pc);
445 return pc;
448 void pet_context_dump(__isl_keep pet_context *pc)
450 if (!pc)
451 return;
452 fprintf(stderr, "domain: ");
453 isl_set_dump(pc->domain);
454 fprintf(stderr, "assignments: ");
455 isl_id_to_pw_aff_dump(pc->assignments);
456 fprintf(stderr, "nesting allowed: %d\n", pc->allow_nested);