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 | #include <vector> |
9 | #include <string> |
10 | #include <limits.h> |
11 | #include <stdio.h> |
12 | #include <stdlib.h> |
13 | |
14 | #include <isl/options.h> |
15 | #include <isl/cpp-checked.h> |
16 | |
17 | namespace isl { using namespace checked; } |
18 | |
19 | static void assert_impl(bool condition, const char *file, int line, |
20 | const char *message) |
21 | { |
22 | if (condition) |
23 | return; |
24 | |
25 | fprintf(stderr, format: "Assertion failed in %s:%d %s\n" , file, line, message); |
26 | exit(EXIT_FAILURE); |
27 | } |
28 | |
29 | static void assert_impl(isl::boolean condition, const char *file, int line, |
30 | const char *message) |
31 | { |
32 | assert_impl(condition: bool(condition), file, line, message); |
33 | } |
34 | |
35 | /* Return the value encapsulated by "s". |
36 | */ |
37 | static int size_val(isl::size s) |
38 | { |
39 | return s.is_error() ? -1 : unsigned(s); |
40 | } |
41 | |
42 | #undef assert |
43 | #define assert(exp) assert_impl(exp, __FILE__, __LINE__, #exp) |
44 | #define IS_TRUE(b) (b).is_true() |
45 | #define SIZE_VAL(s) size_val(s) |
46 | |
47 | #include "isl_test_cpp-generic.cc" |
48 | |
49 | /* Test that isl_bool values are returned correctly. |
50 | * |
51 | * We check in detail the following parts of the isl::boolean class: |
52 | * - The is_true, is_false, and is_error functions return true in case they |
53 | * are called on a true, false, or error instance of isl::boolean, |
54 | * respectively |
55 | * - Explicit conversion to 'bool' |
56 | * - Implicit conversion to 'bool' |
57 | * - The complement operator |
58 | * - Explicit construction from 'true' and 'false' |
59 | * - Explicit construction form isl_bool |
60 | */ |
61 | void test_return_bool(isl::ctx ctx) |
62 | { |
63 | isl::set empty(ctx, "{ : false }" ); |
64 | isl::set univ(ctx, "{ : }" ); |
65 | isl::set null; |
66 | |
67 | isl::boolean b_true = empty.is_empty(); |
68 | isl::boolean b_false = univ.is_empty(); |
69 | isl::boolean b_error = null.is_empty(); |
70 | |
71 | assert(b_true.is_true()); |
72 | assert(!b_true.is_false()); |
73 | assert(!b_true.is_error()); |
74 | |
75 | assert(!b_false.is_true()); |
76 | assert(b_false.is_false()); |
77 | assert(!b_false.is_error()); |
78 | |
79 | assert(!b_error.is_true()); |
80 | assert(!b_error.is_false()); |
81 | assert(b_error.is_error()); |
82 | |
83 | assert(bool(b_true) == true); |
84 | assert(bool(b_false) == false); |
85 | |
86 | assert(b_true); |
87 | |
88 | assert((!b_false).is_true()); |
89 | assert((!b_true).is_false()); |
90 | assert((!b_error).is_error()); |
91 | |
92 | assert(isl::boolean(true).is_true()); |
93 | assert(!isl::boolean(true).is_false()); |
94 | assert(!isl::boolean(true).is_error()); |
95 | |
96 | assert(isl::boolean(false).is_false()); |
97 | assert(!isl::boolean(false).is_true()); |
98 | assert(!isl::boolean(false).is_error()); |
99 | |
100 | assert(isl::manage(isl_bool_true).is_true()); |
101 | assert(!isl::manage(isl_bool_true).is_false()); |
102 | assert(!isl::manage(isl_bool_true).is_error()); |
103 | |
104 | assert(isl::manage(isl_bool_false).is_false()); |
105 | assert(!isl::manage(isl_bool_false).is_true()); |
106 | assert(!isl::manage(isl_bool_false).is_error()); |
107 | |
108 | assert(isl::manage(isl_bool_error).is_error()); |
109 | assert(!isl::manage(isl_bool_error).is_true()); |
110 | assert(!isl::manage(isl_bool_error).is_false()); |
111 | } |
112 | |
113 | /* Test that return values are handled correctly. |
114 | * |
115 | * Test that isl C++ objects, integers, boolean values, and strings are |
116 | * returned correctly. |
117 | */ |
118 | void test_return(isl::ctx ctx) |
119 | { |
120 | test_return_obj(ctx); |
121 | test_return_int(ctx); |
122 | test_return_bool(ctx); |
123 | test_return_string(ctx); |
124 | } |
125 | |
126 | /* Test that foreach functions are modeled correctly. |
127 | * |
128 | * Verify that lambdas are correctly called as callback of a 'foreach' |
129 | * function and that variables captured by the lambda work correctly. Also |
130 | * check that the foreach function takes account of the return value of the |
131 | * lambda and aborts in case isl::stat::error is returned and then returns |
132 | * isl::stat::error itself. |
133 | */ |
134 | void test_foreach(isl::ctx ctx) |
135 | { |
136 | isl::set s(ctx, "{ [0]; [1]; [2] }" ); |
137 | |
138 | std::vector<isl::basic_set> basic_sets; |
139 | |
140 | auto add_to_vector = [&] (isl::basic_set bs) { |
141 | basic_sets.push_back(bs); |
142 | return isl::stat::ok(); |
143 | }; |
144 | |
145 | isl::stat ret1 = s.foreach_basic_set(add_to_vector); |
146 | |
147 | assert(ret1.is_ok()); |
148 | assert(basic_sets.size() == 3); |
149 | assert(isl::set(basic_sets[0]).is_subset(s).is_true()); |
150 | assert(isl::set(basic_sets[1]).is_subset(s).is_true()); |
151 | assert(isl::set(basic_sets[2]).is_subset(s).is_true()); |
152 | assert(!basic_sets[0].is_equal(basic_sets[1]).is_true()); |
153 | |
154 | auto fail = [&] (isl::basic_set bs) { |
155 | return isl::stat::error(); |
156 | }; |
157 | |
158 | isl::stat ret2 = s.foreach_basic_set(fail); |
159 | |
160 | assert(ret2.is_error()); |
161 | } |
162 | |
163 | /* Test the functionality of "every" functions. |
164 | * |
165 | * In particular, test the generic functionality and |
166 | * test that error conditions are properly propagated. |
167 | */ |
168 | static void test_every(isl::ctx ctx) |
169 | { |
170 | isl::union_set us(ctx, "{ A[i]; B[j] }" ); |
171 | |
172 | test_every_generic(ctx); |
173 | |
174 | auto fail = [] (isl::set s){ |
175 | return isl::boolean::error(); |
176 | }; |
177 | assert(us.every_set(fail).is_error()); |
178 | } |
179 | |
180 | /* Test basic schedule tree functionality. |
181 | * |
182 | * In particular, create a simple schedule tree and |
183 | * - perform some generic tests |
184 | * - test map_descendant_bottom_up in the failing case |
185 | * - test foreach_descendant_top_down |
186 | * - test every_descendant |
187 | */ |
188 | static void test_schedule_tree(isl::ctx ctx) |
189 | { |
190 | auto root = test_schedule_tree_generic(ctx); |
191 | |
192 | auto fail_map = [](isl::schedule_node node) { |
193 | return isl::schedule_node(); |
194 | }; |
195 | assert(root.map_descendant_bottom_up(fail_map).is_null()); |
196 | |
197 | int count = 0; |
198 | auto inc_count = [&count](isl::schedule_node node) { |
199 | count++; |
200 | return isl::boolean(true); |
201 | }; |
202 | assert(root.foreach_descendant_top_down(inc_count).is_ok()); |
203 | assert(count == 8); |
204 | |
205 | count = 0; |
206 | auto inc_count_once = [&count](isl::schedule_node node) { |
207 | count++; |
208 | return isl::boolean(false); |
209 | }; |
210 | assert(root.foreach_descendant_top_down(inc_count_once).is_ok()); |
211 | assert(count == 1); |
212 | |
213 | auto is_not_domain = [](isl::schedule_node node) { |
214 | return !node.isa<isl::schedule_node_domain>(); |
215 | }; |
216 | assert(root.child(0).every_descendant(is_not_domain).is_true()); |
217 | assert(root.every_descendant(is_not_domain).is_false()); |
218 | |
219 | auto fail = [](isl::schedule_node node) { |
220 | return isl::boolean(); |
221 | }; |
222 | assert(root.every_descendant(fail).is_error()); |
223 | |
224 | auto domain = root.as<isl::schedule_node_domain>().domain(); |
225 | auto filters = isl::union_set(ctx, "{}" ); |
226 | auto collect_filters = [&filters](isl::schedule_node node) { |
227 | if (node.isa<isl::schedule_node_filter>().is_true()) { |
228 | auto filter = node.as<isl::schedule_node_filter>(); |
229 | filters = filters.unite(filter.filter()); |
230 | } |
231 | return isl::boolean(true); |
232 | }; |
233 | assert(!root.every_descendant(collect_filters).is_error()); |
234 | assert(domain.is_equal(filters).is_true()); |
235 | } |
236 | |
237 | /* Test basic AST generation from a schedule tree. |
238 | * |
239 | * In particular, create a simple schedule tree and |
240 | * - perform some generic tests |
241 | * - test at_each_domain in the failing case |
242 | */ |
243 | static void test_ast_build(isl::ctx ctx) |
244 | { |
245 | auto schedule = test_ast_build_generic(ctx); |
246 | |
247 | bool do_fail = true; |
248 | int count_ast_fail = 0; |
249 | auto fail_inc_count_ast = |
250 | [&count_ast_fail, &do_fail](isl::ast_node node, |
251 | isl::ast_build build) { |
252 | count_ast_fail++; |
253 | return do_fail ? isl::ast_node() : node; |
254 | }; |
255 | auto build = isl::ast_build(ctx); |
256 | build = build.set_at_each_domain(fail_inc_count_ast); |
257 | auto ast = build.node_from(schedule); |
258 | assert(ast.is_null()); |
259 | assert(count_ast_fail > 0); |
260 | auto build_copy = build; |
261 | int count_ast = 0; |
262 | auto inc_count_ast = |
263 | [&count_ast](isl::ast_node node, isl::ast_build build) { |
264 | count_ast++; |
265 | return node; |
266 | }; |
267 | build_copy = build_copy.set_at_each_domain(inc_count_ast); |
268 | ast = build_copy.node_from(schedule); |
269 | assert(!ast.is_null()); |
270 | assert(count_ast == 2); |
271 | count_ast_fail = 0; |
272 | do_fail = false; |
273 | ast = build.node_from(schedule); |
274 | assert(!ast.is_null()); |
275 | assert(count_ast_fail == 2); |
276 | } |
277 | |
278 | /* Test the isl checked C++ interface |
279 | * |
280 | * This includes: |
281 | * - The isl C <-> C++ pointer interface |
282 | * - Object construction |
283 | * - Different parameter types |
284 | * - Different return types |
285 | * - Foreach functions |
286 | * - Every functions |
287 | * - Spaces |
288 | * - Schedule trees |
289 | * - AST generation |
290 | * - AST expression generation |
291 | */ |
292 | int main() |
293 | { |
294 | isl_ctx *ctx = isl_ctx_alloc(); |
295 | |
296 | isl_options_set_on_error(ctx, ISL_ON_ERROR_ABORT); |
297 | |
298 | test_pointer(ctx); |
299 | test_constructors(ctx); |
300 | test_parameters(ctx); |
301 | test_return(ctx); |
302 | test_foreach(ctx); |
303 | test_every(ctx); |
304 | test_space(ctx); |
305 | test_schedule_tree(ctx); |
306 | test_ast_build(ctx); |
307 | test_ast_build_expr(ctx); |
308 | |
309 | isl_ctx_free(ctx); |
310 | |
311 | return EXIT_SUCCESS; |
312 | } |
313 | |