Software: Apache. PHP/5.4.45 

uname -a: Linux webm056.cluster010.gra.hosting.ovh.net 5.15.167-ovh-vps-grsec-zfs-classid #1 SMP Tue
Sep 17 08:14:20 UTC 2024 x86_64
 

uid=243112(mycochar) gid=100(users) groups=100(users)  

Safe-mode: OFF (not secure)

/home/mycochar/www/image/photo/gcc-12.3.0/isl-0.24/   drwxr-xr-x
Free 0 B of 0 B (0%)
Your ip: 216.73.216.77 - Server ip: 213.186.33.19
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    

[Enumerate]    [Encoder]    [Tools]    [Proc.]    [FTP Brute]    [Sec.]    [SQL]    [PHP-Code]    [Backdoor Host]    [Back-Connection]    [milw0rm it!]    [PHP-Proxy]    [Self remove]
    


Viewing file:     isl_schedule_tree.c (78.08 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 * Copyright 2013-2014 Ecole Normale Superieure
 * Copyright 2014      INRIA Rocquencourt
 * Copyright 2016      INRIA Paris
 *
 * 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 Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
 * B.P. 105 - 78153 Le Chesnay, France
 * and Centre de Recherche Inria de Paris, 2 rue Simone Iff - Voie DQ12,
 * CS 42112, 75589 Paris Cedex 12, France
 */

#include <isl/id.h>
#include <isl/val.h>
#include <isl/space.h>
#include <isl/map.h>
#include <isl_schedule_band.h>
#include <isl_schedule_private.h>

#undef EL
#define EL isl_schedule_tree

#include <isl_list_templ.h>

#undef EL_BASE
#define EL_BASE schedule_tree

#include <isl_list_templ.c>

/* Is "tree" the leaf of a schedule tree?
 */
int isl_schedule_tree_is_leaf(__isl_keep isl_schedule_tree *tree)
{
    return isl_schedule_tree_get_type(tree) == isl_schedule_node_leaf;
}

/* Create a new schedule tree of type "type".
 * The caller is responsible for filling in the type specific fields and
 * the children.
 *
 * By default, the single node tree does not have any anchored nodes.
 * The caller is responsible for updating the anchored field if needed.
 */
static __isl_give isl_schedule_tree *isl_schedule_tree_alloc(isl_ctx *ctx,
    enum isl_schedule_node_type type)
{
    isl_schedule_tree *tree;

    if (type == isl_schedule_node_error)
        return NULL;

    tree = isl_calloc_type(ctx, isl_schedule_tree);
    if (!tree)
        return NULL;

    tree->ref = 1;
    tree->ctx = ctx;
    isl_ctx_ref(ctx);
    tree->type = type;
    tree->anchored = 0;

    return tree;
}

/* Return a fresh copy of "tree".
 */
__isl_take isl_schedule_tree *isl_schedule_tree_dup(
    __isl_keep isl_schedule_tree *tree)
{
    isl_ctx *ctx;
    isl_schedule_tree *dup;

    if (!tree)
        return NULL;

    ctx = isl_schedule_tree_get_ctx(tree);
    dup = isl_schedule_tree_alloc(ctx, tree->type);
    if (!dup)
        return NULL;

    switch (tree->type) {
    case isl_schedule_node_error:
        isl_die(ctx, isl_error_internal,
            "allocation should have failed",
            return isl_schedule_tree_free(dup));
    case isl_schedule_node_band:
        dup->band = isl_schedule_band_copy(tree->band);
        if (!dup->band)
            return isl_schedule_tree_free(dup);
        break;
    case isl_schedule_node_context:
        dup->context = isl_set_copy(tree->context);
        if (!dup->context)
            return isl_schedule_tree_free(dup);
        break;
    case isl_schedule_node_domain:
        dup->domain = isl_union_set_copy(tree->domain);
        if (!dup->domain)
            return isl_schedule_tree_free(dup);
        break;
    case isl_schedule_node_expansion:
        dup->contraction =
            isl_union_pw_multi_aff_copy(tree->contraction);
        dup->expansion = isl_union_map_copy(tree->expansion);
        if (!dup->contraction || !dup->expansion)
            return isl_schedule_tree_free(dup);
        break;
    case isl_schedule_node_extension:
        dup->extension = isl_union_map_copy(tree->extension);
        if (!dup->extension)
            return isl_schedule_tree_free(dup);
        break;
    case isl_schedule_node_filter:
        dup->filter = isl_union_set_copy(tree->filter);
        if (!dup->filter)
            return isl_schedule_tree_free(dup);
        break;
    case isl_schedule_node_guard:
        dup->guard = isl_set_copy(tree->guard);
        if (!dup->guard)
            return isl_schedule_tree_free(dup);
        break;
    case isl_schedule_node_mark:
        dup->mark = isl_id_copy(tree->mark);
        if (!dup->mark)
            return isl_schedule_tree_free(dup);
        break;
    case isl_schedule_node_leaf:
    case isl_schedule_node_sequence:
    case isl_schedule_node_set:
        break;
    }

    if (tree->children) {
        dup->children = isl_schedule_tree_list_copy(tree->children);
        if (!dup->children)
            return isl_schedule_tree_free(dup);
    }
    dup->anchored = tree->anchored;

    return dup;
}

/* Return an isl_schedule_tree that is equal to "tree" and that has only
 * a single reference.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_cow(
    __isl_take isl_schedule_tree *tree)
{
    if (!tree)
        return NULL;

    if (tree->ref == 1)
        return tree;
    tree->ref--;
    return isl_schedule_tree_dup(tree);
}

/* Return a new reference to "tree".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_copy(
    __isl_keep isl_schedule_tree *tree)
{
    if (!tree)
        return NULL;

    tree->ref++;
    return tree;
}

/* Free "tree" and return NULL.
 */
__isl_null isl_schedule_tree *isl_schedule_tree_free(
    __isl_take isl_schedule_tree *tree)
{
    if (!tree)
        return NULL;
    if (--tree->ref > 0)
        return NULL;

    switch (tree->type) {
    case isl_schedule_node_band:
        isl_schedule_band_free(tree->band);
        break;
    case isl_schedule_node_context:
        isl_set_free(tree->context);
        break;
    case isl_schedule_node_domain:
        isl_union_set_free(tree->domain);
        break;
    case isl_schedule_node_expansion:
        isl_union_pw_multi_aff_free(tree->contraction);
        isl_union_map_free(tree->expansion);
        break;
    case isl_schedule_node_extension:
        isl_union_map_free(tree->extension);
        break;
    case isl_schedule_node_filter:
        isl_union_set_free(tree->filter);
        break;
    case isl_schedule_node_guard:
        isl_set_free(tree->guard);
        break;
    case isl_schedule_node_mark:
        isl_id_free(tree->mark);
        break;
    case isl_schedule_node_sequence:
    case isl_schedule_node_set:
    case isl_schedule_node_error:
    case isl_schedule_node_leaf:
        break;
    }
    isl_schedule_tree_list_free(tree->children);
    isl_ctx_deref(tree->ctx);
    free(tree);

    return NULL;
}

/* Create and return a new leaf schedule tree.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_leaf(isl_ctx *ctx)
{
    return isl_schedule_tree_alloc(ctx, isl_schedule_node_leaf);
}

/* Create a new band schedule tree referring to "band"
 * with no children.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_from_band(
    __isl_take isl_schedule_band *band)
{
    isl_ctx *ctx;
    isl_schedule_tree *tree;

    if (!band)
        return NULL;

    ctx = isl_schedule_band_get_ctx(band);
    tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_band);
    if (!tree)
        goto error;

    tree->band = band;
    tree->anchored = isl_schedule_band_is_anchored(band);

    return tree;
error:
    isl_schedule_band_free(band);
    return NULL;
}

/* Create a new context schedule tree with the given context and no children.
 * Since the context references the outer schedule dimension,
 * the tree is anchored.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_from_context(
    __isl_take isl_set *context)
{
    isl_ctx *ctx;
    isl_schedule_tree *tree;

    if (!context)
        return NULL;

    ctx = isl_set_get_ctx(context);
    tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_context);
    if (!tree)
        goto error;

    tree->context = context;
    tree->anchored = 1;

    return tree;
error:
    isl_set_free(context);
    return NULL;
}

/* Create a new domain schedule tree with the given domain and no children.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_from_domain(
    __isl_take isl_union_set *domain)
{
    isl_ctx *ctx;
    isl_schedule_tree *tree;

    if (!domain)
        return NULL;

    ctx = isl_union_set_get_ctx(domain);
    tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_domain);
    if (!tree)
        goto error;

    tree->domain = domain;

    return tree;
error:
    isl_union_set_free(domain);
    return NULL;
}

/* Create a new expansion schedule tree with the given contraction and
 * expansion and no children.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_from_expansion(
    __isl_take isl_union_pw_multi_aff *contraction,
    __isl_take isl_union_map *expansion)
{
    isl_ctx *ctx;
    isl_schedule_tree *tree;

    if (!contraction || !expansion)
        goto error;

    ctx = isl_union_map_get_ctx(expansion);
    tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_expansion);
    if (!tree)
        goto error;

    tree->contraction = contraction;
    tree->expansion = expansion;

    return tree;
error:
    isl_union_pw_multi_aff_free(contraction);
    isl_union_map_free(expansion);
    return NULL;
}

/* Create a new extension schedule tree with the given extension and
 * no children.
 * Since the domain of the extension refers to the outer schedule dimension,
 * the tree is anchored.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_from_extension(
    __isl_take isl_union_map *extension)
{
    isl_ctx *ctx;
    isl_schedule_tree *tree;

    if (!extension)
        return NULL;

    ctx = isl_union_map_get_ctx(extension);
    tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_extension);
    if (!tree)
        goto error;

    tree->extension = extension;
    tree->anchored = 1;

    return tree;
error:
    isl_union_map_free(extension);
    return NULL;
}

/* Create a new filter schedule tree with the given filter and no children.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_from_filter(
    __isl_take isl_union_set *filter)
{
    isl_ctx *ctx;
    isl_schedule_tree *tree;

    if (!filter)
        return NULL;

    ctx = isl_union_set_get_ctx(filter);
    tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_filter);
    if (!tree)
        goto error;

    tree->filter = filter;

    return tree;
error:
    isl_union_set_free(filter);
    return NULL;
}

/* Create a new guard schedule tree with the given guard and no children.
 * Since the guard references the outer schedule dimension,
 * the tree is anchored.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_from_guard(
    __isl_take isl_set *guard)
{
    isl_ctx *ctx;
    isl_schedule_tree *tree;

    if (!guard)
        return NULL;

    ctx = isl_set_get_ctx(guard);
    tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_guard);
    if (!tree)
        goto error;

    tree->guard = guard;
    tree->anchored = 1;

    return tree;
error:
    isl_set_free(guard);
    return NULL;
}

/* Create a new mark schedule tree with the given mark identifier and
 * no children.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_from_mark(
    __isl_take isl_id *mark)
{
    isl_ctx *ctx;
    isl_schedule_tree *tree;

    if (!mark)
        return NULL;

    ctx = isl_id_get_ctx(mark);
    tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_mark);
    if (!tree)
        goto error;

    tree->mark = mark;

    return tree;
error:
    isl_id_free(mark);
    return NULL;
}

/* Does "tree" have any node that depends on its position
 * in the complete schedule tree?
 */
isl_bool isl_schedule_tree_is_subtree_anchored(
    __isl_keep isl_schedule_tree *tree)
{
    return tree ? isl_bool_ok(tree->anchored) : isl_bool_error;
}

/* Does the root node of "tree" depend on its position in the complete
 * schedule tree?
 * Band nodes may be anchored depending on the associated AST build options.
 * Context, extension and guard nodes are always anchored.
 */
int isl_schedule_tree_is_anchored(__isl_keep isl_schedule_tree *tree)
{
    if (!tree)
        return -1;

    switch (isl_schedule_tree_get_type(tree)) {
    case isl_schedule_node_error:
        return -1;
    case isl_schedule_node_band:
        return isl_schedule_band_is_anchored(tree->band);
    case isl_schedule_node_context:
    case isl_schedule_node_extension:
    case isl_schedule_node_guard:
        return 1;
    case isl_schedule_node_domain:
    case isl_schedule_node_expansion:
    case isl_schedule_node_filter:
    case isl_schedule_node_leaf:
    case isl_schedule_node_mark:
    case isl_schedule_node_sequence:
    case isl_schedule_node_set:
        return 0;
    }

    isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
        "unhandled case", return -1);
}

