1 /*
2  * Copyright 2008-2009 Katholieke Universiteit Leuven
3  *
4  * Use of this software is governed by the MIT license
5  *
6  * Written by Sven Verdoolaege, K.U.Leuven, Departement
7  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
8  */
9 
10 #include <isl_ctx_private.h>
11 #include <isl/vec.h>
12 #include <isl_options_private.h>
13 
14 #define __isl_calloc(type,size)		((type *)calloc(1, size))
15 #define __isl_calloc_type(type)		__isl_calloc(type,sizeof(type))
16 
17 /* Construct an isl_stat indicating whether "obj" is non-NULL.
18  *
19  * That is, return isl_stat_ok if "obj" is non_NULL and
20  * isl_stat_error otherwise.
21  */
isl_stat_non_null(void * obj)22 isl_stat isl_stat_non_null(void *obj)
23 {
24 	if (obj != NULL)
25 		return isl_stat_ok;
26 	return isl_stat_error;
27 }
28 
29 /* Return the negation of "b", where the negation of isl_bool_error
30  * is isl_bool_error again.
31  */
isl_bool_not(isl_bool b)32 isl_bool isl_bool_not(isl_bool b)
33 {
34 	if (b < 0)
35 		return isl_bool_error;
36 	if (b == isl_bool_false)
37 		return isl_bool_true;
38 	return isl_bool_false;
39 }
40 
41 /* Create an isl_bool from an integer.
42  *
43  * Return isl_bool_false if b is zero, otherwise return isl_bool_true.
44  * This function never returns isl_bool_error.
45  */
isl_bool_ok(int b)46 isl_bool isl_bool_ok(int b)
47 {
48 	if (b)
49 		return isl_bool_true;
50 	return isl_bool_false;
51 }
52 
53 /* Check that the result of an allocation ("p") is not NULL and
54  * complain if it is.
55  * The only exception is when allocation size ("size") is equal to zero.
56  */
check_non_null(isl_ctx * ctx,void * p,size_t size)57 static void *check_non_null(isl_ctx *ctx, void *p, size_t size)
58 {
59 	if (p || size == 0)
60 		return p;
61 	isl_die(ctx, isl_error_alloc, "allocation failure", return NULL);
62 }
63 
64 /* Prepare for performing the next "operation" in the context.
65  * Return 0 if we are allowed to perform this operation and
66  * return -1 if we should abort the computation.
67  *
68  * In particular, we should stop if the user has explicitly aborted
69  * the computation or if the maximal number of operations has been exceeded.
70  */
isl_ctx_next_operation(isl_ctx * ctx)71 int isl_ctx_next_operation(isl_ctx *ctx)
72 {
73 	if (!ctx)
74 		return -1;
75 	if (ctx->abort) {
76 		isl_ctx_set_error(ctx, isl_error_abort);
77 		return -1;
78 	}
79 	if (ctx->max_operations && ctx->operations >= ctx->max_operations)
80 		isl_die(ctx, isl_error_quota,
81 			"maximal number of operations exceeded", return -1);
82 	ctx->operations++;
83 	return 0;
84 }
85 
86 /* Call malloc and complain if it fails.
87  * If ctx is NULL, then return NULL.
88  */
isl_malloc_or_die(isl_ctx * ctx,size_t size)89 void *isl_malloc_or_die(isl_ctx *ctx, size_t size)
90 {
91 	if (isl_ctx_next_operation(ctx) < 0)
92 		return NULL;
93 	return ctx ? check_non_null(ctx, malloc(size), size) : NULL;
94 }
95 
96 /* Call calloc and complain if it fails.
97  * If ctx is NULL, then return NULL.
98  */
isl_calloc_or_die(isl_ctx * ctx,size_t nmemb,size_t size)99 void *isl_calloc_or_die(isl_ctx *ctx, size_t nmemb, size_t size)
100 {
101 	if (isl_ctx_next_operation(ctx) < 0)
102 		return NULL;
103 	return ctx ? check_non_null(ctx, calloc(nmemb, size), nmemb) : NULL;
104 }
105 
106 /* Call realloc and complain if it fails.
107  * If ctx is NULL, then return NULL.
108  */
isl_realloc_or_die(isl_ctx * ctx,void * ptr,size_t size)109 void *isl_realloc_or_die(isl_ctx *ctx, void *ptr, size_t size)
110 {
111 	if (isl_ctx_next_operation(ctx) < 0)
112 		return NULL;
113 	return ctx ? check_non_null(ctx, realloc(ptr, size), size) : NULL;
114 }
115 
116 /* Keep track of all information about the current error ("error", "msg",
117  * "file", "line") in "ctx".
118  */
isl_ctx_set_full_error(isl_ctx * ctx,enum isl_error error,const char * msg,const char * file,int line)119 void isl_ctx_set_full_error(isl_ctx *ctx, enum isl_error error, const char *msg,
120 	const char *file, int line)
121 {
122 	if (!ctx)
123 		return;
124 	ctx->error = error;
125 	ctx->error_msg = msg;
126 	ctx->error_file = file;
127 	ctx->error_line = line;
128 }
129 
isl_handle_error(isl_ctx * ctx,enum isl_error error,const char * msg,const char * file,int line)130 void isl_handle_error(isl_ctx *ctx, enum isl_error error, const char *msg,
131 	const char *file, int line)
132 {
133 	if (!ctx)
134 		return;
135 
136 	isl_ctx_set_full_error(ctx, error, msg, file, line);
137 
138 	switch (ctx->opt->on_error) {
139 	case ISL_ON_ERROR_WARN:
140 		fprintf(stderr, "%s:%d: %s\n", file, line, msg);
141 		return;
142 	case ISL_ON_ERROR_CONTINUE:
143 		return;
144 	case ISL_ON_ERROR_ABORT:
145 		fprintf(stderr, "%s:%d: %s\n", file, line, msg);
146 		abort();
147 		return;
148 	}
149 }
150 
find_nested_options(struct isl_args * args,void * opt,struct isl_args * wanted)151 static struct isl_options *find_nested_options(struct isl_args *args,
152 	void *opt, struct isl_args *wanted)
153 {
154 	int i;
155 	struct isl_options *options;
156 
157 	if (args == wanted)
158 		return opt;
159 
160 	for (i = 0; args->args[i].type != isl_arg_end; ++i) {
161 		struct isl_arg *arg = &args->args[i];
162 		void *child;
163 
164 		if (arg->type != isl_arg_child)
165 			continue;
166 
167 		if (arg->offset == ISL_ARG_OFFSET_NONE)
168 			child = opt;
169 		else
170 			child = *(void **)(((char *)opt) + arg->offset);
171 
172 		options = find_nested_options(arg->u.child.child,
173 						child, wanted);
174 		if (options)
175 			return options;
176 	}
177 
178 	return NULL;
179 }
180 
find_nested_isl_options(struct isl_args * args,void * opt)181 static struct isl_options *find_nested_isl_options(struct isl_args *args,
182 	void *opt)
183 {
184 	return find_nested_options(args, opt, &isl_options_args);
185 }
186 
isl_ctx_peek_options(isl_ctx * ctx,struct isl_args * args)187 void *isl_ctx_peek_options(isl_ctx *ctx, struct isl_args *args)
188 {
189 	if (!ctx)
190 		return NULL;
191 	if (args == &isl_options_args)
192 		return ctx->opt;
193 	return find_nested_options(ctx->user_args, ctx->user_opt, args);
194 }
195 
isl_ctx_alloc_with_options(struct isl_args * args,void * user_opt)196 isl_ctx *isl_ctx_alloc_with_options(struct isl_args *args, void *user_opt)
197 {
198 	struct isl_ctx *ctx = NULL;
199 	struct isl_options *opt = NULL;
200 	int opt_allocated = 0;
201 
202 	if (!user_opt)
203 		return NULL;
204 
205 	opt = find_nested_isl_options(args, user_opt);
206 	if (!opt) {
207 		opt = isl_options_new_with_defaults();
208 		if (!opt)
209 			goto error;
210 		opt_allocated = 1;
211 	}
212 
213 	ctx = __isl_calloc_type(struct isl_ctx);
214 	if (!ctx)
215 		goto error;
216 
217 	if (isl_hash_table_init(ctx, &ctx->id_table, 0))
218 		goto error;
219 
220 	ctx->stats = isl_calloc_type(ctx, struct isl_stats);
221 	if (!ctx->stats)
222 		goto error;
223 
224 	ctx->user_args = args;
225 	ctx->user_opt = user_opt;
226 	ctx->opt_allocated = opt_allocated;
227 	ctx->opt = opt;
228 	ctx->ref = 0;
229 
230 	isl_int_init(ctx->zero);
231 	isl_int_set_si(ctx->zero, 0);
232 
233 	isl_int_init(ctx->one);
234 	isl_int_set_si(ctx->one, 1);
235 
236 	isl_int_init(ctx->two);
237 	isl_int_set_si(ctx->two, 2);
238 
239 	isl_int_init(ctx->negone);
240 	isl_int_set_si(ctx->negone, -1);
241 
242 	isl_int_init(ctx->normalize_gcd);
243 
244 	ctx->n_cached = 0;
245 	ctx->n_miss = 0;
246 
247 	isl_ctx_reset_error(ctx);
248 
249 	ctx->operations = 0;
250 	isl_ctx_set_max_operations(ctx, ctx->opt->max_operations);
251 
252 	return ctx;
253 error:
254 	isl_args_free(args, user_opt);
255 	if (opt_allocated)
256 		isl_options_free(opt);
257 	free(ctx);
258 	return NULL;
259 }
260 
isl_ctx_alloc()261 struct isl_ctx *isl_ctx_alloc()
262 {
263 	struct isl_options *opt;
264 
265 	opt = isl_options_new_with_defaults();
266 
267 	return isl_ctx_alloc_with_options(&isl_options_args, opt);
268 }
269 
isl_ctx_ref(struct isl_ctx * ctx)270 void isl_ctx_ref(struct isl_ctx *ctx)
271 {
272 	ctx->ref++;
273 }
274 
isl_ctx_deref(struct isl_ctx * ctx)275 void isl_ctx_deref(struct isl_ctx *ctx)
276 {
277 	isl_assert(ctx, ctx->ref > 0, return);
278 	ctx->ref--;
279 }
280 
281 /* Print statistics on usage.
282  */
print_stats(isl_ctx * ctx)283 static void print_stats(isl_ctx *ctx)
284 {
285 	fprintf(stderr, "operations: %lu\n", ctx->operations);
286 }
287 
isl_ctx_free(struct isl_ctx * ctx)288 void isl_ctx_free(struct isl_ctx *ctx)
289 {
290 	if (!ctx)
291 		return;
292 	if (ctx->ref != 0)
293 		isl_die(ctx, isl_error_invalid,
294 			"isl_ctx freed, but some objects still reference it",
295 			return);
296 
297 	if (ctx->opt->print_stats)
298 		print_stats(ctx);
299 
300 	isl_hash_table_clear(&ctx->id_table);
301 	isl_blk_clear_cache(ctx);
302 	isl_int_clear(ctx->zero);
303 	isl_int_clear(ctx->one);
304 	isl_int_clear(ctx->two);
305 	isl_int_clear(ctx->negone);
306 	isl_int_clear(ctx->normalize_gcd);
307 	isl_args_free(ctx->user_args, ctx->user_opt);
308 	if (ctx->opt_allocated)
309 		isl_options_free(ctx->opt);
310 	free(ctx->stats);
311 	free(ctx);
312 }
313 
isl_ctx_options(isl_ctx * ctx)314 struct isl_options *isl_ctx_options(isl_ctx *ctx)
315 {
316 	if (!ctx)
317 		return NULL;
318 	return ctx->opt;
319 }
320 
isl_ctx_last_error(isl_ctx * ctx)321 enum isl_error isl_ctx_last_error(isl_ctx *ctx)
322 {
323 	return ctx ? ctx->error : isl_error_invalid;
324 }
325 
326 /* Return the error message of the last error in "ctx".
327  */
isl_ctx_last_error_msg(isl_ctx * ctx)328 const char *isl_ctx_last_error_msg(isl_ctx *ctx)
329 {
330 	return ctx ? ctx->error_msg : NULL;
331 }
332 
333 /* Return the file name where the last error in "ctx" occurred.
334  */
isl_ctx_last_error_file(isl_ctx * ctx)335 const char *isl_ctx_last_error_file(isl_ctx *ctx)
336 {
337 	return ctx ? ctx->error_file : NULL;
338 }
339 
340 /* Return the line number where the last error in "ctx" occurred.
341  */
isl_ctx_last_error_line(isl_ctx * ctx)342 int isl_ctx_last_error_line(isl_ctx *ctx)
343 {
344 	return ctx ? ctx->error_line : -1;
345 }
346 
isl_ctx_reset_error(isl_ctx * ctx)347 void isl_ctx_reset_error(isl_ctx *ctx)
348 {
349 	if (!ctx)
350 		return;
351 	ctx->error = isl_error_none;
352 	ctx->error_msg = NULL;
353 	ctx->error_file = NULL;
354 	ctx->error_line = -1;
355 }
356 
isl_ctx_set_error(isl_ctx * ctx,enum isl_error error)357 void isl_ctx_set_error(isl_ctx *ctx, enum isl_error error)
358 {
359 	isl_ctx_set_full_error(ctx, error, NULL, NULL, -1);
360 }
361 
isl_ctx_abort(isl_ctx * ctx)362 void isl_ctx_abort(isl_ctx *ctx)
363 {
364 	if (ctx)
365 		ctx->abort = 1;
366 }
367 
isl_ctx_resume(isl_ctx * ctx)368 void isl_ctx_resume(isl_ctx *ctx)
369 {
370 	if (ctx)
371 		ctx->abort = 0;
372 }
373 
isl_ctx_aborted(isl_ctx * ctx)374 int isl_ctx_aborted(isl_ctx *ctx)
375 {
376 	return ctx ? ctx->abort : -1;
377 }
378 
isl_ctx_parse_options(isl_ctx * ctx,int argc,char ** argv,unsigned flags)379 int isl_ctx_parse_options(isl_ctx *ctx, int argc, char **argv, unsigned flags)
380 {
381 	if (!ctx)
382 		return -1;
383 	return isl_args_parse(ctx->user_args, argc, argv, ctx->user_opt, flags);
384 }
385 
386 /* Set the maximal number of iterations of "ctx" to "max_operations".
387  */
isl_ctx_set_max_operations(isl_ctx * ctx,unsigned long max_operations)388 void isl_ctx_set_max_operations(isl_ctx *ctx, unsigned long max_operations)
389 {
390 	if (!ctx)
391 		return;
392 	ctx->max_operations = max_operations;
393 }
394 
395 /* Return the maximal number of iterations of "ctx".
396  */
isl_ctx_get_max_operations(isl_ctx * ctx)397 unsigned long isl_ctx_get_max_operations(isl_ctx *ctx)
398 {
399 	return ctx ? ctx->max_operations : 0;
400 }
401 
402 /* Reset the number of operations performed by "ctx".
403  */
isl_ctx_reset_operations(isl_ctx * ctx)404 void isl_ctx_reset_operations(isl_ctx *ctx)
405 {
406 	if (!ctx)
407 		return;
408 	ctx->operations = 0;
409 }
410