5 #include <isl/constraint.h>
6 #include <isl/polynomial.h>
7 #include <barvinok/isl.h>
11 #include "translation.h"
12 #include "mem_options.h"
21 /* Compute the number of array elements that are read but not
22 * (previously) written. These are assumed to be the input.
24 static __isl_give isl_pw_qpolynomial
*compute_input_size(PDG
*pdg
,
25 struct options
*options
)
27 unsigned nparam
= pdg
->params
.size();
29 isl_pw_qpolynomial
*inputsize
;
31 space
= isl_space_alloc(pdg
->get_isl_ctx(), nparam
, 0, 1);
32 isl_dim_set_parameter_names(space
, pdg
->params
);
33 inputsize
= isl_pw_qpolynomial_zero(space
);
35 if (!options
->with_input
)
38 for (int i
= 0; i
< pdg
->dependences
.size(); ++i
) {
40 isl_pw_qpolynomial
*size
;
41 pdg::dependence
*dep
= pdg
->dependences
[i
];
43 if (dep
->type
!= pdg::dependence::uninitialized
)
46 map
= dep
->relation
->get_isl_map(pdg
->get_isl_ctx());
47 size
= isl_map_card(map
);
48 inputsize
= isl_pw_qpolynomial_add(inputsize
, size
);
54 /* Compute the number of elements in domain for a fixed value
55 * of the "fixed_loops" outer loop iterators and return this value
56 * as a function of these loop iterators and the parameters.
58 static __isl_give isl_pw_qpolynomial
*compute_accesses_at(
59 __isl_take isl_set
*domain
, int fixed_loops
)
62 map
= isl_map_from_range(domain
);
63 map
= isl_map_move_dims(map
, isl_dim_in
, 0, isl_dim_out
, 0, fixed_loops
);
64 return isl_map_card(map
);
67 /* Compute the number of elements in domain for a fixed value
68 * of the "level" outer loop iterators and for all values of the
69 * loop iterator at level "level" smaller than a fixed value
70 * and return this value as a function of these (level+1) loop iterators
73 static __isl_give isl_pw_qpolynomial
*compute_accesses_before(
74 __isl_take isl_set
*domain
, int level
)
77 map
= isl_map_from_range(domain
);
78 map
= isl_map_move_dims(map
, isl_dim_in
, 0, isl_dim_out
, 0, level
);
79 map
= isl_map_add_dims(map
, isl_dim_in
, 1);
80 map
= isl_map_order_lt(map
, isl_dim_out
, 0, isl_dim_in
, level
);
81 return isl_map_card(map
);
84 static int cmp_prefix_stat_dims(pdg::node
*node
, int *stat_dims
, int d
)
86 for (int j
= 0; j
< d
; ++j
)
87 if (node
->prefix
[2*j
] != stat_dims
[j
])
88 return node
->prefix
[2*j
] - stat_dims
[j
];
94 * Returns true if dependence is independent of first n_loops loops.
96 static int is_loop_independent(isl_ctx
*ctx
,
97 pdg::IslMap
*relation
, int n_loops
)
101 assert(relation
->input() >= n_loops
);
102 assert(relation
->output() >= n_loops
);
105 rel
= relation
->get_isl_map(ctx
);
106 test
= isl_map_universe(isl_map_get_space(rel
));
107 for (int i
= 0; i
< n_loops
; ++i
)
108 test
= isl_map_equate(test
, isl_dim_in
, i
, isl_dim_out
, i
);
109 indep
= isl_map_is_subset(rel
, test
);
116 struct contribution
{
117 unsigned is_read
: 1;
118 unsigned is_written
: 1;
122 * Determines the net contribution of "dep" within statements
123 * with statement level dimensions prefixed by stat_dims
124 * and within a fixed iteration of the first n_loop loops.
126 static struct contribution
net_contribution(isl_ctx
*ctx
, pdg::dependence
*dep
,
127 int *stat_dims
, int d
, int n_loop
,
128 struct options
*options
)
130 struct contribution c
;
134 if (dep
->type
== pdg::dependence::uninitialized
) {
135 if (options
->with_input
&&
136 cmp_prefix_stat_dims(dep
->to
, stat_dims
, d
) == 0)
139 int is_written
= cmp_prefix_stat_dims(dep
->from
, stat_dims
, d
) == 0;
140 int is_read
= cmp_prefix_stat_dims(dep
->to
, stat_dims
, d
) == 0;
141 int is_local
= is_written
&& is_read
&&
142 is_loop_independent(ctx
, dep
->relation
, n_loop
);
145 c
.is_written
= is_written
;
158 * Compute increment in statement/loop identified by stat_dims
160 static __isl_give isl_pw_qpolynomial
*compute_live_increment(PDG
*pdg
,
161 int *stat_dims
, int d
, struct access
*accesses
, struct options
*options
)
163 unsigned nparam
= pdg
->params
.size();
165 isl_pw_qpolynomial
*sum
;
167 space
= isl_space_alloc(pdg
->get_isl_ctx(), nparam
, d
- 1, 1);
168 isl_dim_set_parameter_names(space
, pdg
->params
);
169 sum
= isl_pw_qpolynomial_zero(space
);
170 for (int i
= 0; i
< pdg
->dependences
.size(); ++i
) {
171 pdg::dependence
*dep
= pdg
->dependences
[i
];
172 struct contribution c
;
174 c
= net_contribution(pdg
->get_isl_ctx(),
175 dep
, stat_dims
, d
, d
-1, options
);
178 isl_pw_qpolynomial
*inc
;
179 inc
= compute_accesses_at(isl_set_copy(accesses
[i
].write
), d
- 1);
180 sum
= isl_pw_qpolynomial_add(sum
, inc
);
183 isl_pw_qpolynomial
*dec
;
184 dec
= compute_accesses_at(isl_set_copy(accesses
[i
].read
), d
- 1);
185 sum
= isl_pw_qpolynomial_sub(sum
, dec
);
192 * Compute increment in previous iterations of loop at given level.
194 static __isl_give isl_pw_qpolynomial
*compute_live_increment_in_loop(PDG
*pdg
,
195 int *stat_dims
, int level
, struct access
*accesses
,
196 struct options
*options
)
198 unsigned nparam
= pdg
->params
.size();
200 isl_pw_qpolynomial
*sum
;
202 space
= isl_space_alloc(pdg
->get_isl_ctx(), nparam
, level
+ 1, 1);
203 isl_dim_set_parameter_names(space
, pdg
->params
);
204 sum
= isl_pw_qpolynomial_zero(space
);
205 for (int i
= 0; i
< pdg
->dependences
.size(); ++i
) {
206 pdg::dependence
*dep
= pdg
->dependences
[i
];
207 struct contribution c
;
209 c
= net_contribution(pdg
->get_isl_ctx(),
210 dep
, stat_dims
, level
+1, level
+1, options
);
213 isl_pw_qpolynomial
*inc
;
214 inc
= compute_accesses_before(isl_set_copy(accesses
[i
].write
), level
);
215 sum
= isl_pw_qpolynomial_add(sum
, inc
);
218 isl_pw_qpolynomial
*dec
;
219 dec
= compute_accesses_before(isl_set_copy(accesses
[i
].read
), level
);
220 sum
= isl_pw_qpolynomial_sub(sum
, dec
);
231 vector
<struct tree
*> children
;
236 * Compute bound on number of live array elements in the
239 * live_before: number of live elements before the loop/statement
240 * in terms of the outer loop iterators
242 static __isl_give isl_pw_qpolynomial_fold
*compute_bound(PDG
*pdg
,
243 __isl_take isl_pw_qpolynomial
*live
,
245 struct access
*accesses
,
246 struct options
*options
)
248 /* If we are in a leaf, we actually compute the bound. */
249 if (tree
->children
.size() == 0) {
251 isl_pw_qpolynomial_fold
*bound
;
253 domain
= isl_set_copy(tree
->domain
);
254 domain
= isl_set_reset_tuple_id(domain
);
255 live
= isl_pw_qpolynomial_intersect_domain(live
, domain
);
256 bound
= isl_pw_qpolynomial_bound(live
, isl_fold_max
, NULL
);
261 isl_pw_qpolynomial_fold
*pwf
;
263 /* If we are not in the outer dummy loop, add contribution of
264 * previous iterations.
268 isl_pw_qpolynomial
*inc
;
270 live
= isl_pw_qpolynomial_add_dims(live
, isl_dim_in
, 1);
271 inc
= compute_live_increment_in_loop(pdg
, tree
->stat_dims
, tree
->d
-1,
273 live
= isl_pw_qpolynomial_add(live
, inc
);
276 pwf
= compute_bound(pdg
, isl_pw_qpolynomial_copy(live
),
277 tree
->children
[0], accesses
, options
);
278 for (int i
= 1; i
< tree
->children
.size(); ++i
) {
279 isl_pw_qpolynomial_fold
*pwf_i
;
280 isl_pw_qpolynomial
*inc
;
281 struct tree
*child
= tree
->children
[i
-1];
282 inc
= compute_live_increment(pdg
, child
->stat_dims
, child
->d
,
284 live
= isl_pw_qpolynomial_add(live
, inc
);
285 pwf_i
= compute_bound(pdg
, isl_pw_qpolynomial_copy(live
),
286 tree
->children
[i
], accesses
, options
);
287 pwf
= isl_pw_qpolynomial_fold_fold(pwf
, pwf_i
);
289 isl_pw_qpolynomial_free(live
);
294 * Construct a tree for all statements whose statement dimensions
295 * start with the d first elements of stat_dims.
296 * The first one of those statemens is statement n.
298 static struct tree
*compute_tree(PDG
*pdg
, int *stat_dims
, int d
, int n
)
300 struct tree
*tree
= new struct tree
;
303 tree
->stat_dims
= new int[d
];
304 for (int i
= 0; i
< d
; ++i
)
305 tree
->stat_dims
[i
] = stat_dims
[i
];
307 if (pdg
->nodes
[n
]->prefix
.size() == 2*d
-1) {
308 tree
->domain
= pdg
->nodes
[n
]->source
->get_isl_set(pdg
->get_isl_ctx());
312 for (int i
= n
; i
< pdg
->nodes
.size(); ++i
) {
313 if (cmp_prefix_stat_dims(pdg
->nodes
[i
], stat_dims
, d
) > 0)
316 stat_dims
[d
] = pdg
->nodes
[i
]->prefix
[2*d
];
318 struct tree
*child
= compute_tree(pdg
, stat_dims
, d
+1, i
);
319 tree
->children
.push_back(child
);
321 /* Skip over nodes with the same prefix at current level */
322 for (; i
+1 < pdg
->nodes
.size(); ++i
)
323 if (cmp_prefix_stat_dims(pdg
->nodes
[i
+1], stat_dims
, d
+1) != 0)
329 static struct tree
*compute_tree(PDG
*pdg
)
331 int n_stat_dims
= normalize_prefix(pdg
);
332 int stat_dims
[n_stat_dims
];
334 return compute_tree(pdg
, stat_dims
, 0, 0);
337 static void free_tree(struct tree
*tree
)
339 for (int i
= 0; i
< tree
->children
.size(); ++i
)
340 free_tree(tree
->children
[i
]);
341 delete [] tree
->stat_dims
;
342 isl_set_free(tree
->domain
);
346 static void compute_bound(PDG
*pdg
, struct options
*options
)
348 struct tree
*tree
= compute_tree(pdg
);
350 struct access accesses
[pdg
->dependences
.size()];
351 for (int i
= 0; i
< pdg
->dependences
.size(); ++i
) {
352 pdg::dependence
*dep
= pdg
->dependences
[i
];
353 isl_map
*rel
= dep
->relation
->get_isl_map(pdg
->get_isl_ctx());
355 accesses
[i
].write
= isl_map_domain(isl_map_copy(rel
));
356 accesses
[i
].read
= isl_map_range(rel
);
359 isl_pw_qpolynomial
*inputsize
;
360 inputsize
= compute_input_size(pdg
, options
);
362 isl_pw_qpolynomial_fold
*pwf
;
363 pwf
= compute_bound(pdg
, inputsize
, tree
, accesses
, options
);
365 isl_set
*context
= pdg
->get_context_isl_set();
366 pwf
= isl_pw_qpolynomial_fold_gist(pwf
, context
);
368 isl_printer
*printer
;
369 printer
= isl_printer_to_file(pdg
->get_isl_ctx(), stdout
);
370 printer
= isl_printer_set_output_format(printer
, ISL_FORMAT_C
);
371 printer
= isl_printer_print_pw_qpolynomial_fold(printer
, pwf
);
372 printer
= isl_printer_end_line(printer
);
373 isl_printer_free(printer
);
375 isl_pw_qpolynomial_fold_free(pwf
);
377 for (int i
= 0; i
< pdg
->dependences
.size(); ++i
) {
378 isl_set_free(accesses
[i
].write
);
379 isl_set_free(accesses
[i
].read
);
383 int main(int argc
, char * argv
[])
386 isl_ctx
*ctx
= isl_ctx_alloc();
387 struct options
*options
= options_new_with_defaults();
389 argc
= options_parse(options
, argc
, argv
, ISL_ARG_ALL
);
392 pdg
= PDG::Load(stdin
, ctx
);
393 int nparam
= pdg
->params
.size();
395 for (int i
= 0; i
< pdg
->arrays
.size(); ++i
)
396 find_deps(pdg
, pdg
->arrays
[i
], data_reuse
);
398 compute_bound(pdg
, options
);
402 options_free(options
);