/* Update the anchored field of "tree" based on whether the root node
 * itself in anchored and the anchored fields of the children.
 *
 * This function should be called whenever the children of a tree node
 * are changed or the anchoredness of the tree root itself changes.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_update_anchored(
    __isl_take isl_schedule_tree *tree)
{
    int i;
    isl_size n;
    int anchored;

    anchored = isl_schedule_tree_is_anchored(tree);
    n = isl_schedule_tree_n_children(tree);
    if (anchored < 0 || n < 0)
        return isl_schedule_tree_free(tree);

    for (i = 0; !anchored && i < n; ++i) {
        isl_schedule_tree *child;

        child = isl_schedule_tree_get_child(tree, i);
        if (!child)
            return isl_schedule_tree_free(tree);
        anchored = child->anchored;
        isl_schedule_tree_free(child);
    }

    if (anchored == tree->anchored)
        return tree;
    tree = isl_schedule_tree_cow(tree);
    if (!tree)
        return NULL;
    tree->anchored = anchored;
    return tree;
}

/* Create a new tree of the given type (isl_schedule_node_sequence or
 * isl_schedule_node_set) with the given children.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_from_children(
    enum isl_schedule_node_type type,
    __isl_take isl_schedule_tree_list *list)
{
    isl_ctx *ctx;
    isl_schedule_tree *tree;

    if (!list)
        return NULL;

    ctx = isl_schedule_tree_list_get_ctx(list);
    tree = isl_schedule_tree_alloc(ctx, type);
    if (!tree)
        goto error;

    tree->children = list;
    tree = isl_schedule_tree_update_anchored(tree);

    return tree;
error:
    isl_schedule_tree_list_free(list);
    return NULL;
}

/* Construct a tree with a root node of type "type" and as children
 * "tree1" and "tree2".
 * If the root of one (or both) of the input trees is itself of type "type",
 * then the tree is replaced by its children.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_from_pair(
    enum isl_schedule_node_type type, __isl_take isl_schedule_tree *tree1,
    __isl_take isl_schedule_tree *tree2)
{
    isl_ctx *ctx;
    isl_schedule_tree_list *list;

    if (!tree1 || !tree2)
        goto error;

    ctx = isl_schedule_tree_get_ctx(tree1);
    if (isl_schedule_tree_get_type(tree1) == type) {
        list = isl_schedule_tree_list_copy(tree1->children);
        isl_schedule_tree_free(tree1);
    } else {
        list = isl_schedule_tree_list_alloc(ctx, 2);
        list = isl_schedule_tree_list_add(list, tree1);
    }
    if (isl_schedule_tree_get_type(tree2) == type) {
        isl_schedule_tree_list *children;

        children = isl_schedule_tree_list_copy(tree2->children);
        list = isl_schedule_tree_list_concat(list, children);
        isl_schedule_tree_free(tree2);
    } else {
        list = isl_schedule_tree_list_add(list, tree2);
    }

    return isl_schedule_tree_from_children(type, list);
error:
    isl_schedule_tree_free(tree1);
    isl_schedule_tree_free(tree2);
    return NULL;
}

/* Construct a tree with a sequence root node and as children
 * "tree1" and "tree2".
 * If the root of one (or both) of the input trees is itself a sequence,
 * then the tree is replaced by its children.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_sequence_pair(
    __isl_take isl_schedule_tree *tree1,
    __isl_take isl_schedule_tree *tree2)
{
    return isl_schedule_tree_from_pair(isl_schedule_node_sequence,
                        tree1, tree2);
}

/* Construct a tree with a set root node and as children
 * "tree1" and "tree2".
 * If the root of one (or both) of the input trees is itself a set,
 * then the tree is replaced by its children.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_set_pair(
    __isl_take isl_schedule_tree *tree1,
    __isl_take isl_schedule_tree *tree2)
{
    return isl_schedule_tree_from_pair(isl_schedule_node_set, tree1, tree2);
}

/* Return the isl_ctx to which "tree" belongs.
 */
isl_ctx *isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree *tree)
{
    return tree ? tree->ctx : NULL;
}

/* Return the type of the root of the tree or isl_schedule_node_error
 * on error.
 */
enum isl_schedule_node_type isl_schedule_tree_get_type(
    __isl_keep isl_schedule_tree *tree)
{
    return tree ? tree->type : isl_schedule_node_error;
}

/* Are "tree1" and "tree2" obviously equal to each other?
 */
isl_bool isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree *tree1,
    __isl_keep isl_schedule_tree *tree2)
{
    isl_bool equal;
    int i;
    isl_size n1, n2;

    if (!tree1 || !tree2)
        return isl_bool_error;
    if (tree1 == tree2)
        return isl_bool_true;
    if (tree1->type != tree2->type)
        return isl_bool_false;

    switch (tree1->type) {
    case isl_schedule_node_band:
        equal = isl_schedule_band_plain_is_equal(tree1->band,
                            tree2->band);
        break;
    case isl_schedule_node_context:
        equal = isl_set_is_equal(tree1->context, tree2->context);
        break;
    case isl_schedule_node_domain:
        equal = isl_union_set_is_equal(tree1->domain, tree2->domain);
        break;
    case isl_schedule_node_expansion:
        equal = isl_union_map_is_equal(tree1->expansion,
                        tree2->expansion);
        if (equal >= 0 && equal)
            equal = isl_union_pw_multi_aff_plain_is_equal(
                    tree1->contraction, tree2->contraction);
        break;
    case isl_schedule_node_extension:
        equal = isl_union_map_is_equal(tree1->extension,
                        tree2->extension);
        break;
    case isl_schedule_node_filter:
        equal = isl_union_set_is_equal(tree1->filter, tree2->filter);
        break;
    case isl_schedule_node_guard:
        equal = isl_set_is_equal(tree1->guard, tree2->guard);
        break;
    case isl_schedule_node_mark:
        equal = isl_bool_ok(tree1->mark == tree2->mark);
        break;
    case isl_schedule_node_leaf:
    case isl_schedule_node_sequence:
    case isl_schedule_node_set:
        equal = isl_bool_true;
        break;
    case isl_schedule_node_error:
        equal = isl_bool_error;
        break;
    }

    if (equal < 0 || !equal)
        return equal;

    n1 = isl_schedule_tree_n_children(tree1);
    n2 = isl_schedule_tree_n_children(tree2);
    if (n1 < 0 || n2 < 0)
        return isl_bool_error;
    if (n1 != n2)
        return isl_bool_false;
    for (i = 0; i < n1; ++i) {
        isl_schedule_tree *child1, *child2;

        child1 = isl_schedule_tree_get_child(tree1, i);
        child2 = isl_schedule_tree_get_child(tree2, i);
        equal = isl_schedule_tree_plain_is_equal(child1, child2);
        isl_schedule_tree_free(child1);
        isl_schedule_tree_free(child2);

        if (equal < 0 || !equal)
            return equal;
    }

    return isl_bool_true;
}

/* Does "tree" have any children, other than an implicit leaf.
 */
int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree *tree)
{
    if (!tree)
        return -1;

    return tree->children != NULL;
}

/* Return the number of children of "tree", excluding implicit leaves.
 * The "children" field is NULL if there are
 * no children (except for the implicit leaves).
 */
isl_size isl_schedule_tree_n_children(__isl_keep isl_schedule_tree *tree)
{
    if (!tree)
        return isl_size_error;

    if (!tree->children)
        return 0;
    return isl_schedule_tree_list_n_schedule_tree(tree->children);
}

