add pet_nested_remove_from_space
[pet.git] / context.c
blob723f76fc8a63c7528963d581b25bf8c21c73ab65
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"
40 /* A pet_context represents the context in which a pet_expr
41 * in converted to an affine expression.
43 * "domain" prescribes the domain space of the affine expressions.
45 * "assignments" maps variable names to their currently known values.
46 * The domains of the values are equal to "domain".
47 * If a variable has been assigned an unknown value (possibly because
48 * it may be assigned a different expression in each iteration) or a value
49 * that is not an affine expression, then the corresponding isl_pw_aff
50 * is set to NaN.
52 * If "allow_nested" is set, then the affine expression created
53 * in this context may involve new parameters that encode a pet_expr.
55 struct pet_context {
56 int ref;
58 isl_space *domain;
59 isl_id_to_pw_aff *assignments;
60 int allow_nested;
63 /* Create a pet_context with the given domain, assignments,
64 * and value for allow_nested.
66 static __isl_give pet_context *context_alloc(__isl_take isl_space *domain,
67 __isl_take isl_id_to_pw_aff *assignments, int allow_nested)
69 pet_context *pc;
71 if (!domain || !assignments)
72 goto error;
74 pc = isl_calloc_type(isl_space_get_ctx(domain), struct pet_context);
75 if (!pc)
76 goto error;
78 pc->ref = 1;
79 pc->domain = domain;
80 pc->assignments = assignments;
81 pc->allow_nested = allow_nested;
83 return pc;
84 error:
85 isl_space_free(domain);
86 isl_id_to_pw_aff_free(assignments);
87 return NULL;
90 /* Create a pet_context with the given domain.
92 * Initially, there are no assigned values and parameters that
93 * encode a pet_expr are not allowed.
95 __isl_give pet_context *pet_context_alloc(__isl_take isl_space *domain)
97 isl_id_to_pw_aff *assignments;
99 if (!domain)
100 return NULL;
102 assignments = isl_id_to_pw_aff_alloc(isl_space_get_ctx(domain), 0);;
103 return context_alloc(domain, assignments, 0);
106 /* Return an independent duplicate of "pc".
108 static __isl_give pet_context *pet_context_dup(__isl_keep pet_context *pc)
110 pet_context *dup;
112 if (!pc)
113 return NULL;
115 dup = context_alloc(isl_space_copy(pc->domain),
116 isl_id_to_pw_aff_copy(pc->assignments),
117 pc->allow_nested);
119 return dup;
122 /* Return a pet_context that is equal to "pc" and that has only one reference.
124 static __isl_give pet_context *pet_context_cow(__isl_take pet_context *pc)
126 if (!pc)
127 return NULL;
129 if (pc->ref == 1)
130 return pc;
131 pc->ref--;
132 return pet_context_dup(pc);
135 /* Return an extra reference to "pc".
137 __isl_give pet_context *pet_context_copy(__isl_keep pet_context *pc)
139 if (!pc)
140 return NULL;
142 pc->ref++;
143 return pc;
146 /* Free a reference to "pc" and return NULL.
148 __isl_null pet_context *pet_context_free(__isl_take pet_context *pc)
150 if (!pc)
151 return NULL;
152 if (--pc->ref > 0)
153 return NULL;
155 isl_space_free(pc->domain);
156 isl_id_to_pw_aff_free(pc->assignments);
157 free(pc);
158 return NULL;
161 /* Return the isl_ctx in which "pc" was created.
163 isl_ctx *pet_context_get_ctx(__isl_keep pet_context *pc)
165 return pc ? isl_space_get_ctx(pc->domain) : NULL;
168 /* Return the domain space of "pc".
170 __isl_give isl_space *pet_context_get_space(__isl_keep pet_context *pc)
172 if (!pc)
173 return NULL;
174 return isl_space_copy(pc->domain);
177 /* Return the dimension of the domain space of "pc".
179 unsigned pet_context_dim(__isl_keep pet_context *pc)
181 if (!pc)
182 return 0;
183 return isl_space_dim(pc->domain, isl_dim_set);
186 /* Return the assignments of "pc".
188 __isl_give isl_id_to_pw_aff *pet_context_get_assignments(
189 __isl_keep pet_context *pc)
191 if (!pc)
192 return NULL;
193 return isl_id_to_pw_aff_copy(pc->assignments);
196 /* Is "id" assigned any value in "pc"?
198 int pet_context_is_assigned(__isl_keep pet_context *pc, __isl_keep isl_id *id)
200 if (!pc || !id)
201 return -1;
202 return isl_id_to_pw_aff_has(pc->assignments, id);
205 /* Return the value assigned to "id" in "pc".
207 __isl_give isl_pw_aff *pet_context_get_value(__isl_keep pet_context *pc,
208 __isl_take isl_id *id)
210 if (!pc || !id)
211 goto error;
213 return isl_id_to_pw_aff_get(pc->assignments, id);
214 error:
215 isl_id_free(id);
216 return NULL;
219 /* Assign the value "value" to "id" in "pc", replacing the previously
220 * assigned value, if any.
222 __isl_give pet_context *pet_context_set_value(__isl_take pet_context *pc,
223 __isl_take isl_id *id, isl_pw_aff *value)
225 pc = pet_context_cow(pc);
226 if (!pc)
227 goto error;
228 pc->assignments = isl_id_to_pw_aff_set(pc->assignments, id, value);
229 if (!pc->assignments)
230 return pet_context_free(pc);
231 return pc;
232 error:
233 isl_id_free(id);
234 isl_pw_aff_free(value);
235 return NULL;
238 /* Remove any assignment to "id" in "pc".
240 __isl_give pet_context *pet_context_clear_value(__isl_keep pet_context *pc,
241 __isl_take isl_id *id)
243 pc = pet_context_cow(pc);
244 if (!pc)
245 goto error;
246 pc->assignments = isl_id_to_pw_aff_drop(pc->assignments, id);
247 if (!pc->assignments)
248 return pet_context_free(pc);
249 return pc;
250 error:
251 isl_id_free(id);
252 return NULL;
255 /* Return a piecewise affine expression defined on the specified domain
256 * that represents NaN.
258 static __isl_give isl_pw_aff *nan_on_domain(__isl_take isl_space *space)
260 return isl_pw_aff_nan_on_domain(isl_local_space_from_space(space));
263 /* Assign the value NaN to "id" in "pc", marked it as having an unknown
264 * value.
266 __isl_give pet_context *pet_context_mark_unknown(__isl_take pet_context *pc,
267 __isl_take isl_id *id)
269 isl_pw_aff *pa;
271 pa = nan_on_domain(pet_context_get_space(pc));
272 pc = pet_context_set_value(pc, id, pa);
274 return pc;
277 /* Internal data structure used inside clear_assigned_parameter.
279 * "pc" is the context that is updated by clear_assigned_parameter.
280 * "id" is the identifier that was assigned an unknown value.
282 struct pet_context_mark_assigned_parameter_data {
283 pet_context *pc;
284 isl_id *id;
287 /* This function is called for each assignment in a pet_context
288 * when data->id is assigned an unknown value where it was not
289 * assigned any value before.
290 * Since it was not assigned any value before, it may have been
291 * treated as a parameter.
293 * If the value "value" does indeed refer to data->id as a parameter,
294 * then it is marked as unknown in data->pc since data->id can no
295 * longer be treated as a parameter and the current value has
296 * therefore been invalidated.
298 static int mark_assigned_parameter(__isl_take isl_id *id,
299 __isl_take isl_pw_aff *value, void *user)
301 struct pet_context_mark_assigned_parameter_data *data;
302 isl_space *space;
304 data = (struct pet_context_mark_assigned_parameter_data *) user;
306 space = isl_pw_aff_get_space(value);
307 if (isl_space_find_dim_by_id(space, isl_dim_param, data->id) >= 0)
308 data->pc = pet_context_mark_unknown(data->pc, id);
309 else
310 isl_id_free(id);
312 isl_space_free(space);
313 isl_pw_aff_free(value);
315 return 0;
318 /* This function is called when "id" may have been assigned some value.
320 * Mark "id" as having an unknown value in "pc".
322 * Furthermore, if no (known or unknown) value was assigned to "id" before,
323 * then it may have been treated as a parameter before and may
324 * therefore appear in a value assigned to another variable.
325 * If so, this assignment needs to be turned into an unknown value too.
327 __isl_give pet_context *pet_context_mark_assigned(__isl_take pet_context *pc,
328 __isl_take isl_id *id)
330 int was_assigned;
331 isl_id_to_pw_aff *assignments;
332 struct pet_context_mark_assigned_parameter_data data;
334 was_assigned = pet_context_is_assigned(pc, id);
336 pc = pet_context_mark_unknown(pc, isl_id_copy(id));
338 if (was_assigned) {
339 isl_id_free(id);
340 return pc;
343 assignments = pet_context_get_assignments(pc);
344 data.pc = pc;
345 data.id = id;
346 if (isl_id_to_pw_aff_foreach(assignments,
347 &mark_assigned_parameter, &data) < 0)
348 data.pc = pet_context_free(data.pc);
349 isl_id_to_pw_aff_free(assignments);
351 isl_id_free(id);
352 return data.pc;
355 /* Are affine expressions created in this context allowed to involve
356 * parameters that encode a pet_expr?
358 int pet_context_allow_nesting(__isl_keep pet_context *pc)
360 if (!pc)
361 return -1;
362 return pc->allow_nested;
365 /* Allow affine expressions created in this context to involve
366 * parameters that encode a pet_expr based on the value of "allow_nested".
368 __isl_give pet_context *pet_context_set_allow_nested(__isl_take pet_context *pc,
369 int allow_nested)
371 if (!pc)
372 return NULL;
373 if (pc->allow_nested == allow_nested)
374 return pc;
375 pc = pet_context_cow(pc);
376 if (!pc)
377 return NULL;
378 pc->allow_nested = allow_nested;
379 return pc;
382 /* If the access expression "expr" writes to a (non-virtual) scalar,
383 * then mark the scalar as having an unknown value in "pc".
385 static int clear_write(__isl_keep pet_expr *expr, void *user)
387 isl_id *id;
388 pet_context **pc = (pet_context **) user;
390 if (!pet_expr_access_is_write(expr))
391 return 0;
392 if (!pet_expr_is_scalar_access(expr))
393 return 0;
395 id = pet_expr_access_get_id(expr);
396 if (isl_id_get_user(id))
397 *pc = pet_context_mark_assigned(*pc, id);
398 else
399 isl_id_free(id);
401 return 0;
404 /* Look for any writes to scalar variables in "expr" and
405 * mark them as having an unknown value in "pc".
407 __isl_give pet_context *pet_context_clear_writes_in_expr(
408 __isl_take pet_context *pc, __isl_keep pet_expr *expr)
410 if (pet_expr_foreach_access_expr(expr, &clear_write, &pc) < 0)
411 pc = pet_context_free(pc);
413 return pc;
416 /* Look for any writes to scalar variables in "tree" and
417 * mark them as having an unknown value in "pc".
419 __isl_give pet_context *pet_context_clear_writes_in_tree(
420 __isl_take pet_context *pc, __isl_keep pet_tree *tree)
422 if (pet_tree_foreach_access_expr(tree, &clear_write, &pc) < 0)
423 pc = pet_context_free(pc);
425 return pc;
428 void pet_context_dump(__isl_keep pet_context *pc)
430 if (!pc)
431 return;
432 fprintf(stderr, "domain: ");
433 isl_space_dump(pc->domain);
434 fprintf(stderr, "assignments: ");
435 isl_id_to_pw_aff_dump(pc->assignments);
436 fprintf(stderr, "nesting allowed: %d\n", pc->allow_nested);