375 lines · plain
1/* Copyright 2016-2017 Tobias Grosser2 *3 * Use of this software is governed by the MIT license4 *5 * Written by Tobias Grosser, Weststrasse 47, CH-8003, Zurich6 */7 8#ifndef IS_TRUE9#define IS_TRUE(b) (b)10#endif11#ifndef SIZE_VAL12#define SIZE_VAL(s) (s)13#endif14 15/* Test the pointer interface for interaction between isl C and C++ types.16 *17 * This tests:18 * - construction from an isl C object19 * - check that constructed objects are non-null20 * - get a non-owned C pointer from an isl C++ object usable in __isl_keep21 * methods22 * - use copy to get an owned C pointer from an isl C++ object which is usable23 * in __isl_take methods. Verify that the original C++ object retains a valid24 * pointer.25 * - use release to get an owned C pointer from an isl C++ object which is26 * usable in __isl_take methods. Verify that the original C++ object gave up27 * 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 object47 * - construction from a string48 * - construction from an integer49 * - static constructor without a parameter50 * - conversion construction (implicit)51 * - conversion construction (explicit)52 * - construction of empty union set53 *54 * The tests to construct from integers and strings cover functionality that55 * is also tested in the parameter type tests, but here we verify that56 * multiple overloaded constructors are available and that overload resolution57 * 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 if110 * there is an inheritance relation. Finally, test function calls without111 * any additional parameters, apart from the isl object on which112 * 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 successfully150 * 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" functions196 * 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 and238 * a single-dimensional band node in each branch, with one of them239 * 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 independent271 * of the type of bindings.272 *273 * In particular, create a simple schedule tree and274 * - check that the root node is a domain node275 * - check that an object of a subclass can be used as one of the superclass276 * - test map_descendant_bottom_up in the successful case277 */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 calls301 * 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 independent329 * of the type of bindings.330 *331 * In particular, create a simple schedule tree and332 * - generate an AST from the schedule tree333 * - test at_each_domain in the successful case334 * - test unrolling335 */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