/* Return a copy of the (explicit) child at position "pos" of "tree".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_get_child(
    __isl_keep isl_schedule_tree *tree, int pos)
{
    if (!tree)
        return NULL;
    if (!tree->children)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
            "schedule tree has no explicit children", return NULL);
    return isl_schedule_tree_list_get_schedule_tree(tree->children, pos);
}

/* Return a copy of the (explicit) child at position "pos" of "tree" and
 * free "tree".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_child(
    __isl_take isl_schedule_tree *tree, int pos)
{
    isl_schedule_tree *child;

    child = isl_schedule_tree_get_child(tree, pos);
    isl_schedule_tree_free(tree);
    return child;
}

/* Remove all (explicit) children from "tree".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_reset_children(
    __isl_take isl_schedule_tree *tree)
{
    tree = isl_schedule_tree_cow(tree);
    if (!tree)
        return NULL;
    tree->children = isl_schedule_tree_list_free(tree->children);
    return tree;
}

/* Remove the child at position "pos" from the children of "tree".
 * If there was only one child to begin with, then remove all children.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_drop_child(
    __isl_take isl_schedule_tree *tree, int pos)
{
    isl_size n;

    tree = isl_schedule_tree_cow(tree);

    n = isl_schedule_tree_n_children(tree);
    if (n < 0)
        return isl_schedule_tree_free(tree);
    if (n == 0)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "tree does not have any explicit children",
            return isl_schedule_tree_free(tree));
    if (pos < 0 || pos >= n)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "position out of bounds",
            return isl_schedule_tree_free(tree));
    if (n == 1)
        return isl_schedule_tree_reset_children(tree);

    tree->children = isl_schedule_tree_list_drop(tree->children, pos, 1);
    if (!tree->children)
        return isl_schedule_tree_free(tree);

    return tree;
}

/* Replace the child at position "pos" of "tree" by "child".
 *
 * If the new child is a leaf, then it is not explicitly
 * recorded in the list of children.  Instead, the list of children
 * (which is assumed to have only one element) is removed.
 * Note that the children of set and sequence nodes are always
 * filters, so they cannot be replaced by empty trees.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_replace_child(
    __isl_take isl_schedule_tree *tree, int pos,
    __isl_take isl_schedule_tree *child)
{
    tree = isl_schedule_tree_cow(tree);
    if (!tree || !child)
        goto error;

    if (isl_schedule_tree_is_leaf(child)) {
        isl_size n;

        isl_schedule_tree_free(child);
        if (!tree->children && pos == 0)
            return tree;
        n = isl_schedule_tree_n_children(tree);
        if (n < 0)
            return isl_schedule_tree_free(tree);
        if (n != 1)
            isl_die(isl_schedule_tree_get_ctx(tree),
                isl_error_internal,
                "can only replace single child by leaf",
                goto error);
        return isl_schedule_tree_reset_children(tree);
    }

    if (!tree->children && pos == 0)
        tree->children =
            isl_schedule_tree_list_from_schedule_tree(child);
    else
        tree->children = isl_schedule_tree_list_set_schedule_tree(
                tree->children, pos, child);

    if (!tree->children)
        return isl_schedule_tree_free(tree);
    tree = isl_schedule_tree_update_anchored(tree);

    return tree;
error:
    isl_schedule_tree_free(tree);
    isl_schedule_tree_free(child);
    return NULL;
}

/* Replace the (explicit) children of "tree" by "children"?
 */
__isl_give isl_schedule_tree *isl_schedule_tree_set_children(
    __isl_take isl_schedule_tree *tree,
    __isl_take isl_schedule_tree_list *children)
{
    tree = isl_schedule_tree_cow(tree);
    if (!tree || !children)
        goto error;
    isl_schedule_tree_list_free(tree->children);
    tree->children = children;
    return tree;
error:
    isl_schedule_tree_free(tree);
    isl_schedule_tree_list_free(children);
    return NULL;
}

/* Create a new band schedule tree referring to "band"
 * with "tree" as single child.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_insert_band(
    __isl_take isl_schedule_tree *tree, __isl_take isl_schedule_band *band)
{
    isl_schedule_tree *res;

    res = isl_schedule_tree_from_band(band);
    return isl_schedule_tree_replace_child(res, 0, tree);
}

/* Create a new context schedule tree with the given context and
 * with "tree" as single child.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_insert_context(
    __isl_take isl_schedule_tree *tree, __isl_take isl_set *context)
{
    isl_schedule_tree *res;

    res = isl_schedule_tree_from_context(context);
    return isl_schedule_tree_replace_child(res, 0, tree);
}

/* Create a new domain schedule tree with the given domain and
 * with "tree" as single child.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_insert_domain(
    __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
{
    isl_schedule_tree *res;

    res = isl_schedule_tree_from_domain(domain);
    return isl_schedule_tree_replace_child(res, 0, tree);
}

/* Create a new expansion schedule tree with the given contraction and
 * expansion and with "tree" as single child.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_insert_expansion(
    __isl_take isl_schedule_tree *tree,
    __isl_take isl_union_pw_multi_aff *contraction,
    __isl_take isl_union_map *expansion)
{
    isl_schedule_tree *res;

    res = isl_schedule_tree_from_expansion(contraction, expansion);
    return isl_schedule_tree_replace_child(res, 0, tree);
}

/* Create a new extension schedule tree with the given extension and
 * with "tree" as single child.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_insert_extension(
    __isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension)
{
    isl_schedule_tree *res;

    res = isl_schedule_tree_from_extension(extension);
    return isl_schedule_tree_replace_child(res, 0, tree);
}

/* Create a new filter schedule tree with the given filter and single child.
 *
 * If the root of "tree" is itself a filter node, then the two
 * filter nodes are merged into one node.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_insert_filter(
    __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
{
    isl_schedule_tree *res;

    if (isl_schedule_tree_get_type(tree) == isl_schedule_node_filter) {
        isl_union_set *tree_filter;

        tree_filter = isl_schedule_tree_filter_get_filter(tree);
        tree_filter = isl_union_set_intersect(tree_filter, filter);
        tree = isl_schedule_tree_filter_set_filter(tree, tree_filter);
        return tree;
    }

    res = isl_schedule_tree_from_filter(filter);
    return isl_schedule_tree_replace_child(res, 0, tree);
}

/* Insert a filter node with filter set "filter"
 * in each of the children of "tree".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_children_insert_filter(
    __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
{
    int i;
    isl_size n;

    n = isl_schedule_tree_n_children(tree);
    if (n < 0 || !filter)
        goto error;

    for (i = 0; i < n; ++i) {
        isl_schedule_tree *child;

        child = isl_schedule_tree_get_child(tree, i);
        child = isl_schedule_tree_insert_filter(child,
                            isl_union_set_copy(filter));
        tree = isl_schedule_tree_replace_child(tree, i, child);
    }

    isl_union_set_free(filter);
    return tree;
error:
    isl_union_set_free(filter);
    isl_schedule_tree_free(tree);
    return NULL;
}

/* Create a new guard schedule tree with the given guard and
 * with "tree" as single child.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_insert_guard(
    __isl_take isl_schedule_tree *tree, __isl_take isl_set *guard)
{
    isl_schedule_tree *res;

    res = isl_schedule_tree_from_guard(guard);
    return isl_schedule_tree_replace_child(res, 0, tree);
}

/* Create a new mark schedule tree with the given mark identifier and
 * single child.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_insert_mark(
    __isl_take isl_schedule_tree *tree, __isl_take isl_id *mark)
{
    isl_schedule_tree *res;

    res = isl_schedule_tree_from_mark(mark);
    return isl_schedule_tree_replace_child(res, 0, tree);
}

/* Return the number of members in the band tree root.
 */
isl_size isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree *tree)
{
    if (!tree)
        return isl_size_error;

    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", return isl_size_error);

    return isl_schedule_band_n_member(tree->band);
}

/* Is the band member at position "pos" of the band tree root
 * marked coincident?
 */
isl_bool isl_schedule_tree_band_member_get_coincident(
    __isl_keep isl_schedule_tree *tree, int pos)
{
    if (!tree)
        return isl_bool_error;

    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", return isl_bool_error);

    return isl_schedule_band_member_get_coincident(tree->band, pos);
}

/* Mark the given band member as being coincident or not
 * according to "coincident".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_coincident(
    __isl_take isl_schedule_tree *tree, int pos, int coincident)
{
    if (!tree)
        return NULL;
    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", return isl_schedule_tree_free(tree));
    if (isl_schedule_tree_band_member_get_coincident(tree, pos) ==
                                    coincident)
        return tree;
    tree = isl_schedule_tree_cow(tree);
    if (!tree)
        return NULL;

    tree->band = isl_schedule_band_member_set_coincident(tree->band, pos,
                            coincident);
    if (!tree->band)
        return isl_schedule_tree_free(tree);
    return tree;
}

/* Is the band tree root marked permutable?
 */
isl_bool isl_schedule_tree_band_get_permutable(
    __isl_keep isl_schedule_tree *tree)
{
    if (!tree)
        return isl_bool_error;

    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", return isl_bool_error);

    return isl_schedule_band_get_permutable(tree->band);
}

/* Mark the band tree root permutable or not according to "permutable"?
 */
__isl_give isl_schedule_tree *isl_schedule_tree_band_set_permutable(
    __isl_take isl_schedule_tree *tree, int permutable)
{
    if (!tree)
        return NULL;
    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", return isl_schedule_tree_free(tree));
    if (isl_schedule_tree_band_get_permutable(tree) == permutable)
        return tree;
    tree = isl_schedule_tree_cow(tree);
    if (!tree)
        return NULL;

    tree->band = isl_schedule_band_set_permutable(tree->band, permutable);
    if (!tree->band)
        return isl_schedule_tree_free(tree);
    return tree;
}

/* Return the schedule space of the band tree root.
 */
__isl_give isl_space *isl_schedule_tree_band_get_space(
    __isl_keep isl_schedule_tree *tree)
{
    if (!tree)
        return NULL;

    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", return NULL);

    return isl_schedule_band_get_space(tree->band);
}

/* Intersect the domain of the band schedule of the band tree root
 * with "domain".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_band_intersect_domain(
    __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
{
    if (!tree || !domain)
        goto error;

    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", goto error);

    tree->band = isl_schedule_band_intersect_domain(tree->band, domain);
    if (!tree->band)
        return isl_schedule_tree_free(tree);

    return tree;
error:
    isl_schedule_tree_free(tree);
    isl_union_set_free(domain);
    return NULL;
}

/* Return the schedule of the band tree root in isolation.
 */
__isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule(
    __isl_keep isl_schedule_tree *tree)
{
    if (!tree)
        return NULL;

    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", return NULL);

    return isl_schedule_band_get_partial_schedule(tree->band);
}

