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

source code of polly/lib/External/isl/isl_test_cpp-generic.cc