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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 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 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 270 void isl_ctx_ref(struct isl_ctx *ctx) 271 { 272 ctx->ref++; 273 } 274 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 */ 283 static void print_stats(isl_ctx *ctx) 284 { 285 fprintf(stderr, "operations: %lu\n", ctx->operations); 286 } 287 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 not freed as 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 314 struct isl_options *isl_ctx_options(isl_ctx *ctx) 315 { 316 if (!ctx) 317 return NULL; 318 return ctx->opt; 319 } 320 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 */ 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 */ 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 */ 342 int isl_ctx_last_error_line(isl_ctx *ctx) 343 { 344 return ctx ? ctx->error_line : -1; 345 } 346 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 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 362 void isl_ctx_abort(isl_ctx *ctx) 363 { 364 if (ctx) 365 ctx->abort = 1; 366 } 367 368 void isl_ctx_resume(isl_ctx *ctx) 369 { 370 if (ctx) 371 ctx->abort = 0; 372 } 373 374 int isl_ctx_aborted(isl_ctx *ctx) 375 { 376 return ctx ? ctx->abort : -1; 377 } 378 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 */ 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 */ 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 */ 404 void isl_ctx_reset_operations(isl_ctx *ctx) 405 { 406 if (!ctx) 407 return; 408 ctx->operations = 0; 409 } 410