/* Replace the schedule of the band tree root by "schedule".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_band_set_partial_schedule(
    __isl_take isl_schedule_tree *tree,
    __isl_take isl_multi_union_pw_aff *schedule)
{
    tree = isl_schedule_tree_cow(tree);
    if (!tree || !schedule)
        goto error;

    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", return NULL);
    tree->band = isl_schedule_band_set_partial_schedule(tree->band,
                                schedule);

    return tree;
error:
    isl_schedule_tree_free(tree);
    isl_multi_union_pw_aff_free(schedule);
    return NULL;
}

/* Return the loop AST generation type for the band member
 * of the band tree root at position "pos".
 */
enum isl_ast_loop_type isl_schedule_tree_band_member_get_ast_loop_type(
    __isl_keep isl_schedule_tree *tree, int pos)
{
    if (!tree)
        return isl_ast_loop_error;

    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", return isl_ast_loop_error);

    return isl_schedule_band_member_get_ast_loop_type(tree->band, pos);
}

/* Set the loop AST generation type for the band member of the band tree root
 * at position "pos" to "type".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_ast_loop_type(
    __isl_take isl_schedule_tree *tree, int pos,
    enum isl_ast_loop_type type)
{
    tree = isl_schedule_tree_cow(tree);
    if (!tree)
        return NULL;

    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", return isl_schedule_tree_free(tree));

    tree->band = isl_schedule_band_member_set_ast_loop_type(tree->band,
                                pos, type);
    if (!tree->band)
        return isl_schedule_tree_free(tree);

    return tree;
}

/* Return the loop AST generation type for the band member
 * of the band tree root at position "pos" for the isolated part.
 */
enum isl_ast_loop_type isl_schedule_tree_band_member_get_isolate_ast_loop_type(
    __isl_keep isl_schedule_tree *tree, int pos)
{
    if (!tree)
        return isl_ast_loop_error;

    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", return isl_ast_loop_error);

    return isl_schedule_band_member_get_isolate_ast_loop_type(tree->band,
                                    pos);
}

/* Set the loop AST generation type for the band member of the band tree root
 * at position "pos" for the isolated part to "type".
 */
__isl_give isl_schedule_tree *
isl_schedule_tree_band_member_set_isolate_ast_loop_type(
    __isl_take isl_schedule_tree *tree, int pos,
    enum isl_ast_loop_type type)
{
    tree = isl_schedule_tree_cow(tree);
    if (!tree)
        return NULL;

    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", return isl_schedule_tree_free(tree));

    tree->band = isl_schedule_band_member_set_isolate_ast_loop_type(
                            tree->band, pos, type);
    if (!tree->band)
        return isl_schedule_tree_free(tree);

    return tree;
}

/* Return the AST build options associated to the band tree root.
 */
__isl_give isl_union_set *isl_schedule_tree_band_get_ast_build_options(
    __isl_keep isl_schedule_tree *tree)
{
    if (!tree)
        return NULL;

    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", return NULL);

    return isl_schedule_band_get_ast_build_options(tree->band);
}

/* Replace the AST build options associated to band tree root by "options".
 * Updated the anchored field if the anchoredness of the root node itself
 * changes.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_band_set_ast_build_options(
    __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *options)
{
    int was_anchored;

    tree = isl_schedule_tree_cow(tree);
    if (!tree || !options)
        goto error;

    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", goto error);

    was_anchored = isl_schedule_tree_is_anchored(tree);
    tree->band = isl_schedule_band_set_ast_build_options(tree->band,
                                options);
    if (!tree->band)
        return isl_schedule_tree_free(tree);
    if (isl_schedule_tree_is_anchored(tree) != was_anchored)
        tree = isl_schedule_tree_update_anchored(tree);

    return tree;
error:
    isl_schedule_tree_free(tree);
    isl_union_set_free(options);
    return NULL;
}

/* Return the "isolate" option associated to the band tree root of "tree",
 * which is assumed to appear at schedule depth "depth".
 */
__isl_give isl_set *isl_schedule_tree_band_get_ast_isolate_option(
    __isl_keep isl_schedule_tree *tree, int depth)
{
    if (!tree)
        return NULL;

    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", return NULL);

    return isl_schedule_band_get_ast_isolate_option(tree->band, depth);
}

/* Return the context of the context tree root.
 */
__isl_give isl_set *isl_schedule_tree_context_get_context(
    __isl_keep isl_schedule_tree *tree)
{
    if (!tree)
        return NULL;

    if (tree->type != isl_schedule_node_context)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a context node", return NULL);

    return isl_set_copy(tree->context);
}

/* Return the domain of the domain tree root.
 */
__isl_give isl_union_set *isl_schedule_tree_domain_get_domain(
    __isl_keep isl_schedule_tree *tree)
{
    if (!tree)
        return NULL;

    if (tree->type != isl_schedule_node_domain)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a domain node", return NULL);

    return isl_union_set_copy(tree->domain);
}

/* Replace the domain of domain tree root "tree" by "domain".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_domain_set_domain(
    __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain)
{
    tree = isl_schedule_tree_cow(tree);
    if (!tree || !domain)
        goto error;

    if (tree->type != isl_schedule_node_domain)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a domain node", goto error);

    isl_union_set_free(tree->domain);
    tree->domain = domain;

    return tree;
error:
    isl_schedule_tree_free(tree);
    isl_union_set_free(domain);
    return NULL;
}

/* Return the contraction of the expansion tree root.
 */
__isl_give isl_union_pw_multi_aff *isl_schedule_tree_expansion_get_contraction(
    __isl_keep isl_schedule_tree *tree)
{
    if (!tree)
        return NULL;

    if (tree->type != isl_schedule_node_expansion)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not an expansion node", return NULL);

    return isl_union_pw_multi_aff_copy(tree->contraction);
}

/* Return the expansion of the expansion tree root.
 */
__isl_give isl_union_map *isl_schedule_tree_expansion_get_expansion(
    __isl_keep isl_schedule_tree *tree)
{
    if (!tree)
        return NULL;

    if (tree->type != isl_schedule_node_expansion)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not an expansion node", return NULL);

    return isl_union_map_copy(tree->expansion);
}

/* Replace the contraction and the expansion of the expansion tree root "tree"
 * by "contraction" and "expansion".
 */
__isl_give isl_schedule_tree *
isl_schedule_tree_expansion_set_contraction_and_expansion(
    __isl_take isl_schedule_tree *tree,
    __isl_take isl_union_pw_multi_aff *contraction,
    __isl_take isl_union_map *expansion)
{
    tree = isl_schedule_tree_cow(tree);
    if (!tree || !contraction || !expansion)
        goto error;

    if (tree->type != isl_schedule_node_expansion)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not an expansion node", return NULL);

    isl_union_pw_multi_aff_free(tree->contraction);
    tree->contraction = contraction;
    isl_union_map_free(tree->expansion);
    tree->expansion = expansion;

    return tree;
error:
    isl_schedule_tree_free(tree);
    isl_union_pw_multi_aff_free(contraction);
    isl_union_map_free(expansion);
    return NULL;
}

/* Return the extension of the extension tree root.
 */
__isl_give isl_union_map *isl_schedule_tree_extension_get_extension(
    __isl_take isl_schedule_tree *tree)
{
    if (!tree)
        return NULL;

    if (tree->type != isl_schedule_node_extension)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not an extension node", return NULL);

    return isl_union_map_copy(tree->extension);
}

/* Replace the extension of extension tree root "tree" by "extension".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_extension_set_extension(
    __isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension)
{
    tree = isl_schedule_tree_cow(tree);
    if (!tree || !extension)
        goto error;

    if (tree->type != isl_schedule_node_extension)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not an extension node", return NULL);
    isl_union_map_free(tree->extension);
    tree->extension = extension;

    return tree;
error:
    isl_schedule_tree_free(tree);
    isl_union_map_free(extension);
    return NULL;
}

/* Return the filter of the filter tree root.
 */
__isl_give isl_union_set *isl_schedule_tree_filter_get_filter(
    __isl_keep isl_schedule_tree *tree)
{
    if (!tree)
        return NULL;

    if (tree->type != isl_schedule_node_filter)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a filter node", return NULL);

    return isl_union_set_copy(tree->filter);
}

/* Replace the filter of the filter tree root by "filter".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_filter_set_filter(
    __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter)
{
    tree = isl_schedule_tree_cow(tree);
    if (!tree || !filter)
        goto error;

    if (tree->type != isl_schedule_node_filter)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a filter node", return NULL);

    isl_union_set_free(tree->filter);
    tree->filter = filter;

    return tree;
error:
    isl_schedule_tree_free(tree);
    isl_union_set_free(filter);
    return NULL;
}

/* Return the guard of the guard tree root.
 */
__isl_give isl_set *isl_schedule_tree_guard_get_guard(
    __isl_take isl_schedule_tree *tree)
{
    if (!tree)
        return NULL;

    if (tree->type != isl_schedule_node_guard)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a guard node", return NULL);

    return isl_set_copy(tree->guard);
}

/* Return the mark identifier of the mark tree root "tree".
 */
__isl_give isl_id *isl_schedule_tree_mark_get_id(
    __isl_keep isl_schedule_tree *tree)
{
    if (!tree)
        return NULL;

    if (tree->type != isl_schedule_node_mark)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a mark node", return NULL);

    return isl_id_copy(tree->mark);
}

/* Set dim to the range dimension of "map" and abort the search.
 */
static isl_stat set_range_dim(__isl_take isl_map *map, void *user)
{
    isl_size *dim = user;

    *dim = isl_map_dim(map, isl_dim_out);
    isl_map_free(map);

    return isl_stat_error;
}

/* Return the dimension of the range of "umap".
 * "umap" is assumed not to be empty and
 * all maps inside "umap" are assumed to have the same range.
 *
 * We extract the range dimension from the first map in "umap".
 */
static isl_size range_dim(__isl_keep isl_union_map *umap)
{
    isl_size dim = isl_size_error;
    isl_size n;

    n = isl_union_map_n_map(umap);
    if (n < 0)
        return isl_size_error;
    if (n == 0)
        isl_die(isl_union_map_get_ctx(umap), isl_error_internal,
            "unexpected empty input", return isl_size_error);

    isl_union_map_foreach_map(umap, &set_range_dim, &dim);

    return dim;
}

/* Append an "extra" number of zeros to the range of "umap" and
 * return the result.
 */
