1*5971e316Smrg /* Copyright 2016-2017 Tobias Grosser
2*5971e316Smrg *
3*5971e316Smrg * Use of this software is governed by the MIT license
4*5971e316Smrg *
5*5971e316Smrg * Written by Tobias Grosser, Weststrasse 47, CH-8003, Zurich
6*5971e316Smrg */
7*5971e316Smrg
8*5971e316Smrg #ifndef IS_TRUE
9*5971e316Smrg #define IS_TRUE(b) (b)
10*5971e316Smrg #endif
11*5971e316Smrg #ifndef SIZE_VAL
12*5971e316Smrg #define SIZE_VAL(s) (s)
13*5971e316Smrg #endif
14*5971e316Smrg
15*5971e316Smrg /* Test the pointer interface for interaction between isl C and C++ types.
16*5971e316Smrg *
17*5971e316Smrg * This tests:
18*5971e316Smrg * - construction from an isl C object
19*5971e316Smrg * - check that constructed objects are non-null
20*5971e316Smrg * - get a non-owned C pointer from an isl C++ object usable in __isl_keep
21*5971e316Smrg * methods
22*5971e316Smrg * - use copy to get an owned C pointer from an isl C++ object which is usable
23*5971e316Smrg * in __isl_take methods. Verify that the original C++ object retains a valid
24*5971e316Smrg * pointer.
25*5971e316Smrg * - use release to get an owned C pointer from an isl C++ object which is
26*5971e316Smrg * usable in __isl_take methods. Verify that the original C++ object gave up
27*5971e316Smrg * its pointer and now is null.
28*5971e316Smrg */
test_pointer(isl::ctx ctx)29*5971e316Smrg void test_pointer(isl::ctx ctx)
30*5971e316Smrg {
31*5971e316Smrg isl_set *c_empty = isl_set_read_from_str(ctx.get(), "{ : false }");
32*5971e316Smrg isl::set empty = isl::manage(c_empty);
33*5971e316Smrg assert(IS_TRUE(empty.is_empty()));
34*5971e316Smrg assert(isl_set_is_empty(empty.get()));
35*5971e316Smrg
36*5971e316Smrg assert(!empty.is_null());
37*5971e316Smrg isl_set_free(empty.copy());
38*5971e316Smrg assert(!empty.is_null());
39*5971e316Smrg isl_set_free(empty.release());
40*5971e316Smrg assert(empty.is_null());
41*5971e316Smrg }
42*5971e316Smrg
43*5971e316Smrg /* Test that isl objects can be constructed.
44*5971e316Smrg *
45*5971e316Smrg * This tests:
46*5971e316Smrg * - construction of a null object
47*5971e316Smrg * - construction from a string
48*5971e316Smrg * - construction from an integer
49*5971e316Smrg * - static constructor without a parameter
50*5971e316Smrg * - conversion construction (implicit)
51*5971e316Smrg * - conversion construction (explicit)
52*5971e316Smrg * - construction of empty union set
53*5971e316Smrg *
54*5971e316Smrg * The tests to construct from integers and strings cover functionality that
55*5971e316Smrg * is also tested in the parameter type tests, but here we verify that
56*5971e316Smrg * multiple overloaded constructors are available and that overload resolution
57*5971e316Smrg * works as expected.
58*5971e316Smrg *
59*5971e316Smrg * Construction from an isl C pointer is tested in test_pointer.
60*5971e316Smrg */
test_constructors(isl::ctx ctx)61*5971e316Smrg void test_constructors(isl::ctx ctx)
62*5971e316Smrg {
63*5971e316Smrg isl::val null;
64*5971e316Smrg assert(null.is_null());
65*5971e316Smrg
66*5971e316Smrg isl::val zero_from_str = isl::val(ctx, "0");
67*5971e316Smrg assert(IS_TRUE(zero_from_str.is_zero()));
68*5971e316Smrg
69*5971e316Smrg isl::val zero_int_con = isl::val(ctx, 0);
70*5971e316Smrg assert(IS_TRUE(zero_int_con.is_zero()));
71*5971e316Smrg
72*5971e316Smrg isl::val zero_static_con = isl::val::zero(ctx);
73*5971e316Smrg assert(IS_TRUE(zero_static_con.is_zero()));
74*5971e316Smrg
75*5971e316Smrg isl::basic_set bs(ctx, "{ [1] }");
76*5971e316Smrg isl::set result(ctx, "{ [1] }");
77*5971e316Smrg isl::set s = bs;
78*5971e316Smrg assert(IS_TRUE(s.is_equal(result)));
79*5971e316Smrg isl::set s2(bs);
80*5971e316Smrg assert(IS_TRUE(s.unite(s2).is_equal(result)));
81*5971e316Smrg
82*5971e316Smrg isl::union_set us(ctx, "{ A[1]; B[2, 3] }");
83*5971e316Smrg isl::union_set empty = isl::union_set::empty(ctx);
84*5971e316Smrg assert(IS_TRUE(us.is_equal(us.unite(empty))));
85*5971e316Smrg }
86*5971e316Smrg
87*5971e316Smrg /* Test integer function parameters.
88*5971e316Smrg *
89*5971e316Smrg * Verify that extreme values and zero work.
90*5971e316Smrg */
test_parameters_int(isl::ctx ctx)91*5971e316Smrg void test_parameters_int(isl::ctx ctx)
92*5971e316Smrg {
93*5971e316Smrg isl::val long_max_str(ctx, std::to_string(LONG_MAX));
94*5971e316Smrg isl::val long_max_int(ctx, LONG_MAX);
95*5971e316Smrg assert(IS_TRUE(long_max_str.eq(long_max_int)));
96*5971e316Smrg
97*5971e316Smrg isl::val long_min_str(ctx, std::to_string(LONG_MIN));
98*5971e316Smrg isl::val long_min_int(ctx, LONG_MIN);
99*5971e316Smrg assert(IS_TRUE(long_min_str.eq(long_min_int)));
100*5971e316Smrg
101*5971e316Smrg isl::val long_zero_str = isl::val(ctx, std::to_string(0));
102*5971e316Smrg isl::val long_zero_int = isl::val(ctx, 0);
103*5971e316Smrg assert(IS_TRUE(long_zero_str.eq(long_zero_int)));
104*5971e316Smrg }
105*5971e316Smrg
106*5971e316Smrg /* Test isl objects parameters.
107*5971e316Smrg *
108*5971e316Smrg * Verify that isl objects can be passed as lvalue and rvalue parameters.
109*5971e316Smrg * Also verify that isl object parameters are automatically type converted if
110*5971e316Smrg * there is an inheritance relation. Finally, test function calls without
111*5971e316Smrg * any additional parameters, apart from the isl object on which
112*5971e316Smrg * the method is called.
113*5971e316Smrg */
test_parameters_obj(isl::ctx ctx)114*5971e316Smrg void test_parameters_obj(isl::ctx ctx)
115*5971e316Smrg {
116*5971e316Smrg isl::set a(ctx, "{ [0] }");
117*5971e316Smrg isl::set b(ctx, "{ [1] }");
118*5971e316Smrg isl::set c(ctx, "{ [2] }");
119*5971e316Smrg isl::set expected(ctx, "{ [i] : 0 <= i <= 2 }");
120*5971e316Smrg
121*5971e316Smrg isl::set tmp = a.unite(b);
122*5971e316Smrg isl::set res_lvalue_param = tmp.unite(c);
123*5971e316Smrg assert(IS_TRUE(res_lvalue_param.is_equal(expected)));
124*5971e316Smrg
125*5971e316Smrg isl::set res_rvalue_param = a.unite(b).unite(c);
126*5971e316Smrg assert(IS_TRUE(res_rvalue_param.is_equal(expected)));
127*5971e316Smrg
128*5971e316Smrg isl::basic_set a2(ctx, "{ [0] }");
129*5971e316Smrg assert(IS_TRUE(a.is_equal(a2)));
130*5971e316Smrg
131*5971e316Smrg isl::val two(ctx, 2);
132*5971e316Smrg isl::val half(ctx, "1/2");
133*5971e316Smrg isl::val res_only_this_param = two.inv();
134*5971e316Smrg assert(IS_TRUE(res_only_this_param.eq(half)));
135*5971e316Smrg }
136*5971e316Smrg
137*5971e316Smrg /* Test different kinds of parameters to be passed to functions.
138*5971e316Smrg *
139*5971e316Smrg * This includes integer and isl C++ object parameters.
140*5971e316Smrg */
test_parameters(isl::ctx ctx)141*5971e316Smrg void test_parameters(isl::ctx ctx)
142*5971e316Smrg {
143*5971e316Smrg test_parameters_int(ctx);
144*5971e316Smrg test_parameters_obj(ctx);
145*5971e316Smrg }
146*5971e316Smrg
147*5971e316Smrg /* Test that isl objects are returned correctly.
148*5971e316Smrg *
149*5971e316Smrg * This only tests that after combining two objects, the result is successfully
150*5971e316Smrg * returned.
151*5971e316Smrg */
test_return_obj(isl::ctx ctx)152*5971e316Smrg void test_return_obj(isl::ctx ctx)
153*5971e316Smrg {
154*5971e316Smrg isl::val one(ctx, "1");
155*5971e316Smrg isl::val two(ctx, "2");
156*5971e316Smrg isl::val three(ctx, "3");
157*5971e316Smrg
158*5971e316Smrg isl::val res = one.add(two);
159*5971e316Smrg
160*5971e316Smrg assert(IS_TRUE(res.eq(three)));
161*5971e316Smrg }
162*5971e316Smrg
163*5971e316Smrg /* Test that integer values are returned correctly.
164*5971e316Smrg */
test_return_int(isl::ctx ctx)165*5971e316Smrg void test_return_int(isl::ctx ctx)
166*5971e316Smrg {
167*5971e316Smrg isl::val one(ctx, "1");
168*5971e316Smrg isl::val neg_one(ctx, "-1");
169*5971e316Smrg isl::val zero(ctx, "0");
170*5971e316Smrg
171*5971e316Smrg assert(one.sgn() > 0);
172*5971e316Smrg assert(neg_one.sgn() < 0);
173*5971e316Smrg assert(zero.sgn() == 0);
174*5971e316Smrg }
175*5971e316Smrg
176*5971e316Smrg /* Test that strings are returned correctly.
177*5971e316Smrg * Do so by calling overloaded isl::ast_build::from_expr methods.
178*5971e316Smrg */
test_return_string(isl::ctx ctx)179*5971e316Smrg void test_return_string(isl::ctx ctx)
180*5971e316Smrg {
181*5971e316Smrg isl::set context(ctx, "[n] -> { : }");
182*5971e316Smrg isl::ast_build build = isl::ast_build::from_context(context);
183*5971e316Smrg isl::pw_aff pw_aff(ctx, "[n] -> { [n] }");
184*5971e316Smrg isl::set set(ctx, "[n] -> { : n >= 0 }");
185*5971e316Smrg
186*5971e316Smrg isl::ast_expr expr = build.expr_from(pw_aff);
187*5971e316Smrg const char *expected_string = "n";
188*5971e316Smrg assert(expected_string == expr.to_C_str());
189*5971e316Smrg
190*5971e316Smrg expr = build.expr_from(set);
191*5971e316Smrg expected_string = "n >= 0";
192*5971e316Smrg assert(expected_string == expr.to_C_str());
193*5971e316Smrg }
194*5971e316Smrg
195*5971e316Smrg /* Test the functionality of "every" functions
196*5971e316Smrg * that does not depend on the type of C++ bindings.
197*5971e316Smrg */
test_every_generic(isl::ctx ctx)198*5971e316Smrg static void test_every_generic(isl::ctx ctx)
199*5971e316Smrg {
200*5971e316Smrg isl::union_set us(ctx, "{ A[i]; B[j] }");
201*5971e316Smrg
202*5971e316Smrg auto is_empty = [] (isl::set s) {
203*5971e316Smrg return s.is_empty();
204*5971e316Smrg };
205*5971e316Smrg assert(!IS_TRUE(us.every_set(is_empty)));
206*5971e316Smrg
207*5971e316Smrg auto is_non_empty = [] (isl::set s) {
208*5971e316Smrg return !s.is_empty();
209*5971e316Smrg };
210*5971e316Smrg assert(IS_TRUE(us.every_set(is_non_empty)));
211*5971e316Smrg
212*5971e316Smrg auto in_A = [] (isl::set s) {
213*5971e316Smrg return s.is_subset(isl::set(s.ctx(), "{ A[x] }"));
214*5971e316Smrg };
215*5971e316Smrg assert(!IS_TRUE(us.every_set(in_A)));
216*5971e316Smrg
217*5971e316Smrg auto not_in_A = [] (isl::set s) {
218*5971e316Smrg return !s.is_subset(isl::set(s.ctx(), "{ A[x] }"));
219*5971e316Smrg };
220*5971e316Smrg assert(!IS_TRUE(us.every_set(not_in_A)));
221*5971e316Smrg }
222*5971e316Smrg
223*5971e316Smrg /* Check basic construction of spaces.
224*5971e316Smrg */
test_space(isl::ctx ctx)225*5971e316Smrg static void test_space(isl::ctx ctx)
226*5971e316Smrg {
227*5971e316Smrg isl::space unit = isl::space::unit(ctx);
228*5971e316Smrg isl::space set_space = unit.add_named_tuple("A", 3);
229*5971e316Smrg isl::space map_space = set_space.add_named_tuple("B", 2);
230*5971e316Smrg
231*5971e316Smrg isl::set set = isl::set::universe(set_space);
232*5971e316Smrg isl::map map = isl::map::universe(map_space);
233*5971e316Smrg assert(IS_TRUE(set.is_equal(isl::set(ctx, "{ A[*,*,*] }"))));
234*5971e316Smrg assert(IS_TRUE(map.is_equal(isl::map(ctx, "{ A[*,*,*] -> B[*,*] }"))));
235*5971e316Smrg }
236*5971e316Smrg
237*5971e316Smrg /* Construct a simple schedule tree with an outer sequence node and
238*5971e316Smrg * a single-dimensional band node in each branch, with one of them
239*5971e316Smrg * marked coincident.
240*5971e316Smrg */
construct_schedule_tree(isl::ctx ctx)241*5971e316Smrg static isl::schedule construct_schedule_tree(isl::ctx ctx)
242*5971e316Smrg {
243*5971e316Smrg isl::union_set A(ctx, "{ A[i] : 0 <= i < 10 }");
244*5971e316Smrg isl::union_set B(ctx, "{ B[i] : 0 <= i < 20 }");
245*5971e316Smrg
246*5971e316Smrg auto node = isl::schedule_node::from_domain(A.unite(B));
247*5971e316Smrg node = node.child(0);
248*5971e316Smrg
249*5971e316Smrg isl::union_set_list filters(ctx, 0);
250*5971e316Smrg filters = filters.add(A).add(B);
251*5971e316Smrg node = node.insert_sequence(filters);
252*5971e316Smrg
253*5971e316Smrg isl::multi_union_pw_aff f_A(ctx, "[ { A[i] -> [i] } ]");
254*5971e316Smrg node = node.child(0);
255*5971e316Smrg node = node.child(0);
256*5971e316Smrg node = node.insert_partial_schedule(f_A);
257*5971e316Smrg auto band = node.as<isl::schedule_node_band>();
258*5971e316Smrg band = band.member_set_coincident(0, true);
259*5971e316Smrg node = band.ancestor(2);
260*5971e316Smrg
261*5971e316Smrg isl::multi_union_pw_aff f_B(ctx, "[ { B[i] -> [i] } ]");
262*5971e316Smrg node = node.child(1);
263*5971e316Smrg node = node.child(0);
264*5971e316Smrg node = node.insert_partial_schedule(f_B);
265*5971e316Smrg node = node.ancestor(2);
266*5971e316Smrg
267*5971e316Smrg return node.schedule();
268*5971e316Smrg }
269*5971e316Smrg
270*5971e316Smrg /* Test basic schedule tree functionality that is independent
271*5971e316Smrg * of the type of bindings.
272*5971e316Smrg *
273*5971e316Smrg * In particular, create a simple schedule tree and
274*5971e316Smrg * - check that the root node is a domain node
275*5971e316Smrg * - check that an object of a subclass can be used as one of the superclass
276*5971e316Smrg * - test map_descendant_bottom_up in the successful case
277*5971e316Smrg */
test_schedule_tree_generic(isl::ctx ctx)278*5971e316Smrg static isl::schedule_node test_schedule_tree_generic(isl::ctx ctx)
279*5971e316Smrg {
280*5971e316Smrg auto schedule = construct_schedule_tree(ctx);
281*5971e316Smrg auto root = schedule.root();
282*5971e316Smrg
283*5971e316Smrg assert(IS_TRUE(root.isa<isl::schedule_node_domain>()));
284*5971e316Smrg root = root.as<isl::schedule_node_domain>().child(0).parent();
285*5971e316Smrg
286*5971e316Smrg int count = 0;
287*5971e316Smrg auto inc_count = [&count](isl::schedule_node node) {
288*5971e316Smrg count++;
289*5971e316Smrg return node;
290*5971e316Smrg };
291*5971e316Smrg root = root.map_descendant_bottom_up(inc_count);
292*5971e316Smrg assert(count == 8);
293*5971e316Smrg
294*5971e316Smrg return root;
295*5971e316Smrg }
296*5971e316Smrg
297*5971e316Smrg /* Test marking band members for unrolling.
298*5971e316Smrg * "schedule" is the schedule created by construct_schedule_tree.
299*5971e316Smrg * It schedules two statements, with 10 and 20 instances, respectively.
300*5971e316Smrg * Unrolling all band members therefore results in 30 at-domain calls
301*5971e316Smrg * by the AST generator.
302*5971e316Smrg */
test_ast_build_unroll(isl::schedule schedule)303*5971e316Smrg static void test_ast_build_unroll(isl::schedule schedule)
304*5971e316Smrg {
305*5971e316Smrg auto root = schedule.root();
306*5971e316Smrg auto mark_unroll = [](isl::schedule_node node) {
307*5971e316Smrg if (IS_TRUE(node.isa<isl::schedule_node_band>())) {
308*5971e316Smrg auto band = node.as<isl::schedule_node_band>();
309*5971e316Smrg node = band.member_set_ast_loop_unroll(0);
310*5971e316Smrg }
311*5971e316Smrg return node;
312*5971e316Smrg };
313*5971e316Smrg root = root.map_descendant_bottom_up(mark_unroll);
314*5971e316Smrg schedule = root.schedule();
315*5971e316Smrg
316*5971e316Smrg int count_ast = 0;
317*5971e316Smrg auto inc_count_ast =
318*5971e316Smrg [&count_ast](isl::ast_node node, isl::ast_build build) {
319*5971e316Smrg count_ast++;
320*5971e316Smrg return node;
321*5971e316Smrg };
322*5971e316Smrg auto build = isl::ast_build(schedule.ctx());
323*5971e316Smrg build = build.set_at_each_domain(inc_count_ast);
324*5971e316Smrg auto ast = build.node_from(schedule);
325*5971e316Smrg assert(count_ast == 30);
326*5971e316Smrg }
327*5971e316Smrg
328*5971e316Smrg /* Test basic AST generation from a schedule tree that is independent
329*5971e316Smrg * of the type of bindings.
330*5971e316Smrg *
331*5971e316Smrg * In particular, create a simple schedule tree and
332*5971e316Smrg * - generate an AST from the schedule tree
333*5971e316Smrg * - test at_each_domain in the successful case
334*5971e316Smrg * - test unrolling
335*5971e316Smrg */
test_ast_build_generic(isl::ctx ctx)336*5971e316Smrg static isl::schedule test_ast_build_generic(isl::ctx ctx)
337*5971e316Smrg {
338*5971e316Smrg auto schedule = construct_schedule_tree(ctx);
339*5971e316Smrg
340*5971e316Smrg int count_ast = 0;
341*5971e316Smrg auto inc_count_ast =
342*5971e316Smrg [&count_ast](isl::ast_node node, isl::ast_build build) {
343*5971e316Smrg count_ast++;
344*5971e316Smrg return node;
345*5971e316Smrg };
346*5971e316Smrg auto build = isl::ast_build(ctx);
347*5971e316Smrg auto build_copy = build.set_at_each_domain(inc_count_ast);
348*5971e316Smrg auto ast = build.node_from(schedule);
349*5971e316Smrg assert(count_ast == 0);
350*5971e316Smrg count_ast = 0;
351*5971e316Smrg ast = build_copy.node_from(schedule);
352*5971e316Smrg assert(count_ast == 2);
353*5971e316Smrg build = build_copy;
354*5971e316Smrg count_ast = 0;
355*5971e316Smrg ast = build.node_from(schedule);
356*5971e316Smrg assert(count_ast == 2);
357*5971e316Smrg
358*5971e316Smrg test_ast_build_unroll(schedule);
359*5971e316Smrg
360*5971e316Smrg return schedule;
361*5971e316Smrg }
362*5971e316Smrg
363*5971e316Smrg /* Test basic AST expression generation from an affine expression.
364*5971e316Smrg */
test_ast_build_expr(isl::ctx ctx)365*5971e316Smrg static void test_ast_build_expr(isl::ctx ctx)
366*5971e316Smrg {
367*5971e316Smrg isl::pw_aff pa(ctx, "[n] -> { [n + 1] }");
368*5971e316Smrg isl::ast_build build = isl::ast_build::from_context(pa.domain());
369*5971e316Smrg
370*5971e316Smrg auto expr = build.expr_from(pa);
371*5971e316Smrg auto op = expr.as<isl::ast_expr_op>();
372*5971e316Smrg assert(IS_TRUE(op.isa<isl::ast_expr_op_add>()));
373*5971e316Smrg assert(SIZE_VAL(op.n_arg()) == 2);
374*5971e316Smrg }
375