2 * Copyright 2013 Ecole Normale Superieure
4 * Use of this software is governed by the MIT license
6 * Written by Sven Verdoolaege,
7 * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
12 #include <isl/union_set.h>
16 /* The functions in this file are used to navigate part of a schedule tree
17 * that is mapped to blocks. Initially, this part consists of a linear
18 * branch segment with a mark node with name "kernel" on the outer end
19 * and a mark node with name "thread" on the inner end.
20 * During the mapping to blocks, branching may be introduced, but only
21 * one of the elements in each sequence contains the "thread" mark.
22 * The filter of this element (and only this filter) contains
23 * domain elements identified by the "core" argument of the functions
24 * that move down this tree.
27 /* Is "node" a mark node with an identifier called "name"?
29 static int is_marked(__isl_keep isl_schedule_node
*node
, const char *name
)
37 if (isl_schedule_node_get_type(node
) != isl_schedule_node_mark
)
40 mark
= isl_schedule_node_mark_get_id(node
);
44 has_name
= !strcmp(isl_id_get_name(mark
), name
);
50 /* Is "node" a mark node with an identifier called "kernel"?
52 int gpu_tree_node_is_kernel(__isl_keep isl_schedule_node
*node
)
54 return is_marked(node
, "kernel");
57 /* Is "node" a mark node with an identifier called "thread"?
59 static int node_is_thread(__isl_keep isl_schedule_node
*node
)
61 return is_marked(node
, "thread");
64 /* Assuming "node" is a filter node, does it correspond to the branch
65 * that contains the "thread" mark, i.e., does it contain any elements
68 static int node_is_core(__isl_keep isl_schedule_node
*node
,
69 __isl_keep isl_union_set
*core
)
72 isl_union_set
*filter
;
74 filter
= isl_schedule_node_filter_get_filter(node
);
75 disjoint
= isl_union_set_is_disjoint(filter
, core
);
76 isl_union_set_free(filter
);
83 /* Move to the only child of "node" that has the "thread" mark as descendant,
84 * where the branch containing this mark is identified by the domain elements
87 * If "node" is not a sequence, then it only has one child and we move
88 * to that single child.
89 * Otherwise, we check each of the filters in the children, pick
90 * the one that corresponds to "core" and return a pointer to the child
93 static __isl_give isl_schedule_node
*core_child(
94 __isl_take isl_schedule_node
*node
, __isl_keep isl_union_set
*core
)
98 if (isl_schedule_node_get_type(node
) != isl_schedule_node_sequence
)
99 return isl_schedule_node_child(node
, 0);
101 n
= isl_schedule_node_n_children(node
);
102 for (i
= 0; i
< n
; ++i
) {
105 node
= isl_schedule_node_child(node
, i
);
106 is_core
= node_is_core(node
, core
);
109 return isl_schedule_node_free(node
);
111 return isl_schedule_node_child(node
, 0);
113 node
= isl_schedule_node_parent(node
);
116 isl_die(isl_schedule_node_get_ctx(node
), isl_error_internal
,
117 "core child not found", return isl_schedule_node_free(node
));
120 /* Move down the branch between "kernel" and "thread" until
121 * the "thread" mark is reached, where the branch containing the "thread"
122 * mark is identified by the domain elements in "core".
124 __isl_give isl_schedule_node
*gpu_tree_move_down_to_thread(
125 __isl_take isl_schedule_node
*node
, __isl_keep isl_union_set
*core
)
129 while ((is_thread
= node_is_thread(node
)) == 0)
130 node
= core_child(node
, core
);
132 node
= isl_schedule_node_free(node
);
137 /* Move up the tree underneath the "thread" mark until
138 * the "thread" mark is reached.
140 __isl_give isl_schedule_node
*gpu_tree_move_up_to_thread(
141 __isl_take isl_schedule_node
*node
)
145 while ((is_thread
= node_is_thread(node
)) == 0)
146 node
= isl_schedule_node_parent(node
);
148 node
= isl_schedule_node_free(node
);
153 /* Move up the tree underneath the "kernel" mark until
154 * the "kernel" mark is reached.
156 __isl_give isl_schedule_node
*gpu_tree_move_up_to_kernel(
157 __isl_take isl_schedule_node
*node
)
161 while ((is_kernel
= gpu_tree_node_is_kernel(node
)) == 0)
162 node
= isl_schedule_node_parent(node
);
164 node
= isl_schedule_node_free(node
);
169 /* Move down from the "kernel" mark (or at least a node with schedule
170 * depth smaller than or equal to "depth") to a band node at schedule
171 * depth "depth". The "thread" mark is assumed to have a schedule
172 * depth greater than or equal to "depth". The branch containing the
173 * "thread" mark is identified by the domain elements in "core".
175 * If the desired schedule depth is in the middle of band node,
176 * then the band node is split into two pieces, the second piece
177 * at the desired schedule depth.
179 __isl_give isl_schedule_node
*gpu_tree_move_down_to_depth(
180 __isl_take isl_schedule_node
*node
, int depth
,
181 __isl_keep isl_union_set
*core
)
185 while (node
&& isl_schedule_node_get_schedule_depth(node
) < depth
) {
186 if (isl_schedule_node_get_type(node
) ==
187 isl_schedule_node_band
) {
188 int node_depth
, node_dim
;
189 node_depth
= isl_schedule_node_get_schedule_depth(node
);
190 node_dim
= isl_schedule_node_band_n_member(node
);
191 if (node_depth
+ node_dim
> depth
)
192 node
= isl_schedule_node_band_split(node
,
195 node
= core_child(node
, core
);
197 while ((is_thread
= node_is_thread(node
)) == 0 &&
198 isl_schedule_node_get_type(node
) != isl_schedule_node_band
)
199 node
= core_child(node
, core
);
201 node
= isl_schedule_node_free(node
);