static __isl_give isl_union_map *append_range(__isl_take isl_union_map *umap,
    int extra)
{
    isl_union_set *dom;
    isl_space *space;
    isl_multi_val *mv;
    isl_union_pw_multi_aff *suffix;
    isl_union_map *universe;
    isl_union_map *suffix_umap;

    universe = isl_union_map_universe(isl_union_map_copy(umap));
    dom = isl_union_map_domain(universe);
    space = isl_union_set_get_space(dom);
    space = isl_space_set_from_params(space);
    space = isl_space_add_dims(space, isl_dim_set, extra);
    mv = isl_multi_val_zero(space);

    suffix = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv);
    suffix_umap = isl_union_map_from_union_pw_multi_aff(suffix);
    umap = isl_union_map_flat_range_product(umap, suffix_umap);

    return umap;
}

/* Should we skip the root of "tree" while looking for the first
 * descendant with schedule information?
 * That is, is it impossible to derive any information about
 * the iteration domain from this node?
 *
 * We do not want to skip leaf or error nodes because there is
 * no point in looking any deeper from these nodes.
 * We can only extract partial iteration domain information
 * from an extension node, but extension nodes are not supported
 * by the caller and it will error out on them.
 */
static isl_bool domain_less(__isl_keep isl_schedule_tree *tree)
{
    enum isl_schedule_node_type type;
    isl_size n;

    type = isl_schedule_tree_get_type(tree);
    switch (type) {
    case isl_schedule_node_band:
        n = isl_schedule_tree_band_n_member(tree);
        return n < 0 ? isl_bool_error : isl_bool_ok(n == 0);
    case isl_schedule_node_context:
    case isl_schedule_node_guard:
    case isl_schedule_node_mark:
        return isl_bool_true;
    case isl_schedule_node_leaf:
    case isl_schedule_node_error:
    case isl_schedule_node_domain:
    case isl_schedule_node_expansion:
    case isl_schedule_node_extension:
    case isl_schedule_node_filter:
    case isl_schedule_node_set:
    case isl_schedule_node_sequence:
        return isl_bool_false;
    }

    isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
        "unhandled case", return isl_bool_error);
}

/* Move down to the first descendant of "tree" that contains any schedule
 * information or return "leaf" if there is no such descendant.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_first_schedule_descendant(
    __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_tree *leaf)
{
    isl_bool down;

    while ((down = domain_less(tree)) == isl_bool_true) {
        if (!isl_schedule_tree_has_children(tree)) {
            isl_schedule_tree_free(tree);
            return isl_schedule_tree_copy(leaf);
        }
        tree = isl_schedule_tree_child(tree, 0);
    }

    if (down < 0)
        return isl_schedule_tree_free(tree);

    return tree;
}

static __isl_give isl_union_map *subtree_schedule_extend(
    __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer);

/* Extend the schedule map "outer" with the subtree schedule
 * of the (single) child of "tree", if any.
 *
 * If "tree" does not have any descendants (apart from those that
 * do not carry any schedule information), then we simply return "outer".
 * Otherwise, we extend the schedule map "outer" with the subtree schedule
 * of the single child.
 */
static __isl_give isl_union_map *subtree_schedule_extend_child(
    __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
{
    isl_schedule_tree *child;
    isl_union_map *res;

    if (!tree)
        return isl_union_map_free(outer);
    if (!isl_schedule_tree_has_children(tree))
        return outer;
    child = isl_schedule_tree_get_child(tree, 0);
    if (!child)
        return isl_union_map_free(outer);
    res = subtree_schedule_extend(child, outer);
    isl_schedule_tree_free(child);
    return res;
}

/* Extract the parameter space from one of the children of "tree",
 * which are assumed to be filters.
 */
static __isl_give isl_space *extract_space_from_filter_child(
    __isl_keep isl_schedule_tree *tree)
{
    isl_space *space;
    isl_union_set *dom;
    isl_schedule_tree *child;

    child = isl_schedule_tree_list_get_schedule_tree(tree->children, 0);
    dom = isl_schedule_tree_filter_get_filter(child);
    space = isl_union_set_get_space(dom);
    isl_union_set_free(dom);
    isl_schedule_tree_free(child);

    return space;
}

/* Extend the schedule map "outer" with the subtree schedule
 * of a set or sequence node.
 *
 * The schedule for the set or sequence node itself is composed of
 * pieces of the form
 *
 *    filter -> []
 *
 * or
 *
 *    filter -> [index]
 *
 * The first form is used if there is only a single child or
 * if the current node is a set node and the schedule_separate_components
 * option is not set.
 *
 * Each of the pieces above is extended with the subtree schedule of
 * the child of the corresponding filter, if any, padded with zeros
 * to ensure that all pieces have the same range dimension.
 */
static __isl_give isl_union_map *subtree_schedule_extend_from_children(
    __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
{
    int i;
    isl_size n;
    isl_size dim;
    int separate;
    isl_ctx *ctx;
    isl_val *v = NULL;
    isl_multi_val *mv;
    isl_space *space;
    isl_union_map *umap;

    n = isl_schedule_tree_n_children(tree);
    if (n < 0)
        return isl_union_map_free(outer);
    if (n == 0)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
            "missing children", return isl_union_map_free(outer));

    ctx = isl_schedule_tree_get_ctx(tree);
    separate = n > 1 && (tree->type == isl_schedule_node_sequence ||
                isl_options_get_schedule_separate_components(ctx));

    space = isl_space_params_alloc(ctx, 0);

    umap = isl_union_map_empty(isl_space_copy(space));
    space = isl_space_set_from_params(space);
    if (separate) {
        space = isl_space_add_dims(space, isl_dim_set, 1);
        v = isl_val_zero(ctx);
    }
    mv = isl_multi_val_zero(space);

    dim = isl_multi_val_dim(mv, isl_dim_set);
    if (dim < 0)
        umap = isl_union_map_free(umap);
    for (i = 0; i < n; ++i) {
        isl_multi_val *mv_copy;
        isl_union_pw_multi_aff *upma;
        isl_union_map *umap_i;
        isl_union_set *dom;
        isl_schedule_tree *child;
        isl_size dim_i;
        isl_bool empty;

        child = isl_schedule_tree_list_get_schedule_tree(
                            tree->children, i);
        dom = isl_schedule_tree_filter_get_filter(child);

        if (separate) {
            mv = isl_multi_val_set_val(mv, 0, isl_val_copy(v));
            v = isl_val_add_ui(v, 1);
        }
        mv_copy = isl_multi_val_copy(mv);
        space = isl_union_set_get_space(dom);
        mv_copy = isl_multi_val_align_params(mv_copy, space);
        upma = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv_copy);
        umap_i = isl_union_map_from_union_pw_multi_aff(upma);
        umap_i = isl_union_map_flat_range_product(
                        isl_union_map_copy(outer), umap_i);
        umap_i = subtree_schedule_extend_child(child, umap_i);
        isl_schedule_tree_free(child);

        empty = isl_union_map_is_empty(umap_i);
        if (empty < 0)
            umap_i = isl_union_map_free(umap_i);
        else if (empty) {
            isl_union_map_free(umap_i);
            continue;
        }

        dim_i = range_dim(umap_i);
        if (dim_i < 0) {
            umap = isl_union_map_free(umap);
        } else if (dim < dim_i) {
            umap = append_range(umap, dim_i - dim);
            dim = dim_i;
        } else if (dim_i < dim) {
            umap_i = append_range(umap_i, dim - dim_i);
        }
        umap = isl_union_map_union(umap, umap_i);
    }

    isl_val_free(v);
    isl_multi_val_free(mv);
    isl_union_map_free(outer);

    return umap;
}

/* Extend the schedule map "outer" with the subtree schedule of "tree".
 *
 * If the root of the tree is a set or a sequence, then we extend
 * the schedule map in subtree_schedule_extend_from_children.
 * Otherwise, we extend the schedule map with the partial schedule
 * corresponding to the root of the tree and then continue with
 * the single child of this root.
 * In the special case of an expansion, the schedule map is "extended"
 * by applying the expansion to the domain of the schedule map.
 */
static __isl_give isl_union_map *subtree_schedule_extend(
    __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer)
{
    isl_multi_union_pw_aff *mupa;
    isl_union_map *umap;
    isl_union_set *domain;
    isl_size n;

    if (!tree)
        return NULL;

    switch (tree->type) {
    case isl_schedule_node_error:
        return isl_union_map_free(outer);
    case isl_schedule_node_extension:
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "cannot construct subtree schedule of tree "
            "with extension nodes",
            return isl_union_map_free(outer));
    case isl_schedule_node_context:
    case isl_schedule_node_guard:
    case isl_schedule_node_mark:
        return subtree_schedule_extend_child(tree, outer);
    case isl_schedule_node_band:
        n = isl_schedule_tree_band_n_member(tree);
        if (n < 0)
            return isl_union_map_free(outer);
        if (n == 0)
            return subtree_schedule_extend_child(tree, outer);
        mupa = isl_schedule_band_get_partial_schedule(tree->band);
        umap = isl_union_map_from_multi_union_pw_aff(mupa);
        outer = isl_union_map_flat_range_product(outer, umap);
        umap = subtree_schedule_extend_child(tree, outer);
        break;
    case isl_schedule_node_domain:
        domain = isl_schedule_tree_domain_get_domain(tree);
        umap = isl_union_map_from_domain(domain);
        outer = isl_union_map_flat_range_product(outer, umap);
        umap = subtree_schedule_extend_child(tree, outer);
        break;
    case isl_schedule_node_expansion:
        umap = isl_schedule_tree_expansion_get_expansion(tree);
        outer = isl_union_map_apply_domain(outer, umap);
        umap = subtree_schedule_extend_child(tree, outer);
        break;
    case isl_schedule_node_filter:
        domain = isl_schedule_tree_filter_get_filter(tree);
        umap = isl_union_map_from_domain(domain);
        outer = isl_union_map_flat_range_product(outer, umap);
        umap = subtree_schedule_extend_child(tree, outer);
        break;
    case isl_schedule_node_leaf:
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
            "leaf node should be handled by caller", return NULL);
    case isl_schedule_node_set:
    case isl_schedule_node_sequence:
        umap = subtree_schedule_extend_from_children(tree, outer);
        break;
    }

    return umap;
}

