4 #include <isl/constraint.h>
5 #include <isl/polynomial.h>
6 #include <barvinok/isl.h>
10 #include "translation.h"
11 #include "mem_options.h"
20 /* Compute the number of array elements that are read but not
21 * (previously) written. These are assumed to be the input.
23 static __isl_give isl_pw_qpolynomial
*compute_input_size(PDG
*pdg
,
24 struct options
*options
)
26 unsigned nparam
= pdg
->params
.size();
28 isl_pw_qpolynomial
*inputsize
;
30 dim
= isl_space_set_alloc(pdg
->get_isl_ctx(), nparam
, 0);
31 isl_dim_set_parameter_names(dim
, pdg
->params
);
32 inputsize
= isl_pw_qpolynomial_zero(dim
);
34 if (!options
->with_input
)
37 for (int i
= 0; i
< pdg
->dependences
.size(); ++i
) {
39 isl_pw_qpolynomial
*size
;
40 pdg::dependence
*dep
= pdg
->dependences
[i
];
42 if (dep
->type
!= pdg::dependence::uninitialized
)
45 map
= dep
->relation
->get_isl_map(pdg
->get_isl_ctx());
46 size
= isl_map_card(map
);
47 inputsize
= isl_pw_qpolynomial_add(inputsize
, size
);
53 /* Compute the number of elements in domain for a fixed value
54 * of the "fixed_loops" outer loop iterators and return this value
55 * as a function of these loop iterators and the parameters.
57 static __isl_give isl_pw_qpolynomial
*compute_accesses_at(
58 __isl_take isl_set
*domain
, int fixed_loops
)
61 map
= isl_map_from_range(domain
);
62 map
= isl_map_move_dims(map
, isl_dim_in
, 0, isl_dim_out
, 0, fixed_loops
);
63 return isl_map_card(map
);
66 static __isl_give isl_map
*less_than(__isl_take isl_space
*dim
,
67 enum isl_dim_type type1
, unsigned pos1
,
68 enum isl_dim_type type2
, unsigned pos2
)
71 struct isl_constraint
*c
;
72 struct isl_basic_map
*bmap
;
76 bmap
= isl_basic_map_universe(isl_space_copy(dim
));
77 c
= isl_inequality_alloc(isl_local_space_from_space(dim
));
79 isl_constraint_set_coefficient(c
, type2
, pos2
, v
);
80 isl_int_set_si(v
, -1);
81 isl_constraint_set_coefficient(c
, type1
, pos1
, v
);
82 isl_constraint_set_constant(c
, v
);
83 bmap
= isl_basic_map_add_constraint(bmap
, c
);
87 return isl_map_from_basic_map(bmap
);
90 /* Compute the number of elements in domain for a fixed value
91 * of the "level" outer loop iterators and for all values of the
92 * loop iterator at level "level" smaller than a fixed value
93 * and return this value as a function of these (level+1) loop iterators
96 static __isl_give isl_pw_qpolynomial
*compute_accesses_before(
97 __isl_take isl_set
*domain
, int level
)
100 map
= isl_map_from_range(domain
);
101 map
= isl_map_move_dims(map
, isl_dim_in
, 0, isl_dim_out
, 0, level
);
102 map
= isl_map_add_dims(map
, isl_dim_in
, 1);
103 map
= isl_map_intersect(map
,
104 less_than(isl_map_get_space(map
), isl_dim_out
, 0,
106 return isl_map_card(map
);
109 static int cmp_prefix_stat_dims(pdg::node
*node
, int *stat_dims
, int d
)
111 for (int j
= 0; j
< d
; ++j
)
112 if (node
->prefix
[2*j
] != stat_dims
[j
])
113 return node
->prefix
[2*j
] - stat_dims
[j
];
119 * Returns true if dependence is independent of first n_loops loops.
121 static int is_loop_independent(isl_ctx
*ctx
,
122 pdg::IslMap
*relation
, int n_loops
)
126 assert(relation
->input() >= n_loops
);
127 assert(relation
->output() >= n_loops
);
130 rel
= relation
->get_isl_map(ctx
);
131 test
= isl_map_universe(isl_map_get_space(rel
));
132 for (int i
= 0; i
< n_loops
; ++i
)
133 test
= isl_map_equate(test
, isl_dim_in
, i
, isl_dim_out
, i
);
134 indep
= isl_map_is_subset(rel
, test
);
141 struct contribution
{
142 unsigned is_read
: 1;
143 unsigned is_written
: 1;
147 * Determines the net contribution of "dep" within statements
148 * with statement level dimensions prefixed by stat_dims
149 * and within a fixed iteration of the first n_loop loops.
151 static struct contribution
net_contribution(isl_ctx
*ctx
, pdg::dependence
*dep
,
152 int *stat_dims
, int d
, int n_loop
,
153 struct options
*options
)
155 struct contribution c
;
159 if (dep
->type
== pdg::dependence::uninitialized
) {
160 if (options
->with_input
&&
161 cmp_prefix_stat_dims(dep
->to
, stat_dims
, d
) == 0)
164 int is_written
= cmp_prefix_stat_dims(dep
->from
, stat_dims
, d
) == 0;
165 int is_read
= cmp_prefix_stat_dims(dep
->to
, stat_dims
, d
) == 0;
166 int is_local
= is_written
&& is_read
&&
167 is_loop_independent(ctx
, dep
->relation
, n_loop
);
170 c
.is_written
= is_written
;
183 * Compute increment in statement/loop identified by stat_dims
185 static __isl_give isl_pw_qpolynomial
*compute_live_increment(PDG
*pdg
,
186 int *stat_dims
, int d
, struct access
*accesses
, struct options
*options
)
188 unsigned nparam
= pdg
->params
.size();
190 isl_pw_qpolynomial
*sum
;
192 dim
= isl_space_set_alloc(pdg
->get_isl_ctx(), nparam
, d
- 1);
193 isl_dim_set_parameter_names(dim
, pdg
->params
);
194 sum
= isl_pw_qpolynomial_zero(dim
);
195 for (int i
= 0; i
< pdg
->dependences
.size(); ++i
) {
196 pdg::dependence
*dep
= pdg
->dependences
[i
];
197 struct contribution c
;
199 c
= net_contribution(pdg
->get_isl_ctx(),
200 dep
, stat_dims
, d
, d
-1, options
);
203 isl_pw_qpolynomial
*inc
;
204 inc
= compute_accesses_at(isl_set_copy(accesses
[i
].write
), d
- 1);
205 sum
= isl_pw_qpolynomial_add(sum
, inc
);
208 isl_pw_qpolynomial
*dec
;
209 dec
= compute_accesses_at(isl_set_copy(accesses
[i
].read
), d
- 1);
210 sum
= isl_pw_qpolynomial_sub(sum
, dec
);
217 * Compute increment in previous iterations of loop at given level.
219 static __isl_give isl_pw_qpolynomial
*compute_live_increment_in_loop(PDG
*pdg
,
220 int *stat_dims
, int level
, struct access
*accesses
,
221 struct options
*options
)
223 unsigned nparam
= pdg
->params
.size();
225 isl_pw_qpolynomial
*sum
;
227 dim
= isl_space_set_alloc(pdg
->get_isl_ctx(), nparam
, level
+ 1);
228 isl_dim_set_parameter_names(dim
, pdg
->params
);
229 sum
= isl_pw_qpolynomial_zero(dim
);
230 for (int i
= 0; i
< pdg
->dependences
.size(); ++i
) {
231 pdg::dependence
*dep
= pdg
->dependences
[i
];
232 struct contribution c
;
234 c
= net_contribution(pdg
->get_isl_ctx(),
235 dep
, stat_dims
, level
+1, level
+1, options
);
238 isl_pw_qpolynomial
*inc
;
239 inc
= compute_accesses_before(isl_set_copy(accesses
[i
].write
), level
);
240 sum
= isl_pw_qpolynomial_add(sum
, inc
);
243 isl_pw_qpolynomial
*dec
;
244 dec
= compute_accesses_before(isl_set_copy(accesses
[i
].read
), level
);
245 sum
= isl_pw_qpolynomial_sub(sum
, dec
);
256 vector
<struct tree
*> children
;
261 * Compute bound on number of live array elements in the
264 * live_before: number of live elements before the loop/statement
265 * in terms of the outer loop iterators
267 static __isl_give isl_pw_qpolynomial_fold
*compute_bound(PDG
*pdg
,
268 __isl_take isl_pw_qpolynomial
*live
,
270 struct access
*accesses
,
271 struct options
*options
)
273 /* If we are in a leaf, we actually compute the bound. */
274 if (tree
->children
.size() == 0) {
276 isl_pw_qpolynomial_fold
*bound
;
278 domain
= isl_set_copy(tree
->domain
);
279 live
= isl_pw_qpolynomial_intersect_domain(live
, domain
);
280 bound
= isl_pw_qpolynomial_bound(live
, isl_fold_max
, NULL
);
285 isl_pw_qpolynomial_fold
*pwf
;
287 /* If we are not in the outer dummy loop, add contribution of
288 * previous iterations.
292 isl_pw_qpolynomial
*inc
;
294 live
= isl_pw_qpolynomial_add_dims(live
, isl_dim_set
, 1);
295 inc
= compute_live_increment_in_loop(pdg
, tree
->stat_dims
, tree
->d
-1,
297 live
= isl_pw_qpolynomial_add(live
, inc
);
300 pwf
= compute_bound(pdg
, isl_pw_qpolynomial_copy(live
),
301 tree
->children
[0], accesses
, options
);
302 for (int i
= 1; i
< tree
->children
.size(); ++i
) {
303 isl_pw_qpolynomial_fold
*pwf_i
;
304 isl_pw_qpolynomial
*inc
;
305 struct tree
*child
= tree
->children
[i
-1];
306 inc
= compute_live_increment(pdg
, child
->stat_dims
, child
->d
,
308 live
= isl_pw_qpolynomial_add(live
, inc
);
309 pwf_i
= compute_bound(pdg
, isl_pw_qpolynomial_copy(live
),
310 tree
->children
[i
], accesses
, options
);
311 pwf
= isl_pw_qpolynomial_fold_fold(pwf
, pwf_i
);
313 isl_pw_qpolynomial_free(live
);
318 * Construct a tree for all statements whose statement dimensions
319 * start with the d first elements of stat_dims.
320 * The first one of those statemens is statement n.
322 static struct tree
*compute_tree(PDG
*pdg
, int *stat_dims
, int d
, int n
)
324 struct tree
*tree
= new struct tree
;
327 tree
->stat_dims
= new int[d
];
328 for (int i
= 0; i
< d
; ++i
)
329 tree
->stat_dims
[i
] = stat_dims
[i
];
331 if (pdg
->nodes
[n
]->prefix
.size() == 2*d
-1) {
332 tree
->domain
= pdg
->nodes
[n
]->source
->get_isl_set(pdg
->get_isl_ctx());
336 for (int i
= n
; i
< pdg
->nodes
.size(); ++i
) {
337 if (cmp_prefix_stat_dims(pdg
->nodes
[i
], stat_dims
, d
) > 0)
340 stat_dims
[d
] = pdg
->nodes
[i
]->prefix
[2*d
];
342 struct tree
*child
= compute_tree(pdg
, stat_dims
, d
+1, i
);
343 tree
->children
.push_back(child
);
345 /* Skip over nodes with the same prefix at current level */
346 for (; i
+1 < pdg
->nodes
.size(); ++i
)
347 if (cmp_prefix_stat_dims(pdg
->nodes
[i
+1], stat_dims
, d
+1) != 0)
353 static struct tree
*compute_tree(PDG
*pdg
)
355 int n_stat_dims
= normalize_prefix(pdg
);
356 int stat_dims
[n_stat_dims
];
358 return compute_tree(pdg
, stat_dims
, 0, 0);
361 static void free_tree(struct tree
*tree
)
363 for (int i
= 0; i
< tree
->children
.size(); ++i
)
364 free_tree(tree
->children
[i
]);
365 delete [] tree
->stat_dims
;
366 isl_set_free(tree
->domain
);
370 static void compute_bound(PDG
*pdg
, struct options
*options
)
372 struct tree
*tree
= compute_tree(pdg
);
374 struct access accesses
[pdg
->dependences
.size()];
375 for (int i
= 0; i
< pdg
->dependences
.size(); ++i
) {
376 pdg::dependence
*dep
= pdg
->dependences
[i
];
377 isl_map
*rel
= dep
->relation
->get_isl_map(pdg
->get_isl_ctx());
379 accesses
[i
].write
= isl_map_domain(isl_map_copy(rel
));
380 accesses
[i
].read
= isl_map_range(rel
);
383 isl_pw_qpolynomial
*inputsize
;
384 inputsize
= compute_input_size(pdg
, options
);
386 isl_pw_qpolynomial_fold
*pwf
;
387 pwf
= compute_bound(pdg
, inputsize
, tree
, accesses
, options
);
389 isl_set
*context
= pdg
->get_context_isl_set();
390 pwf
= isl_pw_qpolynomial_fold_gist(pwf
, context
);
392 isl_printer
*printer
;
393 printer
= isl_printer_to_file(pdg
->get_isl_ctx(), stdout
);
394 printer
= isl_printer_set_output_format(printer
, ISL_FORMAT_C
);
395 printer
= isl_printer_print_pw_qpolynomial_fold(printer
, pwf
);
396 printer
= isl_printer_end_line(printer
);
397 isl_printer_free(printer
);
399 isl_pw_qpolynomial_fold_free(pwf
);
401 for (int i
= 0; i
< pdg
->dependences
.size(); ++i
) {
402 isl_set_free(accesses
[i
].write
);
403 isl_set_free(accesses
[i
].read
);
407 int main(int argc
, char * argv
[])
410 isl_ctx
*ctx
= isl_ctx_alloc();
411 struct options
*options
= options_new_with_defaults();
413 argc
= options_parse(options
, argc
, argv
, ISL_ARG_ALL
);
416 pdg
= PDG::Load(stdin
, ctx
);
417 int nparam
= pdg
->params
.size();
419 for (int i
= 0; i
< pdg
->arrays
.size(); ++i
)
420 find_deps(pdg
, pdg
->arrays
[i
], data_reuse
);
422 compute_bound(pdg
, options
);
426 options_free(options
);