diff options
Diffstat (limited to 'polly/lib/External/isl/isl_ast.c')
-rw-r--r-- | polly/lib/External/isl/isl_ast.c | 1644 |
1 files changed, 1306 insertions, 338 deletions
diff --git a/polly/lib/External/isl/isl_ast.c b/polly/lib/External/isl/isl_ast.c index 6bf517893f7b..c7164c4b3e7c 100644 --- a/polly/lib/External/isl/isl_ast.c +++ b/polly/lib/External/isl/isl_ast.c @@ -1,15 +1,18 @@ /* * Copyright 2012-2013 Ecole Normale Superieure + * Copyright 2022 Cerebras Systems * * Use of this software is governed by the MIT license * * Written by Sven Verdoolaege, * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France + * and Cerebras Systems, 1237 E Arques Ave, Sunnyvale, CA, USA */ #include <string.h> #include <isl/id.h> +#include <isl/stream.h> #include <isl/val.h> #include <isl_ast_private.h> @@ -146,6 +149,49 @@ __isl_give isl_ast_print_options *isl_ast_print_options_set_print_for( return options; } +/* Create a new operation expression of operation type "op", + * with arguments "args". + */ +static __isl_give isl_ast_expr *alloc_op(enum isl_ast_expr_op_type op, + __isl_take isl_ast_expr_list *args) +{ + isl_ctx *ctx; + isl_ast_expr *expr; + + if (!args) + return NULL; + + ctx = isl_ast_expr_list_get_ctx(args); + expr = isl_calloc_type(ctx, isl_ast_expr); + if (!expr) + goto error; + + expr->ctx = ctx; + isl_ctx_ref(ctx); + expr->ref = 1; + expr->type = isl_ast_expr_op; + expr->u.op.op = op; + expr->u.op.args = args; + + return expr; +error: + isl_ast_expr_list_free(args); + return NULL; +} + +/* Create a new operation expression of operation type "op", + * which will end up having "n_arg" arguments. + * The caller still needs to add those arguments. + */ +__isl_give isl_ast_expr *isl_ast_expr_alloc_op(isl_ctx *ctx, + enum isl_ast_expr_op_type op, int n_arg) +{ + isl_ast_expr_list *args; + + args = isl_ast_expr_list_alloc(ctx, n_arg); + return alloc_op(op, args); +} + __isl_give isl_ast_expr *isl_ast_expr_copy(__isl_keep isl_ast_expr *expr) { if (!expr) @@ -157,14 +203,11 @@ __isl_give isl_ast_expr *isl_ast_expr_copy(__isl_keep isl_ast_expr *expr) __isl_give isl_ast_expr *isl_ast_expr_dup(__isl_keep isl_ast_expr *expr) { - int i; - isl_ctx *ctx; isl_ast_expr *dup; if (!expr) return NULL; - ctx = isl_ast_expr_get_ctx(expr); switch (expr->type) { case isl_ast_expr_int: dup = isl_ast_expr_from_val(isl_val_copy(expr->u.v)); @@ -173,13 +216,8 @@ __isl_give isl_ast_expr *isl_ast_expr_dup(__isl_keep isl_ast_expr *expr) dup = isl_ast_expr_from_id(isl_id_copy(expr->u.id)); break; case isl_ast_expr_op: - dup = isl_ast_expr_alloc_op(ctx, - expr->u.op.op, expr->u.op.n_arg); - if (!dup) - return NULL; - for (i = 0; i < expr->u.op.n_arg; ++i) - dup->u.op.args[i] = - isl_ast_expr_copy(expr->u.op.args[i]); + dup = alloc_op(expr->u.op.op, + isl_ast_expr_list_copy(expr->u.op.args)); break; case isl_ast_expr_error: dup = NULL; @@ -204,8 +242,6 @@ __isl_give isl_ast_expr *isl_ast_expr_cow(__isl_take isl_ast_expr *expr) __isl_null isl_ast_expr *isl_ast_expr_free(__isl_take isl_ast_expr *expr) { - int i; - if (!expr) return NULL; @@ -222,10 +258,7 @@ __isl_null isl_ast_expr *isl_ast_expr_free(__isl_take isl_ast_expr *expr) isl_id_free(expr->u.id); break; case isl_ast_expr_op: - if (expr->u.op.args) - for (i = 0; i < expr->u.op.n_arg; ++i) - isl_ast_expr_free(expr->u.op.args[i]); - free(expr->u.op.args); + isl_ast_expr_list_free(expr->u.op.args); break; case isl_ast_expr_error: break; @@ -282,17 +315,25 @@ __isl_give isl_id *isl_ast_expr_get_id(__isl_keep isl_ast_expr *expr) return isl_ast_expr_id_get_id(expr); } +/* Check that "expr" is of type isl_ast_expr_op. + */ +static isl_stat isl_ast_expr_check_op(__isl_keep isl_ast_expr *expr) +{ + if (!expr) + return isl_stat_error; + if (expr->type != isl_ast_expr_op) + isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, + "expression not an operation", return isl_stat_error); + return isl_stat_ok; +} + /* Return the type of operation represented by "expr". */ enum isl_ast_expr_op_type isl_ast_expr_op_get_type( __isl_keep isl_ast_expr *expr) { - if (!expr) + if (isl_ast_expr_check_op(expr) < 0) return isl_ast_expr_op_error; - if (expr->type != isl_ast_expr_op) - isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, - "expression not an operation", - return isl_ast_expr_op_error); return expr->u.op.op; } @@ -308,12 +349,9 @@ enum isl_ast_expr_op_type isl_ast_expr_get_op_type( */ isl_size isl_ast_expr_op_get_n_arg(__isl_keep isl_ast_expr *expr) { - if (!expr) + if (isl_ast_expr_check_op(expr) < 0) return isl_size_error; - if (expr->type != isl_ast_expr_op) - isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, - "expression not an operation", return isl_size_error); - return expr->u.op.n_arg; + return isl_ast_expr_list_size(expr->u.op.args); } /* This is an alternative name for the function above. @@ -328,16 +366,10 @@ isl_size isl_ast_expr_get_op_n_arg(__isl_keep isl_ast_expr *expr) __isl_give isl_ast_expr *isl_ast_expr_op_get_arg(__isl_keep isl_ast_expr *expr, int pos) { - if (!expr) + if (isl_ast_expr_check_op(expr) < 0) return NULL; - if (expr->type != isl_ast_expr_op) - isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, - "expression not an operation", return NULL); - if (pos < 0 || pos >= expr->u.op.n_arg) - isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, - "index out of bounds", return NULL); - return isl_ast_expr_copy(expr->u.op.args[pos]); + return isl_ast_expr_list_get_at(expr->u.op.args, pos); } /* This is an alternative name for the function above. @@ -348,28 +380,130 @@ __isl_give isl_ast_expr *isl_ast_expr_get_op_arg(__isl_keep isl_ast_expr *expr, return isl_ast_expr_op_get_arg(expr, pos); } -/* Replace the argument at position "pos" of "expr" by "arg". +/* Return a copy of the arguments of the operation represented by "expr". */ -__isl_give isl_ast_expr *isl_ast_expr_set_op_arg(__isl_take isl_ast_expr *expr, - int pos, __isl_take isl_ast_expr *arg) +static __isl_give isl_ast_expr_list *isl_ast_expr_op_get_args( + __isl_keep isl_ast_expr *expr) +{ + if (isl_ast_expr_check_op(expr) < 0) + return NULL; + return isl_ast_expr_list_copy(expr->u.op.args); +} + +/* Return the arguments of the operation expression "expr". + * This may be either a copy or the arguments themselves + * if there is only one reference to "expr". + * This allows the arguments to be modified inplace + * if both "expr" and its arguments have only a single reference. + * The caller is not allowed to modify "expr" between this call and + * the subsequent call to isl_ast_expr_op_restore_args. + * The only exception is that isl_ast_expr_free can be called instead. + */ +static __isl_give isl_ast_expr_list *isl_ast_expr_op_take_args( + __isl_keep isl_ast_expr *expr) { + isl_ast_expr_list *args; + + if (isl_ast_expr_check_op(expr) < 0) + return NULL; + if (expr->ref != 1) + return isl_ast_expr_op_get_args(expr); + args = expr->u.op.args; + expr->u.op.args = NULL; + return args; +} + +/* Set the arguments of the operation expression "expr" to "args", + * where the arguments of "args" may be missing + * due to a preceding call to isl_ast_expr_op_take_args. + * However, in this case, "expr" only has a single reference and + * then the call to isl_ast_expr_cow has no effect. + */ +static __isl_give isl_ast_expr *isl_ast_expr_op_restore_args( + __isl_take isl_ast_expr *expr, __isl_take isl_ast_expr_list *args) +{ + if (isl_ast_expr_check_op(expr) < 0 || !args) + goto error; + if (expr->u.op.args == args) { + isl_ast_expr_list_free(args); + return expr; + } + expr = isl_ast_expr_cow(expr); - if (!expr || !arg) + if (!expr) goto error; - if (expr->type != isl_ast_expr_op) - isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, - "expression not an operation", goto error); - if (pos < 0 || pos >= expr->u.op.n_arg) - isl_die(isl_ast_expr_get_ctx(expr), isl_error_invalid, - "index out of bounds", goto error); - isl_ast_expr_free(expr->u.op.args[pos]); - expr->u.op.args[pos] = arg; + isl_ast_expr_list_free(expr->u.op.args); + expr->u.op.args = args; return expr; error: - isl_ast_expr_free(arg); - return isl_ast_expr_free(expr); + isl_ast_expr_free(expr); + isl_ast_expr_list_free(args); + return NULL; +} + +/* Add "arg" to the arguments of the operation expression "expr". + */ +__isl_give isl_ast_expr *isl_ast_expr_op_add_arg(__isl_take isl_ast_expr *expr, + __isl_take isl_ast_expr *arg) +{ + isl_ast_expr_list *args; + + args = isl_ast_expr_op_take_args(expr); + args = isl_ast_expr_list_add(args, arg); + expr = isl_ast_expr_op_restore_args(expr, args); + + return expr; +} + +/* Replace the argument at position "pos" of "expr" by "arg". + */ +__isl_give isl_ast_expr *isl_ast_expr_set_op_arg(__isl_take isl_ast_expr *expr, + int pos, __isl_take isl_ast_expr *arg) +{ + isl_ast_expr_list *args; + + args = isl_ast_expr_op_take_args(expr); + args = isl_ast_expr_list_set_at(args, pos, arg); + expr = isl_ast_expr_op_restore_args(expr, args); + + return expr; +} + +/* Are the lists of AST expressions "list1" and "list2" the same? + */ +static isl_bool isl_ast_expr_list_is_equal(__isl_keep isl_ast_expr_list *list1, + __isl_keep isl_ast_expr_list *list2) +{ + int i; + isl_size n1, n2; + + if (!list1 || !list2) + return isl_bool_error; + if (list1 == list2) + return isl_bool_true; + + n1 = isl_ast_expr_list_size(list1); + n2 = isl_ast_expr_list_size(list2); + if (n1 < 0 || n2 < 0) + return isl_bool_error; + if (n1 != n2) + return isl_bool_false; + for (i = 0; i < n1; ++i) { + isl_ast_expr *expr1, *expr2; + isl_bool equal; + + expr1 = isl_ast_expr_list_get_at(list1, i); + expr2 = isl_ast_expr_list_get_at(list2, i); + equal = isl_ast_expr_is_equal(expr1, expr2); + isl_ast_expr_free(expr1); + isl_ast_expr_free(expr2); + if (equal < 0 || !equal) + return equal; + } + + return isl_bool_true; } /* Is "expr1" equal to "expr2"? @@ -377,8 +511,6 @@ error: isl_bool isl_ast_expr_is_equal(__isl_keep isl_ast_expr *expr1, __isl_keep isl_ast_expr *expr2) { - int i; - if (!expr1 || !expr2) return isl_bool_error; @@ -394,16 +526,8 @@ isl_bool isl_ast_expr_is_equal(__isl_keep isl_ast_expr *expr1, case isl_ast_expr_op: if (expr1->u.op.op != expr2->u.op.op) return isl_bool_false; - if (expr1->u.op.n_arg != expr2->u.op.n_arg) - return isl_bool_false; - for (i = 0; i < expr1->u.op.n_arg; ++i) { - isl_bool equal; - equal = isl_ast_expr_is_equal(expr1->u.op.args[i], - expr2->u.op.args[i]); - if (equal < 0 || !equal) - return equal; - } - return isl_bool_true; + return isl_ast_expr_list_is_equal(expr1->u.op.args, + expr2->u.op.args); case isl_ast_expr_error: return isl_bool_error; } @@ -412,32 +536,6 @@ isl_bool isl_ast_expr_is_equal(__isl_keep isl_ast_expr *expr1, "unhandled case", return isl_bool_error); } -/* Create a new operation expression of operation type "op", - * with "n_arg" as yet unspecified arguments. - */ -__isl_give isl_ast_expr *isl_ast_expr_alloc_op(isl_ctx *ctx, - enum isl_ast_expr_op_type op, int n_arg) -{ - isl_ast_expr *expr; - - expr = isl_calloc_type(ctx, isl_ast_expr); - if (!expr) - return NULL; - - expr->ctx = ctx; - isl_ctx_ref(ctx); - expr->ref = 1; - expr->type = isl_ast_expr_op; - expr->u.op.op = op; - expr->u.op.n_arg = n_arg; - expr->u.op.args = isl_calloc_array(ctx, isl_ast_expr *, n_arg); - - if (n_arg && !expr->u.op.args) - return isl_ast_expr_free(expr); - - return expr; -} - /* Create a new id expression representing "id". */ __isl_give isl_ast_expr *isl_ast_expr_from_id(__isl_take isl_id *id) @@ -524,21 +622,19 @@ __isl_give isl_ast_expr *isl_ast_expr_alloc_unary( { isl_ctx *ctx; isl_ast_expr *expr = NULL; + isl_ast_expr_list *args; if (!arg) return NULL; ctx = isl_ast_expr_get_ctx(arg); expr = isl_ast_expr_alloc_op(ctx, type, 1); - if (!expr) - goto error; - expr->u.op.args[0] = arg; + args = isl_ast_expr_op_take_args(expr); + args = isl_ast_expr_list_add(args, arg); + expr = isl_ast_expr_op_restore_args(expr, args); return expr; -error: - isl_ast_expr_free(arg); - return NULL; } /* Create an expression representing the negation of "arg". @@ -573,17 +669,18 @@ __isl_give isl_ast_expr *isl_ast_expr_alloc_binary( { isl_ctx *ctx; isl_ast_expr *expr = NULL; + isl_ast_expr_list *args; if (!expr1 || !expr2) goto error; ctx = isl_ast_expr_get_ctx(expr1); expr = isl_ast_expr_alloc_op(ctx, type, 2); - if (!expr) - goto error; - expr->u.op.args[0] = expr1; - expr->u.op.args[1] = expr2; + args = isl_ast_expr_op_take_args(expr); + args = isl_ast_expr_list_add(args, expr1); + args = isl_ast_expr_list_add(args, expr2); + expr = isl_ast_expr_op_restore_args(expr, args); return expr; error: @@ -725,37 +822,8 @@ static __isl_give isl_ast_expr *ast_expr_with_arguments( enum isl_ast_expr_op_type type, __isl_take isl_ast_expr *arg0, __isl_take isl_ast_expr_list *arguments) { - int i; - isl_size n; - isl_ctx *ctx; - isl_ast_expr *res = NULL; - - if (!arg0 || !arguments) - goto error; - - ctx = isl_ast_expr_get_ctx(arg0); - n = isl_ast_expr_list_n_ast_expr(arguments); - if (n < 0) - goto error; - res = isl_ast_expr_alloc_op(ctx, type, 1 + n); - if (!res) - goto error; - for (i = 0; i < n; ++i) { - isl_ast_expr *arg; - arg = isl_ast_expr_list_get_ast_expr(arguments, i); - res->u.op.args[1 + i] = arg; - if (!arg) - goto error; - } - res->u.op.args[0] = arg0; - - isl_ast_expr_list_free(arguments); - return res; -error: - isl_ast_expr_free(arg0); - isl_ast_expr_list_free(arguments); - isl_ast_expr_free(res); - return NULL; + arguments = isl_ast_expr_list_insert(arguments, 0, arg0); + return alloc_op(type, arguments); } /* Create an expression representing an access to "array" with index @@ -776,6 +844,18 @@ __isl_give isl_ast_expr *isl_ast_expr_call(__isl_take isl_ast_expr *function, return ast_expr_with_arguments(isl_ast_expr_op_call, function, arguments); } +/* Wrapper around isl_ast_expr_substitute_ids for use + * as an isl_ast_expr_list_map callback. + */ +static __isl_give isl_ast_expr *substitute_ids(__isl_take isl_ast_expr *expr, + void *user) +{ + isl_id_to_ast_expr *id2expr = user; + + return isl_ast_expr_substitute_ids(expr, + isl_id_to_ast_expr_copy(id2expr)); +} + /* For each subexpression of "expr" of type isl_ast_expr_id, * if it appears in "id2expr", then replace it by the corresponding * expression. @@ -783,8 +863,8 @@ __isl_give isl_ast_expr *isl_ast_expr_call(__isl_take isl_ast_expr *function, __isl_give isl_ast_expr *isl_ast_expr_substitute_ids( __isl_take isl_ast_expr *expr, __isl_take isl_id_to_ast_expr *id2expr) { - int i; isl_maybe_isl_ast_expr m; + isl_ast_expr_list *args; if (!expr || !id2expr) goto error; @@ -802,25 +882,9 @@ __isl_give isl_ast_expr *isl_ast_expr_substitute_ids( expr = m.value; break; case isl_ast_expr_op: - for (i = 0; i < expr->u.op.n_arg; ++i) { - isl_ast_expr *arg; - arg = isl_ast_expr_copy(expr->u.op.args[i]); - arg = isl_ast_expr_substitute_ids(arg, - isl_id_to_ast_expr_copy(id2expr)); - if (arg == expr->u.op.args[i]) { - isl_ast_expr_free(arg); - continue; - } - if (!arg) - expr = isl_ast_expr_free(expr); - expr = isl_ast_expr_cow(expr); - if (!expr) { - isl_ast_expr_free(arg); - break; - } - isl_ast_expr_free(expr->u.op.args[i]); - expr->u.op.args[i] = arg; - } + args = isl_ast_expr_op_take_args(expr); + args = isl_ast_expr_list_map(args, &substitute_ids, id2expr); + expr = isl_ast_expr_op_restore_args(expr, args); break; case isl_ast_expr_error: expr = isl_ast_expr_free(expr); @@ -939,7 +1003,8 @@ error: /* Create a user node evaluating "expr". */ -__isl_give isl_ast_node *isl_ast_node_alloc_user(__isl_take isl_ast_expr *expr) +__isl_give isl_ast_node *isl_ast_node_user_from_expr( + __isl_take isl_ast_expr *expr) { isl_ctx *ctx; isl_ast_node *node; @@ -960,9 +1025,16 @@ error: return NULL; } +/* This is an alternative name for the function above. + */ +__isl_give isl_ast_node *isl_ast_node_alloc_user(__isl_take isl_ast_expr *expr) +{ + return isl_ast_node_user_from_expr(expr); +} + /* Create a block node with the given children. */ -__isl_give isl_ast_node *isl_ast_node_alloc_block( +__isl_give isl_ast_node *isl_ast_node_block_from_children( __isl_take isl_ast_node_list *list) { isl_ast_node *node; @@ -984,6 +1056,14 @@ error: return NULL; } +/* This is an alternative name for the function above. + */ +__isl_give isl_ast_node *isl_ast_node_alloc_block( + __isl_take isl_ast_node_list *list) +{ + return isl_ast_node_block_from_children(list); +} + /* Represent the given list of nodes as a single node, either by * extract the node from a single element list or by creating * a block node with the list of nodes as children. @@ -1018,6 +1098,11 @@ __isl_give isl_ast_node *isl_ast_node_copy(__isl_keep isl_ast_node *node) return node; } +/* Return a fresh copy of "node". + * + * In the case of a degenerate for node, take into account + * that "cond" and "inc" are NULL. + */ __isl_give isl_ast_node *isl_ast_node_dup(__isl_keep isl_ast_node *node) { isl_ast_node *dup; @@ -1039,13 +1124,17 @@ __isl_give isl_ast_node *isl_ast_node_dup(__isl_keep isl_ast_node *node) return isl_ast_node_free(dup); break; case isl_ast_node_for: + dup->u.f.degenerate = node->u.f.degenerate; dup->u.f.iterator = isl_ast_expr_copy(node->u.f.iterator); dup->u.f.init = isl_ast_expr_copy(node->u.f.init); + dup->u.f.body = isl_ast_node_copy(node->u.f.body); + if (!dup->u.f.iterator || !dup->u.f.init || !dup->u.f.body) + return isl_ast_node_free(dup); + if (node->u.f.degenerate) + break; dup->u.f.cond = isl_ast_expr_copy(node->u.f.cond); dup->u.f.inc = isl_ast_expr_copy(node->u.f.inc); - dup->u.f.body = isl_ast_node_copy(node->u.f.body); - if (!dup->u.f.iterator || !dup->u.f.init || !dup->u.f.cond || - !dup->u.f.inc || !dup->u.f.body) + if (!dup->u.f.cond || !dup->u.f.inc) return isl_ast_node_free(dup); break; case isl_ast_node_block: @@ -1068,6 +1157,12 @@ __isl_give isl_ast_node *isl_ast_node_dup(__isl_keep isl_ast_node *node) break; } + if (!node->annotation) + return dup; + dup->annotation = isl_id_copy(node->annotation); + if (!dup->annotation) + return isl_ast_node_free(dup); + return dup; } @@ -1124,36 +1219,137 @@ __isl_null isl_ast_node *isl_ast_node_free(__isl_take isl_ast_node *node) return NULL; } -/* Replace the body of the for node "node" by "body". +/* Check that "node" is of type "type", printing "msg" if not. */ -__isl_give isl_ast_node *isl_ast_node_for_set_body( - __isl_take isl_ast_node *node, __isl_take isl_ast_node *body) +static isl_stat isl_ast_node_check_type(__isl_keep isl_ast_node *node, + enum isl_ast_node_type type, const char *msg) { - node = isl_ast_node_cow(node); - if (!node || !body) - goto error; - if (node->type != isl_ast_node_for) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a for node", goto error); + if (!node) + return isl_stat_error; + if (node->type != type) + isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, msg, + return isl_stat_error); + return isl_stat_ok; +} - isl_ast_node_free(node->u.f.body); - node->u.f.body = body; +/* Check that "node" is of type isl_ast_node_block. + */ +static isl_stat isl_ast_node_check_block(__isl_keep isl_ast_node *node) +{ + return isl_ast_node_check_type(node, isl_ast_node_block, + "not a block node"); +} - return node; -error: - isl_ast_node_free(node); - isl_ast_node_free(body); - return NULL; +/* Check that "node" is of type isl_ast_node_if. + */ +static isl_stat isl_ast_node_check_if(__isl_keep isl_ast_node *node) +{ + return isl_ast_node_check_type(node, isl_ast_node_if, "not an if node"); +} + +/* Check that "node" is of type isl_ast_node_for. + */ +static isl_stat isl_ast_node_check_for(__isl_keep isl_ast_node *node) +{ + return isl_ast_node_check_type(node, isl_ast_node_for, + "not a for node"); +} + +/* Check that "node" is of type isl_ast_node_mark. + */ +static isl_stat isl_ast_node_check_mark(__isl_keep isl_ast_node *node) +{ + return isl_ast_node_check_type(node, isl_ast_node_mark, + "not a mark node"); +} + +/* Check that "node" is of type isl_ast_node_user. + */ +static isl_stat isl_ast_node_check_user(__isl_keep isl_ast_node *node) +{ + return isl_ast_node_check_type(node, isl_ast_node_user, + "not a user node"); +} + +#undef NODE_TYPE +#define NODE_TYPE for +#undef FIELD_NAME +#define FIELD_NAME init +#undef FIELD_TYPE +#define FIELD_TYPE isl_ast_expr +#undef FIELD +#define FIELD u.f.init +#include "isl_ast_node_set_field_templ.c" + +#undef NODE_TYPE +#define NODE_TYPE for +#undef FIELD_NAME +#define FIELD_NAME cond +#undef FIELD_TYPE +#define FIELD_TYPE isl_ast_expr +#undef FIELD +#define FIELD u.f.cond +#include "isl_ast_node_set_field_templ.c" + +#undef NODE_TYPE +#define NODE_TYPE for +#undef FIELD_NAME +#define FIELD_NAME inc +#undef FIELD_TYPE +#define FIELD_TYPE isl_ast_expr +#undef FIELD +#define FIELD u.f.inc +#include "isl_ast_node_set_field_templ.c" + +#undef NODE_TYPE +#define NODE_TYPE for +#undef FIELD_NAME +#define FIELD_NAME body +#undef FIELD_TYPE +#define FIELD_TYPE isl_ast_node +#undef FIELD +#define FIELD u.f.body +#include "isl_ast_node_set_field_templ.c" + +/* Return the body of the for-node "node", + * This may be either a copy or the body itself + * if there is only one reference to "node". + * This allows the body to be modified inplace + * if both "node" and its body have only a single reference. + * The caller is not allowed to modify "node" between this call and + * the subsequent call to isl_ast_node_for_restore_body. + * The only exception is that isl_ast_node_free can be called instead. + */ +static __isl_give isl_ast_node *isl_ast_node_for_take_body( + __isl_keep isl_ast_node *node) +{ + isl_ast_node *body; + + if (isl_ast_node_check_for(node) < 0) + return NULL; + if (node->ref != 1) + return isl_ast_node_for_get_body(node); + body = node->u.f.body; + node->u.f.body = NULL; + return body; +} + +/* Set the body of the for-node "node" to "body", + * where the body of "node" may be missing + * due to a preceding call to isl_ast_node_for_take_body. + * However, in this case, "node" only has a single reference. + */ +static __isl_give isl_ast_node *isl_ast_node_for_restore_body( + __isl_take isl_ast_node *node, __isl_take isl_ast_node *body) +{ + return isl_ast_node_for_set_body(node, body); } __isl_give isl_ast_node *isl_ast_node_for_get_body( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_for(node) < 0) return NULL; - if (node->type != isl_ast_node_for) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a for node", return NULL); return isl_ast_node_copy(node->u.f.body); } @@ -1171,33 +1367,24 @@ __isl_give isl_ast_node *isl_ast_node_for_mark_degenerate( isl_bool isl_ast_node_for_is_degenerate(__isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_for(node) < 0) return isl_bool_error; - if (node->type != isl_ast_node_for) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a for node", return isl_bool_error); return isl_bool_ok(node->u.f.degenerate); } __isl_give isl_ast_expr *isl_ast_node_for_get_iterator( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_for(node) < 0) return NULL; - if (node->type != isl_ast_node_for) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a for node", return NULL); return isl_ast_expr_copy(node->u.f.iterator); } __isl_give isl_ast_expr *isl_ast_node_for_get_init( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_for(node) < 0) return NULL; - if (node->type != isl_ast_node_for) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a for node", return NULL); return isl_ast_expr_copy(node->u.f.init); } @@ -1211,11 +1398,8 @@ __isl_give isl_ast_expr *isl_ast_node_for_get_init( __isl_give isl_ast_expr *isl_ast_node_for_get_cond( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_for(node) < 0) return NULL; - if (node->type != isl_ast_node_for) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a for node", return NULL); if (!node->u.f.degenerate) return isl_ast_expr_copy(node->u.f.cond); @@ -1232,36 +1416,55 @@ __isl_give isl_ast_expr *isl_ast_node_for_get_cond( __isl_give isl_ast_expr *isl_ast_node_for_get_inc( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_for(node) < 0) return NULL; - if (node->type != isl_ast_node_for) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a for node", return NULL); if (!node->u.f.degenerate) return isl_ast_expr_copy(node->u.f.inc); return isl_ast_expr_alloc_int_si(isl_ast_node_get_ctx(node), 1); } -/* Replace the then branch of the if node "node" by "child". - */ -__isl_give isl_ast_node *isl_ast_node_if_set_then( - __isl_take isl_ast_node *node, __isl_take isl_ast_node *child) +#undef NODE_TYPE +#define NODE_TYPE if +#undef FIELD_NAME +#define FIELD_NAME then +#undef FIELD_TYPE +#define FIELD_TYPE isl_ast_node +#undef FIELD +#define FIELD u.i.then +#include "isl_ast_node_set_field_templ.c" + +/* Return the then-branch of the if-node "node", + * This may be either a copy or the branch itself + * if there is only one reference to "node". + * This allows the branch to be modified inplace + * if both "node" and its then-branch have only a single reference. + * The caller is not allowed to modify "node" between this call and + * the subsequent call to isl_ast_node_if_restore_then_node. + * The only exception is that isl_ast_node_free can be called instead. + */ +static __isl_give isl_ast_node *isl_ast_node_if_take_then_node( + __isl_keep isl_ast_node *node) { - node = isl_ast_node_cow(node); - if (!node || !child) - goto error; - if (node->type != isl_ast_node_if) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not an if node", goto error); + isl_ast_node *then_node; - isl_ast_node_free(node->u.i.then); - node->u.i.then = child; + if (isl_ast_node_check_if(node) < 0) + return NULL; + if (node->ref != 1) + return isl_ast_node_if_get_then_node(node); + then_node = node->u.i.then; + node->u.i.then = NULL; + return then_node; +} - return node; -error: - isl_ast_node_free(node); - isl_ast_node_free(child); - return NULL; +/* Set the then-branch of the if-node "node" to "child", + * where the then-branch of "node" may be missing + * due to a preceding call to isl_ast_node_if_take_then_node. + * However, in this case, "node" only has a single reference. + */ +static __isl_give isl_ast_node *isl_ast_node_if_restore_then_node( + __isl_take isl_ast_node *node, __isl_take isl_ast_node *child) +{ + return isl_ast_node_if_set_then(node, child); } /* Return the then-node of the given if-node. @@ -1269,11 +1472,8 @@ error: __isl_give isl_ast_node *isl_ast_node_if_get_then_node( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_if(node) < 0) return NULL; - if (node->type != isl_ast_node_if) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not an if node", return NULL); return isl_ast_node_copy(node->u.i.then); } @@ -1289,11 +1489,8 @@ __isl_give isl_ast_node *isl_ast_node_if_get_then( */ isl_bool isl_ast_node_if_has_else_node(__isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_if(node) < 0) return isl_bool_error; - if (node->type != isl_ast_node_if) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not an if node", return isl_bool_error); return isl_bool_ok(node->u.i.else_node != NULL); } @@ -1310,11 +1507,8 @@ isl_bool isl_ast_node_if_has_else(__isl_keep isl_ast_node *node) __isl_give isl_ast_node *isl_ast_node_if_get_else_node( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_if(node) < 0) return NULL; - if (node->type != isl_ast_node_if) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not an if node", return NULL); return isl_ast_node_copy(node->u.i.else_node); } @@ -1326,36 +1520,117 @@ __isl_give isl_ast_node *isl_ast_node_if_get_else( return isl_ast_node_if_get_else_node(node); } +#undef NODE_TYPE +#define NODE_TYPE if +#undef FIELD_NAME +#define FIELD_NAME else_node +#undef FIELD_TYPE +#define FIELD_TYPE isl_ast_node +#undef FIELD +#define FIELD u.i.else_node +static +#include "isl_ast_node_set_field_templ.c" + +/* Return the else-branch of the if-node "node", + * This may be either a copy or the branch itself + * if there is only one reference to "node". + * This allows the branch to be modified inplace + * if both "node" and its else-branch have only a single reference. + * The caller is not allowed to modify "node" between this call and + * the subsequent call to isl_ast_node_if_restore_else_node. + * The only exception is that isl_ast_node_free can be called instead. + */ +static __isl_give isl_ast_node *isl_ast_node_if_take_else_node( + __isl_keep isl_ast_node *node) +{ + isl_ast_node *else_node; + + if (isl_ast_node_check_if(node) < 0) + return NULL; + if (node->ref != 1) + return isl_ast_node_if_get_else_node(node); + else_node = node->u.i.else_node; + node->u.i.else_node = NULL; + return else_node; +} + +/* Set the else-branch of the if-node "node" to "child", + * where the else-branch of "node" may be missing + * due to a preceding call to isl_ast_node_if_take_else_node. + * However, in this case, "node" only has a single reference. + */ +static __isl_give isl_ast_node *isl_ast_node_if_restore_else_node( + __isl_take isl_ast_node *node, __isl_take isl_ast_node *child) +{ + return isl_ast_node_if_set_else_node(node, child); +} + __isl_give isl_ast_expr *isl_ast_node_if_get_cond( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_if(node) < 0) return NULL; - if (node->type != isl_ast_node_if) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a guard node", return NULL); return isl_ast_expr_copy(node->u.i.guard); } __isl_give isl_ast_node_list *isl_ast_node_block_get_children( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_block(node) < 0) return NULL; - if (node->type != isl_ast_node_block) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a block node", return NULL); return isl_ast_node_list_copy(node->u.b.children); } +#undef NODE_TYPE +#define NODE_TYPE block +#undef FIELD_NAME +#define FIELD_NAME children +#undef FIELD_TYPE +#define FIELD_TYPE isl_ast_node_list +#undef FIELD +#define FIELD u.b.children +static +#include "isl_ast_node_set_field_templ.c" + +/* Return the children of the block-node "node", + * This may be either a copy or the children themselves + * if there is only one reference to "node". + * This allows the children to be modified inplace + * if both "node" and its children have only a single reference. + * The caller is not allowed to modify "node" between this call and + * the subsequent call to isl_ast_node_block_restore_children. + * The only exception is that isl_ast_node_free can be called instead. + */ +static __isl_give isl_ast_node_list *isl_ast_node_block_take_children( + __isl_keep isl_ast_node *node) +{ + isl_ast_node_list *children; + + if (isl_ast_node_check_block(node) < 0) + return NULL; + if (node->ref != 1) + return isl_ast_node_block_get_children(node); + children = node->u.b.children; + node->u.b.children = NULL; + return children; +} + +/* Set the children of the block-node "node" to "children", + * where the children of "node" may be missing + * due to a preceding call to isl_ast_node_block_take_children. + * However, in this case, "node" only has a single reference. + */ +static __isl_give isl_ast_node *isl_ast_node_block_restore_children( + __isl_take isl_ast_node *node, __isl_take isl_ast_node_list *children) +{ + return isl_ast_node_block_set_children(node, children); +} + __isl_give isl_ast_expr *isl_ast_node_user_get_expr( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_user(node) < 0) return NULL; - if (node->type != isl_ast_node_user) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a user node", return NULL); return isl_ast_expr_copy(node->u.e.expr); } @@ -1364,11 +1639,8 @@ __isl_give isl_ast_expr *isl_ast_node_user_get_expr( */ __isl_give isl_id *isl_ast_node_mark_get_id(__isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_mark(node) < 0) return NULL; - if (node->type != isl_ast_node_mark) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a mark node", return NULL); return isl_id_copy(node->u.m.mark); } @@ -1378,61 +1650,229 @@ __isl_give isl_id *isl_ast_node_mark_get_id(__isl_keep isl_ast_node *node) __isl_give isl_ast_node *isl_ast_node_mark_get_node( __isl_keep isl_ast_node *node) { - if (!node) + if (isl_ast_node_check_mark(node) < 0) return NULL; - if (node->type != isl_ast_node_mark) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a mark node", return NULL); return isl_ast_node_copy(node->u.m.node); } +#undef NODE_TYPE +#define NODE_TYPE mark +#undef FIELD_NAME +#define FIELD_NAME node +#undef FIELD_TYPE +#define FIELD_TYPE isl_ast_node +#undef FIELD +#define FIELD u.m.node +static +#include "isl_ast_node_set_field_templ.c" + +/* Return the child of the mark-node "node", + * This may be either a copy or the child itself + * if there is only one reference to "node". + * This allows the child to be modified inplace + * if both "node" and its child have only a single reference. + * The caller is not allowed to modify "node" between this call and + * the subsequent call to isl_ast_node_mark_restore_node. + * The only exception is that isl_ast_node_free can be called instead. + */ +static __isl_give isl_ast_node *isl_ast_node_mark_take_node( + __isl_keep isl_ast_node *node) +{ + isl_ast_node *child; + + if (isl_ast_node_check_mark(node) < 0) + return NULL; + if (node->ref != 1) + return isl_ast_node_mark_get_node(node); + child = node->u.m.node; + node->u.m.node = NULL; + return child; +} + +/* Set the child of the mark-node "node" to "child", + * where the child of "node" may be missing + * due to a preceding call to isl_ast_node_mark_take_node. + * However, in this case, "node" only has a single reference. + */ +static __isl_give isl_ast_node *isl_ast_node_mark_restore_node( + __isl_take isl_ast_node *node, __isl_take isl_ast_node *child) +{ + return isl_ast_node_mark_set_node(node, child); +} + __isl_give isl_id *isl_ast_node_get_annotation(__isl_keep isl_ast_node *node) { return node ? isl_id_copy(node->annotation) : NULL; } +/* Check that "node" is of any type. + * That is, simply check that it is a valid node. + */ +static isl_stat isl_ast_node_check_any(__isl_keep isl_ast_node *node) +{ + return isl_stat_non_null(node); +} + +#undef NODE_TYPE +#define NODE_TYPE any +#undef FIELD_NAME +#define FIELD_NAME annotation +#undef FIELD_TYPE +#define FIELD_TYPE isl_id +#undef FIELD +#define FIELD annotation +static +#include "isl_ast_node_set_field_templ.c" + /* Replace node->annotation by "annotation". */ __isl_give isl_ast_node *isl_ast_node_set_annotation( __isl_take isl_ast_node *node, __isl_take isl_id *annotation) { - node = isl_ast_node_cow(node); - if (!node || !annotation) - goto error; - - isl_id_free(node->annotation); - node->annotation = annotation; - - return node; -error: - isl_id_free(annotation); - return isl_ast_node_free(node); + return isl_ast_node_any_set_annotation(node, annotation); } +static __isl_give isl_ast_node *traverse(__isl_take isl_ast_node *node, + __isl_give isl_ast_node *(*enter)(__isl_take isl_ast_node *node, + int *more, void *user), + __isl_give isl_ast_node *(*leave)(__isl_take isl_ast_node *node, + void *user), + void *user); + /* Traverse the elements of "list" and all their descendants - * in depth first preorder. + * in depth first preorder. Call "enter" whenever a node is entered and "leave" + * whenever a node is left. * - * Return isl_stat_ok on success and isl_stat_error on failure. - */ -static isl_stat nodelist_foreach(__isl_keep isl_ast_node_list *list, - isl_bool (*fn)(__isl_keep isl_ast_node *node, void *user), void *user) + * Return the updated node. + */ +static __isl_give isl_ast_node_list *traverse_list( + __isl_take isl_ast_node_list *list, + __isl_give isl_ast_node *(*enter)(__isl_take isl_ast_node *node, + int *more, void *user), + __isl_give isl_ast_node *(*leave)(__isl_take isl_ast_node *node, + void *user), + void *user) { int i; + isl_size n; - if (!list) - return isl_stat_error; + n = isl_ast_node_list_size(list); + if (n < 0) + return isl_ast_node_list_free(list); - for (i = 0; i < list->n; ++i) { - isl_stat ok; - isl_ast_node *node = list->p[i]; + for (i = 0; i < n; ++i) { + isl_ast_node *node; - ok = isl_ast_node_foreach_descendant_top_down(node, fn, user); - if (ok < 0) - return isl_stat_error; + node = isl_ast_node_list_get_at(list, i); + node = traverse(node, enter, leave, user); + list = isl_ast_node_list_set_at(list, i, node); } - return isl_stat_ok; + return list; +} + +/* Traverse the descendants of "node" (including the node itself) + * in depth first preorder. Call "enter" whenever a node is entered and "leave" + * whenever a node is left. + * + * If "enter" sets the "more" argument to zero, then the subtree rooted + * at the given node is skipped. + * + * Return the updated node. + */ +static __isl_give isl_ast_node *traverse(__isl_take isl_ast_node *node, + __isl_give isl_ast_node *(*enter)(__isl_take isl_ast_node *node, + int *more, void *user), + __isl_give isl_ast_node *(*leave)(__isl_take isl_ast_node *node, + void *user), + void *user) +{ + int more; + isl_bool has_else; + isl_ast_node *child; + isl_ast_node_list *children; + + node = enter(node, &more, user); + if (!node) + return NULL; + if (!more) + return node; + + switch (node->type) { + case isl_ast_node_for: + child = isl_ast_node_for_take_body(node); + child = traverse(child, enter, leave, user); + node = isl_ast_node_for_restore_body(node, child); + return leave(node, user); + case isl_ast_node_if: + child = isl_ast_node_if_take_then_node(node); + child = traverse(child, enter, leave, user); + node = isl_ast_node_if_restore_then_node(node, child); + has_else = isl_ast_node_if_has_else_node(node); + if (has_else < 0) + return isl_ast_node_free(node); + if (!has_else) + return leave(node, user); + child = isl_ast_node_if_take_else_node(node); + child = traverse(child, enter, leave, user); + node = isl_ast_node_if_restore_else_node(node, child); + return leave(node, user); + case isl_ast_node_block: + children = isl_ast_node_block_take_children(node); + children = traverse_list(children, enter, leave, user); + node = isl_ast_node_block_restore_children(node, children); + return leave(node, user); + case isl_ast_node_mark: + child = isl_ast_node_mark_take_node(node); + child = traverse(child, enter, leave, user); + node = isl_ast_node_mark_restore_node(node, child); + return leave(node, user); + case isl_ast_node_user: + return leave(node, user); + case isl_ast_node_error: + return isl_ast_node_free(node); + } + + return node; +} + +/* Internal data structure storing the arguments of + * isl_ast_node_foreach_descendant_top_down. + */ +struct isl_ast_node_preorder_data { + isl_bool (*fn)(__isl_keep isl_ast_node *node, void *user); + void *user; +}; + +/* Enter "node" and set *more to continue traversing its descendants. + * + * In the case of a depth first preorder traversal, call data->fn and + * let it decide whether to continue. + */ +static __isl_give isl_ast_node *preorder_enter(__isl_take isl_ast_node *node, + int *more, void *user) +{ + struct isl_ast_node_preorder_data *data = user; + isl_bool m; + + if (!node) + return NULL; + m = data->fn(node, data->user); + if (m < 0) + return isl_ast_node_free(node); + *more = m; + return node; +} + +/* Leave "node". + * + * In the case of a depth first preorder traversal, nothing needs to be done. + */ +static __isl_give isl_ast_node *preorder_leave(__isl_take isl_ast_node *node, + void *user) +{ + return node; } /* Traverse the descendants of "node" (including the node itself) @@ -1449,43 +1889,66 @@ isl_stat isl_ast_node_foreach_descendant_top_down( __isl_keep isl_ast_node *node, isl_bool (*fn)(__isl_keep isl_ast_node *node, void *user), void *user) { - isl_bool more; - isl_stat ok; + struct isl_ast_node_preorder_data data = { fn, user }; + + node = isl_ast_node_copy(node); + node = traverse(node, &preorder_enter, &preorder_leave, &data); + isl_ast_node_free(node); + + return isl_stat_non_null(node); +} + +/* Internal data structure storing the arguments of + * isl_ast_node_map_descendant_bottom_up. + */ +struct isl_ast_node_postorder_data { + __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node, + void *user); + void *user; +}; + +/* Enter "node" and set *more to continue traversing its descendants. + * + * In the case of a depth-first post-order traversal, + * nothing needs to be done and traversal always continues. + */ +static __isl_give isl_ast_node *postorder_enter(__isl_take isl_ast_node *node, + int *more, void *user) +{ + *more = 1; + return node; +} + +/* Leave "node". + * + * In the case of a depth-first post-order traversal, call data->fn. + */ +static __isl_give isl_ast_node *postorder_leave(__isl_take isl_ast_node *node, + void *user) +{ + struct isl_ast_node_postorder_data *data = user; if (!node) - return isl_stat_error; + return NULL; - more = fn(node, user); - if (more < 0) - return isl_stat_error; - if (!more) - return isl_stat_ok; + node = data->fn(node, data->user); + return node; +} - switch (node->type) { - case isl_ast_node_for: - node = node->u.f.body; - return isl_ast_node_foreach_descendant_top_down(node, fn, user); - case isl_ast_node_if: - ok = isl_ast_node_foreach_descendant_top_down(node->u.i.then, - fn, user); - if (ok < 0) - return isl_stat_error; - if (!node->u.i.else_node) - return isl_stat_ok; - node = node->u.i.else_node; - return isl_ast_node_foreach_descendant_top_down(node, fn, user); - case isl_ast_node_block: - return nodelist_foreach(node->u.b.children, fn, user); - case isl_ast_node_mark: - node = node->u.m.node; - return isl_ast_node_foreach_descendant_top_down(node, fn, user); - case isl_ast_node_user: - break; - case isl_ast_node_error: - return isl_stat_error; - } +/* Traverse the descendants of "node" (including the node itself) + * in depth-first post-order, where the user callback is allowed to modify the + * visited node. + * + * Return the updated node. + */ +__isl_give isl_ast_node *isl_ast_node_map_descendant_bottom_up( + __isl_take isl_ast_node *node, + __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node, + void *user), void *user) +{ + struct isl_ast_node_postorder_data data = { fn, user }; - return isl_stat_ok; + return traverse(node, &postorder_enter, &postorder_leave, &data); } /* Textual C representation of the various operators. @@ -1644,21 +2107,30 @@ static int sub_expr_need_parens(enum isl_ast_expr_op_type op, return 0; } -/* Print "expr" as a subexpression of an "op" operation in C format. +/* Print the subexpression at position "pos" of operation expression "expr" + * in C format. * If "left" is set, then "expr" is the left-most operand. */ static __isl_give isl_printer *print_sub_expr_c(__isl_take isl_printer *p, - enum isl_ast_expr_op_type op, __isl_keep isl_ast_expr *expr, int left) + __isl_keep isl_ast_expr *expr, int pos, int left) { int need_parens; + isl_ast_expr *arg; - need_parens = sub_expr_need_parens(op, expr, left); + if (!expr) + return isl_printer_free(p); + + arg = isl_ast_expr_list_get_at(expr->u.op.args, pos); + need_parens = sub_expr_need_parens(expr->u.op.op, arg, left); if (need_parens) p = isl_printer_print_str(p, "("); - p = print_ast_expr_c(p, expr); + p = print_ast_expr_c(p, arg); if (need_parens) p = isl_printer_print_str(p, ")"); + + isl_ast_expr_free(arg); + return p; } @@ -1822,21 +2294,40 @@ static const char *get_op_str_c(__isl_keep isl_printer *p, return op_str_c[type]; } +/* Print the expression at position "pos" in "list" in C format. + */ +static __isl_give isl_printer *print_at_c(__isl_take isl_printer *p, + __isl_keep isl_ast_expr_list *list, int pos) +{ + isl_ast_expr *expr; + + expr = isl_ast_expr_list_get_at(list, pos); + p = print_ast_expr_c(p, expr); + isl_ast_expr_free(expr); + + return p; +} + /* Print a min or max reduction "expr" in C format. */ static __isl_give isl_printer *print_min_max_c(__isl_take isl_printer *p, __isl_keep isl_ast_expr *expr) { int i = 0; + isl_size n; - for (i = 1; i < expr->u.op.n_arg; ++i) { + n = isl_ast_expr_list_size(expr->u.op.args); + if (n < 0) + return isl_printer_free(p); + + for (i = 1; i < n; ++i) { p = isl_printer_print_str(p, get_op_str_c(p, expr->u.op.op)); p = isl_printer_print_str(p, "("); } - p = isl_printer_print_ast_expr(p, expr->u.op.args[0]); - for (i = 1; i < expr->u.op.n_arg; ++i) { + p = print_at_c(p, expr->u.op.args, 0); + for (i = 1; i < n; ++i) { p = isl_printer_print_str(p, ", "); - p = print_ast_expr_c(p, expr->u.op.args[i]); + p = print_at_c(p, expr->u.op.args, i); p = isl_printer_print_str(p, ")"); } @@ -1851,13 +2342,18 @@ static __isl_give isl_printer *print_call_c(__isl_take isl_printer *p, __isl_keep isl_ast_expr *expr) { int i = 0; + isl_size n; - p = print_ast_expr_c(p, expr->u.op.args[0]); + n = isl_ast_expr_list_size(expr->u.op.args); + if (n < 0) + return isl_printer_free(p); + + p = print_at_c(p, expr->u.op.args, 0); p = isl_printer_print_str(p, "("); - for (i = 1; i < expr->u.op.n_arg; ++i) { + for (i = 1; i < n; ++i) { if (i != 1) p = isl_printer_print_str(p, ", "); - p = print_ast_expr_c(p, expr->u.op.args[i]); + p = print_at_c(p, expr->u.op.args, i); } p = isl_printer_print_str(p, ")"); @@ -1872,11 +2368,16 @@ static __isl_give isl_printer *print_access_c(__isl_take isl_printer *p, __isl_keep isl_ast_expr *expr) { int i = 0; + isl_size n; + + n = isl_ast_expr_list_size(expr->u.op.args); + if (n < 0) + return isl_printer_free(p); - p = print_ast_expr_c(p, expr->u.op.args[0]); - for (i = 1; i < expr->u.op.n_arg; ++i) { + p = print_at_c(p, expr->u.op.args, 0); + for (i = 1; i < n; ++i) { p = isl_printer_print_str(p, "["); - p = print_ast_expr_c(p, expr->u.op.args[i]); + p = print_at_c(p, expr->u.op.args, i); p = isl_printer_print_str(p, "]"); } @@ -1888,6 +2389,8 @@ static __isl_give isl_printer *print_access_c(__isl_take isl_printer *p, static __isl_give isl_printer *print_ast_expr_c(__isl_take isl_printer *p, __isl_keep isl_ast_expr *expr) { + isl_size n; + if (!p) return NULL; if (!expr) @@ -1903,11 +2406,13 @@ static __isl_give isl_printer *print_ast_expr_c(__isl_take isl_printer *p, p = print_access_c(p, expr); break; } - if (expr->u.op.n_arg == 1) { + n = isl_ast_expr_list_size(expr->u.op.args); + if (n < 0) + return isl_printer_free(p); + if (n == 1) { p = isl_printer_print_str(p, get_op_str_c(p, expr->u.op.op)); - p = print_sub_expr_c(p, expr->u.op.op, - expr->u.op.args[0], 0); + p = print_sub_expr_c(p, expr, 0, 0); break; } if (expr->u.op.op == isl_ast_expr_op_fdiv_q) { @@ -1916,9 +2421,9 @@ static __isl_give isl_printer *print_ast_expr_c(__isl_take isl_printer *p, name = get_op_str_c(p, isl_ast_expr_op_fdiv_q); p = isl_printer_print_str(p, name); p = isl_printer_print_str(p, "("); - p = print_ast_expr_c(p, expr->u.op.args[0]); + p = print_at_c(p, expr->u.op.args, 0); p = isl_printer_print_str(p, ", "); - p = print_ast_expr_c(p, expr->u.op.args[1]); + p = print_at_c(p, expr->u.op.args, 1); p = isl_printer_print_str(p, ")"); break; } @@ -1929,24 +2434,24 @@ static __isl_give isl_printer *print_ast_expr_c(__isl_take isl_printer *p, } if (expr->u.op.op == isl_ast_expr_op_cond || expr->u.op.op == isl_ast_expr_op_select) { - p = print_ast_expr_c(p, expr->u.op.args[0]); + p = print_at_c(p, expr->u.op.args, 0); p = isl_printer_print_str(p, " ? "); - p = print_ast_expr_c(p, expr->u.op.args[1]); + p = print_at_c(p, expr->u.op.args, 1); p = isl_printer_print_str(p, " : "); - p = print_ast_expr_c(p, expr->u.op.args[2]); + p = print_at_c(p, expr->u.op.args, 2); break; } - if (expr->u.op.n_arg != 2) + if (n != 2) isl_die(isl_printer_get_ctx(p), isl_error_internal, "operation should have two arguments", return isl_printer_free(p)); - p = print_sub_expr_c(p, expr->u.op.op, expr->u.op.args[0], 1); + p = print_sub_expr_c(p, expr, 0, 1); if (expr->u.op.op != isl_ast_expr_op_member) p = isl_printer_print_str(p, " "); p = isl_printer_print_str(p, get_op_str_c(p, expr->u.op.op)); if (expr->u.op.op != isl_ast_expr_op_member) p = isl_printer_print_str(p, " "); - p = print_sub_expr_c(p, expr->u.op.op, expr->u.op.args[1], 0); + p = print_sub_expr_c(p, expr, 1, 0); break; case isl_ast_expr_id: p = isl_printer_print_str(p, isl_id_get_name(expr->u.id)); @@ -2030,6 +2535,14 @@ static __isl_give isl_printer *print_arguments(__isl_take isl_printer *p, return p; } +/* Textual representations of the YAML keys for an isl_ast_expr object. + */ +static char *expr_str[] = { + [isl_ast_expr_op] = "op", + [isl_ast_expr_id] = "id", + [isl_ast_expr_int] = "val", +}; + /* Print "expr" to "p" in isl format. * * In particular, print the isl_ast_expr as a YAML document. @@ -2054,21 +2567,21 @@ static __isl_give isl_printer *print_ast_expr_isl(__isl_take isl_printer *p, op = isl_ast_expr_get_op_type(expr); if (op == isl_ast_expr_op_error) return isl_printer_free(p); - p = isl_printer_print_str(p, "op"); + p = isl_printer_print_str(p, expr_str[type]); p = isl_printer_yaml_next(p); p = isl_printer_print_str(p, op_str[op]); p = isl_printer_yaml_next(p); p = print_arguments(p, expr); break; case isl_ast_expr_id: - p = isl_printer_print_str(p, "id"); + p = isl_printer_print_str(p, expr_str[type]); p = isl_printer_yaml_next(p); id = isl_ast_expr_get_id(expr); p = isl_printer_print_id(p, id); isl_id_free(id); break; case isl_ast_expr_int: - p = isl_printer_print_str(p, "val"); + p = isl_printer_print_str(p, expr_str[type]); p = isl_printer_yaml_next(p); v = isl_ast_expr_get_val(expr); p = isl_printer_print_val(p, v); @@ -2109,6 +2622,176 @@ __isl_give isl_printer *isl_printer_print_ast_expr(__isl_take isl_printer *p, return p; } +#undef KEY +#define KEY enum isl_ast_expr_op_type +#undef KEY_ERROR +#define KEY_ERROR isl_ast_expr_op_error +#undef KEY_END +#define KEY_END (isl_ast_expr_op_address_of + 1) +#undef KEY_STR +#define KEY_STR op_str +#undef KEY_EXTRACT +#define KEY_EXTRACT extract_op_type +#undef KEY_GET +#define KEY_GET get_op_type +#include "extract_key.c" + +/* Return the next token, which is assumed to be a key in a YAML mapping, + * from "s" as a string. + */ +static __isl_give char *next_key(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + char *str; + isl_ctx *ctx; + + if (!s) + return NULL; + tok = isl_stream_next_token(s); + if (!tok) { + isl_stream_error(s, NULL, "unexpected EOF"); + return NULL; + } + ctx = isl_stream_get_ctx(s); + str = isl_token_get_str(ctx, tok); + isl_token_free(tok); + return str; +} + +/* Remove the next token, which is assumed to be the key "expected" + * in a YAML mapping, from "s" and move to the corresponding value. + */ +static isl_stat eat_key(__isl_keep isl_stream *s, const char *expected) +{ + char *str; + int ok; + + str = next_key(s); + if (!str) + return isl_stat_error; + ok = !strcmp(str, expected); + free(str); + + if (!ok) { + isl_stream_error(s, NULL, "expecting different key"); + return isl_stat_error; + } + + if (isl_stream_yaml_next(s) < 0) + return isl_stat_error; + + return isl_stat_ok; +} + +#undef EL_BASE +#define EL_BASE ast_expr + +#include <isl_list_read_yaml_templ.c> + +/* Read an isl_ast_expr object of type isl_ast_expr_op from "s", + * where the "op" key has already been read by the caller. + * + * Read the operation type and the arguments and + * return the corresponding isl_ast_expr object. + */ +static __isl_give isl_ast_expr *read_op(__isl_keep isl_stream *s) +{ + enum isl_ast_expr_op_type op; + isl_ast_expr_list *list; + + op = get_op_type(s); + if (op < 0) + return NULL; + if (isl_stream_yaml_next(s) < 0) + return NULL; + if (eat_key(s, "args") < 0) + return NULL; + + list = isl_stream_yaml_read_ast_expr_list(s); + + return alloc_op(op, list); +} + +/* Read an isl_ast_expr object of type isl_ast_expr_id from "s", + * where the "id" key has already been read by the caller. + */ +static __isl_give isl_ast_expr *read_id(__isl_keep isl_stream *s) +{ + return isl_ast_expr_from_id(isl_stream_read_id(s)); +} + +/* Read an isl_ast_expr object of type isl_ast_expr_int from "s", + * where the "val" key has already been read by the caller. + */ +static __isl_give isl_ast_expr *read_int(__isl_keep isl_stream *s) +{ + return isl_ast_expr_from_val(isl_stream_read_val(s)); +} + +#undef KEY +#define KEY enum isl_ast_expr_type +#undef KEY_ERROR +#define KEY_ERROR isl_ast_expr_error +#undef KEY_END +#define KEY_END (isl_ast_expr_int + 1) +#undef KEY_STR +#define KEY_STR expr_str +#undef KEY_EXTRACT +#define KEY_EXTRACT extract_expr_type +#undef KEY_GET +#define KEY_GET get_expr_type +#include "extract_key.c" + +/* Read an isl_ast_expr object from "s". + * + * The keys in the YAML mapping are assumed to appear + * in the same order as the one in which they are printed + * by print_ast_expr_isl. + * In particular, the isl_ast_expr_op type, which is the only one + * with more than one element, is identified by the "op" key and + * not by the "args" key. + */ +__isl_give isl_ast_expr *isl_stream_read_ast_expr(__isl_keep isl_stream *s) +{ + enum isl_ast_expr_type type; + isl_bool more; + isl_ast_expr *expr; + + if (isl_stream_yaml_read_start_mapping(s)) + return NULL; + more = isl_stream_yaml_next(s); + if (more < 0) + return NULL; + if (!more) { + isl_stream_error(s, NULL, "missing key"); + return NULL; + } + + type = get_expr_type(s); + if (type < 0) + return NULL; + if (isl_stream_yaml_next(s) < 0) + return NULL; + switch (type) { + case isl_ast_expr_op: + expr = read_op(s); + break; + case isl_ast_expr_id: + expr = read_id(s); + break; + case isl_ast_expr_int: + expr = read_int(s); + break; + case isl_ast_expr_error: + return NULL; + } + + if (isl_stream_yaml_read_end_mapping(s) < 0) + return isl_ast_expr_free(expr); + + return expr; +} + static __isl_give isl_printer *print_ast_node_isl(__isl_take isl_printer *p, __isl_keep isl_ast_node *node); @@ -2493,11 +3176,8 @@ static __isl_give isl_printer *print_ast_node_c(__isl_take isl_printer *p, __isl_give isl_printer *isl_ast_node_for_print(__isl_keep isl_ast_node *node, __isl_take isl_printer *p, __isl_take isl_ast_print_options *options) { - if (!node || !options) + if (isl_ast_node_check_for(node) < 0 || !options) goto error; - if (node->type != isl_ast_node_for) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not a for node", goto error); p = print_for_c(p, node, options, 0, 0); isl_ast_print_options_free(options); return p; @@ -2512,11 +3192,8 @@ error: __isl_give isl_printer *isl_ast_node_if_print(__isl_keep isl_ast_node *node, __isl_take isl_printer *p, __isl_take isl_ast_print_options *options) { - if (!node || !options) + if (isl_ast_node_check_if(node) < 0 || !options) goto error; - if (node->type != isl_ast_node_if) - isl_die(isl_ast_node_get_ctx(node), isl_error_invalid, - "not an if node", goto error); p = print_if_c(p, node, options, 1, 0); isl_ast_print_options_free(options); return p; @@ -2603,6 +3280,284 @@ __isl_give isl_printer *isl_ast_node_list_print( return p; } +/* Is the next token on "s" the start of a YAML sequence + * (rather than a YAML mapping)? + * + * A YAML sequence starts with either a '[' or a '-', depending on the format. + */ +static isl_bool next_is_sequence(__isl_keep isl_stream *s) +{ + struct isl_token *tok; + int type; + int seq; + + tok = isl_stream_next_token(s); + if (!tok) + return isl_bool_error; + type = isl_token_get_type(tok); + seq = type == '[' || type == '-'; + isl_stream_push_token(s, tok); + + return isl_bool_ok(seq); +} + +#undef EL_BASE +#define EL_BASE ast_node + +#include <isl_list_read_yaml_templ.c> + +/* Read an isl_ast_node object of type isl_ast_node_block from "s". + */ +static __isl_give isl_ast_node *read_block(__isl_keep isl_stream *s) +{ + isl_ast_node_list *children; + + children = isl_stream_yaml_read_ast_node_list(s); + return isl_ast_node_block_from_children(children); +} + +/* Textual representation of the first YAML key used + * while printing an isl_ast_node of a given type. + * + * An isl_ast_node of type isl_ast_node_block is not printed + * as a YAML mapping and is therefore assigned a dummy key. + */ +static char *node_first_str[] = { + [isl_ast_node_for] = "iterator", + [isl_ast_node_mark] = "mark", + [isl_ast_node_user] = "user", + [isl_ast_node_if] = "guard", + [isl_ast_node_block] = "", +}; + +#undef KEY +#define KEY enum isl_ast_node_type +#undef KEY_ERROR +#define KEY_ERROR isl_ast_node_error +#undef KEY_END +#define KEY_END (isl_ast_node_user + 1) +#undef KEY_STR +#define KEY_STR node_first_str +#undef KEY_EXTRACT +#define KEY_EXTRACT extract_node_type +#undef KEY_GET +#define KEY_GET get_node_type +#include "extract_key.c" + +static __isl_give isl_ast_node *read_body(__isl_keep isl_stream *s, + __isl_take isl_ast_node *node) +{ + if (eat_key(s, "body") < 0) + return isl_ast_node_free(node); + node = isl_ast_node_for_set_body(node, isl_stream_read_ast_node(s)); + if (isl_stream_yaml_next(s) < 0) + return isl_ast_node_free(node); + return node; +} + +/* Read an isl_ast_node object of type isl_ast_node_for from "s", + * where the initial "iterator" key has already been read by the caller. + * + * If the initial value is printed as the value of the key "value", + * then the for-loop is degenerate and can at most have + * a further "body" element. + * Otherwise, the for-loop also has "cond" and "inc" elements. + */ +static __isl_give isl_ast_node *read_for(__isl_keep isl_stream *s) +{ + isl_id *id; + isl_ast_expr *expr; + isl_ast_node *node; + char *key; + isl_bool more; + int is_value, is_init; + + expr = isl_stream_read_ast_expr(s); + id = isl_ast_expr_id_get_id(expr); + isl_ast_expr_free(expr); + if (!id) + return NULL; + if (isl_stream_yaml_next(s) < 0) + id = isl_id_free(id); + + node = isl_ast_node_alloc_for(id); + + key = next_key(s); + if (!key) + return isl_ast_node_free(node); + is_value = !strcmp(key, "value"); + is_init = !strcmp(key, "init"); + free(key); + if (!is_value && !is_init) + isl_die(isl_stream_get_ctx(s), isl_error_invalid, + "unexpected key", return isl_ast_node_free(node)); + if (isl_stream_yaml_next(s) < 0) + return isl_ast_node_free(node); + node = isl_ast_node_for_set_init(node, isl_stream_read_ast_expr(s)); + if ((more = isl_stream_yaml_next(s)) < 0) + return isl_ast_node_free(node); + if (is_value) { + node = isl_ast_node_for_mark_degenerate(node); + if (more) + node = read_body(s, node); + return node; + } + + if (eat_key(s, "cond") < 0) + return isl_ast_node_free(node); + node = isl_ast_node_for_set_cond(node, isl_stream_read_ast_expr(s)); + if (isl_stream_yaml_next(s) < 0) + return isl_ast_node_free(node); + if (eat_key(s, "inc") < 0) + return isl_ast_node_free(node); + node = isl_ast_node_for_set_inc(node, isl_stream_read_ast_expr(s)); + if ((more = isl_stream_yaml_next(s)) < 0) + return isl_ast_node_free(node); + + if (more) + node = read_body(s, node); + + return node; +} + +/* Read an isl_ast_node object of type isl_ast_node_mark from "s", + * where the initial "mark" key has already been read by the caller. + */ +static __isl_give isl_ast_node *read_mark(__isl_keep isl_stream *s) +{ + isl_id *id; + isl_ast_node *node; + + id = isl_stream_read_id(s); + if (!id) + return NULL; + if (isl_stream_yaml_next(s) < 0) + goto error; + if (eat_key(s, "node") < 0) + goto error; + node = isl_stream_read_ast_node(s); + node = isl_ast_node_alloc_mark(id, node); + if (isl_stream_yaml_next(s) < 0) + return isl_ast_node_free(node); + return node; +error: + isl_id_free(id); + return NULL; +} + +/* Read an isl_ast_node object of type isl_ast_node_user from "s", + * where the "user" key has already been read by the caller. + */ +static __isl_give isl_ast_node *read_user(__isl_keep isl_stream *s) +{ + isl_ast_node *node; + + node = isl_ast_node_alloc_user(isl_stream_read_ast_expr(s)); + if (isl_stream_yaml_next(s) < 0) + return isl_ast_node_free(node); + return node; +} + +/* Read an isl_ast_node object of type isl_ast_node_if from "s", + * where the initial "guard" key has already been read by the caller. + */ +static __isl_give isl_ast_node *read_if(__isl_keep isl_stream *s) +{ + isl_bool more; + isl_ast_node *node; + + node = isl_ast_node_alloc_if(isl_stream_read_ast_expr(s)); + if ((more = isl_stream_yaml_next(s)) < 0) + return isl_ast_node_free(node); + if (!more) + return node; + + if (eat_key(s, "then") < 0) + return isl_ast_node_free(node); + node = isl_ast_node_if_set_then(node, isl_stream_read_ast_node(s)); + if ((more = isl_stream_yaml_next(s)) < 0) + return isl_ast_node_free(node); + if (!more) + return node; + + if (eat_key(s, "else") < 0) + return isl_ast_node_free(node); + node = isl_ast_node_if_set_else_node(node, isl_stream_read_ast_node(s)); + if (isl_stream_yaml_next(s) < 0) + return isl_ast_node_free(node); + + return node; +} + +/* Read an isl_ast_node object from "s". + * + * A block node is printed as a YAML sequence by print_ast_node_isl. + * Every other node type is printed as a YAML mapping. + * + * First check if the next element is a sequence and if so, + * read a block node. + * Otherwise, read a node based on the first mapping key + * that is used to print a node type. + * Note that the keys in the YAML mapping are assumed to appear + * in the same order as the one in which they are printed + * by print_ast_node_isl. + */ +__isl_give isl_ast_node *isl_stream_read_ast_node(__isl_keep isl_stream *s) +{ + enum isl_ast_node_type type; + isl_bool more; + isl_bool seq; + isl_ast_node *node; + + seq = next_is_sequence(s); + if (seq < 0) + return NULL; + if (seq) + return read_block(s); + + if (isl_stream_yaml_read_start_mapping(s)) + return NULL; + more = isl_stream_yaml_next(s); + if (more < 0) + return NULL; + if (!more) { + isl_stream_error(s, NULL, "missing key"); + return NULL; + } + + type = get_node_type(s); + if (type < 0) + return NULL; + if (isl_stream_yaml_next(s) < 0) + return NULL; + + switch (type) { + case isl_ast_node_block: + isl_die(isl_stream_get_ctx(s), isl_error_internal, + "block cannot be detected as mapping", + return NULL); + case isl_ast_node_for: + node = read_for(s); + break; + case isl_ast_node_mark: + node = read_mark(s); + break; + case isl_ast_node_user: + node = read_user(s); + break; + case isl_ast_node_if: + node = read_if(s); + break; + case isl_ast_node_error: + return NULL; + } + + if (isl_stream_yaml_read_end_mapping(s) < 0) + return isl_ast_node_free(node); + + return node; +} + #define ISL_AST_MACRO_FDIV_Q (1 << 0) #define ISL_AST_MACRO_MIN (1 << 1) #define ISL_AST_MACRO_MAX (1 << 2) @@ -2610,13 +3565,26 @@ __isl_give isl_printer *isl_ast_node_list_print( ISL_AST_MACRO_MIN | \ ISL_AST_MACRO_MAX) +static int ast_expr_required_macros(__isl_keep isl_ast_expr *expr, int macros); + +/* Wrapper around ast_expr_required_macros for use + * as an isl_ast_expr_list_foreach callback. + */ +static isl_stat entry_required_macros(__isl_take isl_ast_expr *expr, void *user) +{ + int *macros = user; + + *macros = ast_expr_required_macros(expr, *macros); + isl_ast_expr_free(expr); + + return isl_stat_ok; +} + /* If "expr" contains an isl_ast_expr_op_min, isl_ast_expr_op_max or * isl_ast_expr_op_fdiv_q then set the corresponding bit in "macros". */ static int ast_expr_required_macros(__isl_keep isl_ast_expr *expr, int macros) { - int i; - if (macros == ISL_AST_MACRO_ALL) return macros; @@ -2630,8 +3598,8 @@ static int ast_expr_required_macros(__isl_keep isl_ast_expr *expr, int macros) if (expr->u.op.op == isl_ast_expr_op_fdiv_q) macros |= ISL_AST_MACRO_FDIV_Q; - for (i = 0; i < expr->u.op.n_arg; ++i) - macros = ast_expr_required_macros(expr->u.op.args[i], macros); + isl_ast_expr_list_foreach(expr->u.op.args, + &entry_required_macros, ¯os); return macros; } |