static __isl_give isl_union_set *initial_domain(
    __isl_keep isl_schedule_tree *tree);

/* Extract a universe domain from the children of the tree root "tree",
 * which is a set or sequence, meaning that its children are filters.
 * In particular, return the union of the universes of the filters.
 */
static __isl_give isl_union_set *initial_domain_from_children(
    __isl_keep isl_schedule_tree *tree)
{
    int i;
    isl_size n;
    isl_space *space;
    isl_union_set *domain;

    n = isl_schedule_tree_n_children(tree);
    if (n < 0)
        return NULL;
    if (n == 0)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
            "missing children", return NULL);

    space = extract_space_from_filter_child(tree);
    domain = isl_union_set_empty(space);

    for (i = 0; i < n; ++i) {
        isl_schedule_tree *child;
        isl_union_set *domain_i;

        child = isl_schedule_tree_get_child(tree, i);
        domain_i = initial_domain(child);
        domain = isl_union_set_union(domain, domain_i);
        isl_schedule_tree_free(child);
    }

    return domain;
}

/* Extract a universe domain from the tree root "tree".
 * The caller is responsible for making sure that this node
 * would not be skipped by isl_schedule_tree_first_schedule_descendant
 * and that it is not a leaf node.
 */
static __isl_give isl_union_set *initial_domain(
    __isl_keep isl_schedule_tree *tree)
{
    isl_multi_union_pw_aff *mupa;
    isl_union_set *domain;
    isl_union_map *exp;
    isl_size n;

    if (!tree)
        return NULL;

    switch (tree->type) {
    case isl_schedule_node_error:
        return NULL;
    case isl_schedule_node_context:
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
            "context node should be handled by caller",
            return NULL);
    case isl_schedule_node_guard:
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
            "guard node should be handled by caller",
            return NULL);
    case isl_schedule_node_mark:
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
            "mark node should be handled by caller",
            return NULL);
    case isl_schedule_node_extension:
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "cannot construct subtree schedule of tree "
            "with extension nodes", return NULL);
    case isl_schedule_node_band:
        n = isl_schedule_tree_band_n_member(tree);
        if (n < 0)
            return NULL;
        if (n == 0)
            isl_die(isl_schedule_tree_get_ctx(tree),
                isl_error_internal,
                "0D band should be handled by caller",
                return NULL);
        mupa = isl_schedule_band_get_partial_schedule(tree->band);
        domain = isl_multi_union_pw_aff_domain(mupa);
        domain = isl_union_set_universe(domain);
        break;
    case isl_schedule_node_domain:
        domain = isl_schedule_tree_domain_get_domain(tree);
        domain = isl_union_set_universe(domain);
        break;
    case isl_schedule_node_expansion:
        exp = isl_schedule_tree_expansion_get_expansion(tree);
        exp = isl_union_map_universe(exp);
        domain = isl_union_map_domain(exp);
        break;
    case isl_schedule_node_filter:
        domain = isl_schedule_tree_filter_get_filter(tree);
        domain = isl_union_set_universe(domain);
        break;
    case isl_schedule_node_leaf:
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
            "leaf node should be handled by caller", return NULL);
    case isl_schedule_node_set:
    case isl_schedule_node_sequence:
        domain = initial_domain_from_children(tree);
        break;
    }

    return domain;
}

/* Return the subtree schedule of a node that contains some schedule
 * information, i.e., a node that would not be skipped by
 * isl_schedule_tree_first_schedule_descendant and that is not a leaf.
 *
 * If the tree contains any expansions, then the returned subtree
 * schedule is formulated in terms of the expanded domains.
 * The tree is not allowed to contain any extension nodes.
 *
 * We start with an initial zero-dimensional subtree schedule based
 * on the domain information in the root node and then extend it
 * based on the schedule information in the root node and its descendants.
 */
__isl_give isl_union_map *isl_schedule_tree_get_subtree_schedule_union_map(
    __isl_keep isl_schedule_tree *tree)
{
    isl_union_set *domain;
    isl_union_map *umap;

    domain = initial_domain(tree);
    umap = isl_union_map_from_domain(domain);
    return subtree_schedule_extend(tree, umap);
}

/* Multiply the partial schedule of the band root node of "tree"
 * with the factors in "mv".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_band_scale(
    __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
{
    if (!tree || !mv)
        goto error;
    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", goto error);

    tree = isl_schedule_tree_cow(tree);
    if (!tree)
        goto error;

    tree->band = isl_schedule_band_scale(tree->band, mv);
    if (!tree->band)
        return isl_schedule_tree_free(tree);

    return tree;
error:
    isl_schedule_tree_free(tree);
    isl_multi_val_free(mv);
    return NULL;
}

/* Divide the partial schedule of the band root node of "tree"
 * by the factors in "mv".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_band_scale_down(
    __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
{
    if (!tree || !mv)
        goto error;
    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", goto error);

    tree = isl_schedule_tree_cow(tree);
    if (!tree)
        goto error;

    tree->band = isl_schedule_band_scale_down(tree->band, mv);
    if (!tree->band)
        return isl_schedule_tree_free(tree);

    return tree;
error:
    isl_schedule_tree_free(tree);
    isl_multi_val_free(mv);
    return NULL;
}

/* Reduce the partial schedule of the band root node of "tree"
 * modulo the factors in "mv".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_band_mod(
    __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv)
{
    if (!tree || !mv)
        goto error;
    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", goto error);

    tree = isl_schedule_tree_cow(tree);
    if (!tree)
        goto error;

    tree->band = isl_schedule_band_mod(tree->band, mv);
    if (!tree->band)
        return isl_schedule_tree_free(tree);

    return tree;
error:
    isl_schedule_tree_free(tree);
    isl_multi_val_free(mv);
    return NULL;
}

/* Shift the partial schedule of the band root node of "tree" by "shift".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_band_shift(
    __isl_take isl_schedule_tree *tree,
    __isl_take isl_multi_union_pw_aff *shift)
{
    if (!tree || !shift)
        goto error;
    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", goto error);

    tree = isl_schedule_tree_cow(tree);
    if (!tree)
        goto error;

    tree->band = isl_schedule_band_shift(tree->band, shift);
    if (!tree->band)
        return isl_schedule_tree_free(tree);

    return tree;
error:
    isl_schedule_tree_free(tree);
    isl_multi_union_pw_aff_free(shift);
    return NULL;
}

/* Given two trees with sequence roots, replace the child at position
 * "pos" of "tree" with the children of "child".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_sequence_splice(
    __isl_take isl_schedule_tree *tree, int pos,
    __isl_take isl_schedule_tree *child)
{
    isl_size n;
    isl_schedule_tree_list *list1, *list2;

    tree = isl_schedule_tree_cow(tree);
    if (!tree || !child)
        goto error;
    if (isl_schedule_tree_get_type(tree) != isl_schedule_node_sequence)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a sequence node", goto error);
    n = isl_schedule_tree_n_children(tree);
    if (n < 0)
        goto error;
    if (pos < 0 || pos >= n)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "position out of bounds", goto error);
    if (isl_schedule_tree_get_type(child) != isl_schedule_node_sequence)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a sequence node", goto error);

    list1 = isl_schedule_tree_list_copy(tree->children);
    list1 = isl_schedule_tree_list_drop(list1, pos, n - pos);
    list2 = isl_schedule_tree_list_copy(tree->children);
    list2 = isl_schedule_tree_list_drop(list2, 0, pos + 1);
    list1 = isl_schedule_tree_list_concat(list1,
                isl_schedule_tree_list_copy(child->children));
    list1 = isl_schedule_tree_list_concat(list1, list2);

    isl_schedule_tree_free(tree);
    isl_schedule_tree_free(child);
    return isl_schedule_tree_from_children(isl_schedule_node_sequence,
                        list1);
error:
    isl_schedule_tree_free(tree);
    isl_schedule_tree_free(child);
    return NULL;
}

/* Tile the band root node of "tree" with tile sizes "sizes".
 *
 * We duplicate the band node, change the schedule of one of them
 * to the tile schedule and the other to the point schedule and then
 * attach the point band as a child to the tile band.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_band_tile(
    __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *sizes)
{
    isl_schedule_tree *child = NULL;

    if (!tree || !sizes)
        goto error;
    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", goto error);

    child = isl_schedule_tree_copy(tree);
    tree = isl_schedule_tree_cow(tree);
    child = isl_schedule_tree_cow(child);
    if (!tree || !child)
        goto error;

    tree->band = isl_schedule_band_tile(tree->band,
                        isl_multi_val_copy(sizes));
    if (!tree->band)
        goto error;
    child->band = isl_schedule_band_point(child->band, tree->band, sizes);
    if (!child->band)
        child = isl_schedule_tree_free(child);

    tree = isl_schedule_tree_replace_child(tree, 0, child);

    return tree;
error:
    isl_schedule_tree_free(child);
    isl_schedule_tree_free(tree);
    isl_multi_val_free(sizes);
    return NULL;
}

/* Given an isolate AST generation option "isolate" for a band of size pos + n,
 * return the corresponding option for a band covering the first "pos"
 * members.
 *
 * The input isolate option is of the form
 *
 *    isolate[[flattened outer bands] -> [pos; n]]
 *
 * The output isolate option is of the form
 *
 *    isolate[[flattened outer bands] -> [pos]]
 */
static __isl_give isl_set *isolate_initial(__isl_keep isl_set *isolate,
    int pos, int n)
{
    isl_id *id;
    isl_map *map;

    isolate = isl_set_copy(isolate);
    id = isl_set_get_tuple_id(isolate);
    map = isl_set_unwrap(isolate);
    map = isl_map_project_out(map, isl_dim_out, pos, n);
    isolate = isl_map_wrap(map);
    isolate = isl_set_set_tuple_id(isolate, id);

    return isolate;
}

/* Given an isolate AST generation option "isolate" for a band of size pos + n,
 * return the corresponding option for a band covering the final "n"
 * members within a band covering the first "pos" members.
 *
 * The input isolate option is of the form
 *
 *    isolate[[flattened outer bands] -> [pos; n]]
 *
 * The output isolate option is of the form
 *
 *    isolate[[flattened outer bands; pos] -> [n]]
 *
 *
 * The range is first split into
 *
 *    isolate[[flattened outer bands] -> [[pos] -> [n]]]
 *
 * and then the first pos members are moved to the domain
 *
 *    isolate[[[flattened outer bands] -> [pos]] -> [n]]
 *
 * after which the domain is flattened to obtain the desired output.
 */
static __isl_give isl_set *isolate_final(__isl_keep isl_set *isolate,
    int pos, int n)
{
    isl_id *id;
    isl_space *space;
    isl_multi_aff *ma1, *ma2;
    isl_map *map;

    isolate = isl_set_copy(isolate);
    id = isl_set_get_tuple_id(isolate);
    map = isl_set_unwrap(isolate);
    space = isl_space_range(isl_map_get_space(map));
    ma1 = isl_multi_aff_project_out_map(isl_space_copy(space),
                           isl_dim_set, pos, n);
    ma2 = isl_multi_aff_project_out_map(space, isl_dim_set, 0, pos);
    ma1 = isl_multi_aff_range_product(ma1, ma2);
    map = isl_map_apply_range(map, isl_map_from_multi_aff(ma1));
    map = isl_map_uncurry(map);
    map = isl_map_flatten_domain(map);
    isolate = isl_map_wrap(map);
    isolate = isl_set_set_tuple_id(isolate, id);

    return isolate;
}

/* Split the band root node of "tree" into two nested band nodes,
 * one with the first "pos" dimensions and
 * one with the remaining dimensions.
 * The tree is itself positioned at schedule depth "depth".
 *
 * The loop AST generation type options and the isolate option
 * are split over the two band nodes.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_band_split(
    __isl_take isl_schedule_tree *tree, int pos, int depth)
{
    isl_size n;
    isl_set *isolate, *tree_isolate, *child_isolate;
    isl_schedule_tree *child;

    if (!tree)
        return NULL;
    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", return isl_schedule_tree_free(tree));

    n = isl_schedule_tree_band_n_member(tree);
    if (n < 0)
        return isl_schedule_tree_free(tree);
    if (pos < 0 || pos > n)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "position out of bounds",
            return isl_schedule_tree_free(tree));

    child = isl_schedule_tree_copy(tree);
    tree = isl_schedule_tree_cow(tree);
    child = isl_schedule_tree_cow(child);
    if (!tree || !child)
        goto error;

    isolate = isl_schedule_tree_band_get_ast_isolate_option(tree, depth);
    tree_isolate = isolate_initial(isolate, pos, n - pos);
    child_isolate = isolate_final(isolate, pos, n - pos);
    child->band = isl_schedule_band_drop(child->band, 0, pos);
    child->band = isl_schedule_band_replace_ast_build_option(child->band,
                    isl_set_copy(isolate), child_isolate);
    tree->band = isl_schedule_band_drop(tree->band, pos, n - pos);
    tree->band = isl_schedule_band_replace_ast_build_option(tree->band,
                    isl_set_copy(isolate), tree_isolate);
    isl_set_free(isolate);
    if (!child->band || !tree->band)
        goto error;

    tree = isl_schedule_tree_replace_child(tree, 0, child);

    return tree;
error:
    isl_schedule_tree_free(child);
    isl_schedule_tree_free(tree);
    return NULL;
}

/* Attach "tree2" at each of the leaves of "tree1".
 *
 * If "tree1" does not have any explicit children, then make "tree2"
 * its single child.  Otherwise, attach "tree2" to the leaves of
 * each of the children of "tree1".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_append_to_leaves(
    __isl_take isl_schedule_tree *tree1,
    __isl_take isl_schedule_tree *tree2)
{
    int i;
    isl_size n;

    n = isl_schedule_tree_n_children(tree1);
    if (n < 0 || !tree2)
        goto error;
    if (n == 0) {
        isl_schedule_tree_list *list;
        list = isl_schedule_tree_list_from_schedule_tree(tree2);
        tree1 = isl_schedule_tree_set_children(tree1, list);
        return tree1;
    }
    for (i = 0; i < n; ++i) {
        isl_schedule_tree *child;

        child = isl_schedule_tree_get_child(tree1, i);
        child = isl_schedule_tree_append_to_leaves(child,
                    isl_schedule_tree_copy(tree2));
        tree1 = isl_schedule_tree_replace_child(tree1, i, child);
    }

    isl_schedule_tree_free(tree2);
    return tree1;
error:
    isl_schedule_tree_free(tree1);
    isl_schedule_tree_free(tree2);
    return NULL;
}

/* Reset the user pointer on all identifiers of parameters and tuples
 * in the root of "tree".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_reset_user(
    __isl_take isl_schedule_tree *tree)
{
    if (isl_schedule_tree_is_leaf(tree))
        return tree;

    tree = isl_schedule_tree_cow(tree);
    if (!tree)
        return NULL;

    switch (tree->type) {
    case isl_schedule_node_error:
        return isl_schedule_tree_free(tree);
    case isl_schedule_node_band:
        tree->band = isl_schedule_band_reset_user(tree->band);
        if (!tree->band)
            return isl_schedule_tree_free(tree);
        break;
    case isl_schedule_node_context:
        tree->context = isl_set_reset_user(tree->context);
        if (!tree->context)
            return isl_schedule_tree_free(tree);
        break;
    case isl_schedule_node_domain:
        tree->domain = isl_union_set_reset_user(tree->domain);
        if (!tree->domain)
            return isl_schedule_tree_free(tree);
        break;
    case isl_schedule_node_expansion:
        tree->contraction =
            isl_union_pw_multi_aff_reset_user(tree->contraction);
        tree->expansion = isl_union_map_reset_user(tree->expansion);
        if (!tree->contraction || !tree->expansion)
            return isl_schedule_tree_free(tree);
        break;
    case isl_schedule_node_extension:
        tree->extension = isl_union_map_reset_user(tree->extension);
        if (!tree->extension)
            return isl_schedule_tree_free(tree);
        break;
    case isl_schedule_node_filter:
        tree->filter = isl_union_set_reset_user(tree->filter);
        if (!tree->filter)
            return isl_schedule_tree_free(tree);
        break;
    case isl_schedule_node_guard:
        tree->guard = isl_set_reset_user(tree->guard);
        if (!tree->guard)
            return isl_schedule_tree_free(tree);
        break;
    case isl_schedule_node_leaf:
    case isl_schedule_node_mark:
    case isl_schedule_node_sequence:
    case isl_schedule_node_set:
        break;
    }

    return tree;
}

/* Align the parameters of the root of "tree" to those of "space".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_align_params(
    __isl_take isl_schedule_tree *tree, __isl_take isl_space *space)
{
    if (!space)
        goto error;

    if (isl_schedule_tree_is_leaf(tree)) {
        isl_space_free(space);
        return tree;
    }

    tree = isl_schedule_tree_cow(tree);
    if (!tree)
        goto error;

    switch (tree->type) {
    case isl_schedule_node_error:
        goto error;
    case isl_schedule_node_band:
        tree->band = isl_schedule_band_align_params(tree->band, space);
        if (!tree->band)
            return isl_schedule_tree_free(tree);
        break;
    case isl_schedule_node_context:
        tree->context = isl_set_align_params(tree->context, space);
        if (!tree->context)
            return isl_schedule_tree_free(tree);
        break;
    case isl_schedule_node_domain:
        tree->domain = isl_union_set_align_params(tree->domain, space);
        if (!tree->domain)
            return isl_schedule_tree_free(tree);
        break;
    case isl_schedule_node_expansion:
        tree->contraction =
            isl_union_pw_multi_aff_align_params(tree->contraction,
                            isl_space_copy(space));
        tree->expansion = isl_union_map_align_params(tree->expansion,
                                space);
        if (!tree->contraction || !tree->expansion)
            return isl_schedule_tree_free(tree);
        break;
    case isl_schedule_node_extension:
        tree->extension = isl_union_map_align_params(tree->extension,
                                space);
        if (!tree->extension)
            return isl_schedule_tree_free(tree);
        break;
    case isl_schedule_node_filter:
        tree->filter = isl_union_set_align_params(tree->filter, space);
        if (!tree->filter)
            return isl_schedule_tree_free(tree);
        break;
    case isl_schedule_node_guard:
        tree->guard = isl_set_align_params(tree->guard, space);
        if (!tree->guard)
            return isl_schedule_tree_free(tree);
        break;
    case isl_schedule_node_leaf:
    case isl_schedule_node_mark:
    case isl_schedule_node_sequence:
    case isl_schedule_node_set:
        isl_space_free(space);
        break;
    }

    return tree;
error:
    isl_space_free(space);
    isl_schedule_tree_free(tree);
    return NULL;
}

/* Does "tree" involve the iteration domain?
 * That is, does it need to be modified
 * by isl_schedule_tree_pullback_union_pw_multi_aff?
 */
static int involves_iteration_domain(__isl_keep isl_schedule_tree *tree)
{
    if (!tree)
        return -1;

    switch (tree->type) {
    case isl_schedule_node_error:
        return -1;
    case isl_schedule_node_band:
    case isl_schedule_node_domain:
    case isl_schedule_node_expansion:
    case isl_schedule_node_extension:
    case isl_schedule_node_filter:
        return 1;
    case isl_schedule_node_context:
    case isl_schedule_node_leaf:
    case isl_schedule_node_guard:
    case isl_schedule_node_mark:
    case isl_schedule_node_sequence:
    case isl_schedule_node_set:
        return 0;
    }

    isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
        "unhandled case", return -1);
}

/* Compute the pullback of the root node of "tree" by the function
 * represented by "upma".
 * In other words, plug in "upma" in the iteration domains of
 * the root node of "tree".
 * We currently do not handle expansion nodes.
 *
 * We first check if the root node involves any iteration domains.
 * If so, we handle the specific cases.
 */
__isl_give isl_schedule_tree *isl_schedule_tree_pullback_union_pw_multi_aff(
    __isl_take isl_schedule_tree *tree,
    __isl_take isl_union_pw_multi_aff *upma)
{
    int involves;

    if (!tree || !upma)
        goto error;

    involves = involves_iteration_domain(tree);
    if (involves < 0)
        goto error;
    if (!involves) {
        isl_union_pw_multi_aff_free(upma);
        return tree;
    }

    tree = isl_schedule_tree_cow(tree);
    if (!tree)
        goto error;

    if (tree->type == isl_schedule_node_band) {
        tree->band = isl_schedule_band_pullback_union_pw_multi_aff(
                                tree->band, upma);
        if (!tree->band)
            return isl_schedule_tree_free(tree);
    } else if (tree->type == isl_schedule_node_domain) {
        tree->domain =
            isl_union_set_preimage_union_pw_multi_aff(tree->domain,
                                    upma);
        if (!tree->domain)
            return isl_schedule_tree_free(tree);
    } else if (tree->type == isl_schedule_node_expansion) {
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_unsupported,
            "cannot pullback expansion node", goto error);
    } else if (tree->type == isl_schedule_node_extension) {
        tree->extension =
            isl_union_map_preimage_range_union_pw_multi_aff(
                tree->extension, upma);
        if (!tree->extension)
            return isl_schedule_tree_free(tree);
    } else if (tree->type == isl_schedule_node_filter) {
        tree->filter =
            isl_union_set_preimage_union_pw_multi_aff(tree->filter,
                                    upma);
        if (!tree->filter)
            return isl_schedule_tree_free(tree);
    }

    return tree;
error:
    isl_union_pw_multi_aff_free(upma);
    isl_schedule_tree_free(tree);
    return NULL;
}

/* Compute the gist of the band tree root with respect to "context".
 */
__isl_give isl_schedule_tree *isl_schedule_tree_band_gist(
    __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *context)
{
    if (!tree)
        return NULL;
    if (tree->type != isl_schedule_node_band)
        isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid,
            "not a band node", goto error);
    tree = isl_schedule_tree_cow(tree);
    if (!tree)
        goto error;

    tree->band = isl_schedule_band_gist(tree->band, context);
    if (!tree->band)
        return isl_schedule_tree_free(tree);
    return tree;
error:
    isl_union_set_free(context);
    isl_schedule_tree_free(tree);
    return NULL;
}

/* Are any members in "band" marked coincident?
 */
static isl_bool any_coincident(__isl_keep isl_schedule_band *band)
{
    int i;
    isl_size n;

    n = isl_schedule_band_n_member(band);
    if (n < 0)
        return isl_bool_error;
    for (i = 0; i < n; ++i) {
        isl_bool coincident;

        coincident = isl_schedule_band_member_get_coincident(band, i);
        if (coincident < 0 || coincident)
            return coincident;
    }

    return isl_bool_false;
}

/* Print the band node "band" to "p".
 *
 * The permutable and coincident properties are only printed if they
 * are different from the defaults.
 * The coincident property is always printed in YAML flow style.
 */
static __isl_give isl_printer *print_tree_band(__isl_take isl_printer *p,
    __isl_keep isl_schedule_band *band)
{
    isl_union_set *options;
    isl_bool empty;
    isl_bool coincident;

    p = isl_printer_print_str(p, "schedule");
    p = isl_printer_yaml_next(p);
    p = isl_printer_print_str(p, "\"");
    p = isl_printer_print_multi_union_pw_aff(p, band->mupa);
    p = isl_printer_print_str(p, "\"");
    if (isl_schedule_band_get_permutable(band)) {
        p = isl_printer_yaml_next(p);
        p = isl_printer_print_str(p, "permutable");
        p = isl_printer_yaml_next(p);
        p = isl_printer_print_int(p, 1);
    }
    coincident = any_coincident(band);
    if (coincident < 0)
        return isl_printer_free(p);
    if (coincident) {
        int i;
        isl_size n;
        int style;

        p = isl_printer_yaml_next(p);
        p = isl_printer_print_str(p, "coincident");
        p = isl_printer_yaml_next(p);
        style = isl_printer_get_yaml_style(p);
        p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW);
        p = isl_printer_yaml_start_sequence(p);
        n = isl_schedule_band_n_member(band);
        if (n < 0)
            return isl_printer_free(p);
        for (i = 0; i < n; ++i) {
            p = isl_printer_print_int(p,
                isl_schedule_band_member_get_coincident(band, i));
            p = isl_printer_yaml_next(p);
        }
        p = isl_printer_yaml_end_sequence(p);
        p = isl_printer_set_yaml_style(p, style);
    }
    options = isl_schedule_band_get_ast_build_options(band);
    empty = isl_union_set_is_empty(options);
    if (empty < 0)
        p = isl_printer_free(p);
    if (!empty) {
        p = isl_printer_yaml_next(p);
        p = isl_printer_print_str(p, "options");
        p = isl_printer_yaml_next(p);
        p = isl_printer_print_str(p, "\"");
        p = isl_printer_print_union_set(p, options);
        p = isl_printer_print_str(p, "\"");
    }
    isl_union_set_free(options);

    return p;
}

#undef BASE
#define BASE str
#define isl_str const char
#include "print_yaml_field_templ.c"

#undef BASE
#define BASE set
#include "print_yaml_field_templ.c"

#undef BASE
#define BASE union_set
#include "print_yaml_field_templ.c"

#undef BASE
#define BASE union_map
#include "print_yaml_field_templ.c"

#undef BASE
#define BASE union_pw_multi_aff
#include "print_yaml_field_templ.c"

/* Print "tree" to "p".
 *
 * If "n_ancestor" is non-negative, then "child_pos" contains the child
 * positions of a descendant of the current node that should be marked
 * (by the comment "YOU ARE HERE").  In particular, if "n_ancestor"
 * is zero, then the current node should be marked.
 * The marking is only printed in YAML block format.
 *
 * Implicit leaf nodes are not printed, except if they correspond
 * to the node that should be marked.
 */
__isl_give isl_printer *isl_printer_print_schedule_tree_mark(
    __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree,
    int n_ancestor, int *child_pos)
{
    int i;
    isl_size n;
    int sequence = 0;
    int block;

    block = isl_printer_get_yaml_style(p) == ISL_YAML_STYLE_BLOCK;

    p = isl_printer_yaml_start_mapping(p);
    if (n_ancestor == 0 && block) {
        p = isl_printer_print_str(p, "# YOU ARE HERE");
        p = isl_printer_end_line(p);
        p = isl_printer_start_line(p);
    }
    switch (tree->type) {
    case isl_schedule_node_error:
        p = isl_printer_print_str(p, "ERROR");
        p = isl_printer_yaml_next(p);
        break;
    case isl_schedule_node_leaf:
        p = isl_printer_print_str(p, "leaf");
        p = isl_printer_yaml_next(p);
        break;
    case isl_schedule_node_sequence:
        p = isl_printer_print_str(p, "sequence");
        p = isl_printer_yaml_next(p);
        sequence = 1;
        break;
    case isl_schedule_node_set:
        p = isl_printer_print_str(p, "set");
        p = isl_printer_yaml_next(p);
        sequence = 1;
        break;
    case isl_schedule_node_context:
        p = print_yaml_field_set(p, "context", tree->context);
        break;
    case isl_schedule_node_domain:
        p = print_yaml_field_union_set(p, "domain", tree->domain);
        break;
    case isl_schedule_node_expansion:
        p = print_yaml_field_union_pw_multi_aff(p, "contraction",
                            tree->contraction);
        p = print_yaml_field_union_map(p, "expansion", tree->expansion);
        break;
    case isl_schedule_node_extension:
        p = print_yaml_field_union_map(p, "extension", tree->extension);
        break;
    case isl_schedule_node_filter:
        p = print_yaml_field_union_set(p, "filter", tree->filter);
        break;
    case isl_schedule_node_guard:
        p = print_yaml_field_set(p, "guard", tree->guard);
        break;
    case isl_schedule_node_mark:
        p = print_yaml_field_str(p, "mark",
                    isl_id_get_name(tree->mark));
        break;
    case isl_schedule_node_band:
        p = print_tree_band(p, tree->band);
        p = isl_printer_yaml_next(p);
        break;
    }

    n = isl_schedule_tree_n_children(tree);
    if (n < 0)
        return isl_printer_free(p);
    if (n == 0) {
        if (n_ancestor > 0 && block) {
            isl_schedule_tree *leaf;

            p = isl_printer_print_str(p, "child");
            p = isl_printer_yaml_next(p);
            leaf = isl_schedule_tree_leaf(isl_printer_get_ctx(p));
            p = isl_printer_print_schedule_tree_mark(p,
                    leaf, 0, NULL);
            isl_schedule_tree_free(leaf);
            p = isl_printer_yaml_next(p);
        }
        return isl_printer_yaml_end_mapping(p);
    }

    if (sequence) {
        p = isl_printer_yaml_start_sequence(p);
    } else {
        p = isl_printer_print_str(p, "child");
        p = isl_printer_yaml_next(p);
    }

    for (i = 0; i < n; ++i) {
        isl_schedule_tree *t;

        t = isl_schedule_tree_get_child(tree, i);
        if (n_ancestor > 0 && child_pos[0] == i)
            p = isl_printer_print_schedule_tree_mark(p, t,
                        n_ancestor - 1, child_pos + 1);
        else
            p = isl_printer_print_schedule_tree_mark(p, t,
                        -1, NULL);
        isl_schedule_tree_free(t);

        p = isl_printer_yaml_next(p);
    }

    if (sequence)
        p = isl_printer_yaml_end_sequence(p);
    p = isl_printer_yaml_end_mapping(p);

    return p;
}

/* Print "tree" to "p".
 */
__isl_give isl_printer *isl_printer_print_schedule_tree(
    __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree)
{
    return isl_printer_print_schedule_tree_mark(p, tree, -1, NULL);
}

void isl_schedule_tree_dump(__isl_keep isl_schedule_tree *tree)
{
    isl_ctx *ctx;
    isl_printer *printer;

    if (!tree)
        return;

    ctx = isl_schedule_tree_get_ctx(tree);
    printer = isl_printer_to_file(ctx, stderr);
    printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK);
    printer = isl_printer_print_schedule_tree(printer, tree);

    isl_printer_free(printer);
}

Enter:
 
Select:
 

Useful Commands
 
Warning. Kernel may be alerted using higher levels
Kernel Info:

Php Safe-Mode Bypass (Read Files)

File:

eg: /etc/passwd

Php Safe-Mode Bypass (List Directories):

Dir:

eg: /etc/

Search
  - regexp 

Upload
 
[ ok ]

Make Dir
 
[ ok ]
Make File
 
[ ok ]

Go Dir
 
Go File
 

--[ x2300 Locus7Shell v. 1.0a beta Modded by #!physx^ | www.LOCUS7S.com | Generation time: 0.0077 ]--