Mercurial > hg > CbC > CbC_gcc
comparison gcc/function-tests.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children | 84e7813d76e9 |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
1 /* Unit tests for function-handling. | |
2 Copyright (C) 2015-2017 Free Software Foundation, Inc. | |
3 | |
4 This file is part of GCC. | |
5 | |
6 GCC is free software; you can redistribute it and/or modify it under | |
7 the terms of the GNU General Public License as published by the Free | |
8 Software Foundation; either version 3, or (at your option) any later | |
9 version. | |
10 | |
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with GCC; see the file COPYING3. If not see | |
18 <http://www.gnu.org/licenses/>. */ | |
19 | |
20 #include "config.h" | |
21 #include "system.h" | |
22 #include "coretypes.h" | |
23 #include "tm.h" | |
24 #include "opts.h" | |
25 #include "hash-set.h" | |
26 #include "fixed-value.h" | |
27 #include "alias.h" | |
28 #include "flags.h" | |
29 #include "symtab.h" | |
30 #include "tree-core.h" | |
31 #include "stor-layout.h" | |
32 #include "tree.h" | |
33 #include "stringpool.h" | |
34 #include "stor-layout.h" | |
35 #include "rtl.h" | |
36 #include "predict.h" | |
37 #include "vec.h" | |
38 #include "hashtab.h" | |
39 #include "hash-set.h" | |
40 #include "hard-reg-set.h" | |
41 #include "input.h" | |
42 #include "function.h" | |
43 #include "dominance.h" | |
44 #include "cfg.h" | |
45 #include "cfganal.h" | |
46 #include "basic-block.h" | |
47 #include "tree-ssa-alias.h" | |
48 #include "internal-fn.h" | |
49 #include "gimple-fold.h" | |
50 #include "gimple-expr.h" | |
51 #include "toplev.h" | |
52 #include "print-tree.h" | |
53 #include "tree-iterator.h" | |
54 #include "gimplify.h" | |
55 #include "tree-cfg.h" | |
56 #include "basic-block.h" | |
57 #include "alias.h" | |
58 #include "symtab.h" | |
59 #include "inchash.h" | |
60 #include "tree.h" | |
61 #include "fold-const.h" | |
62 #include "stor-layout.h" | |
63 #include "stmt.h" | |
64 #include "hash-table.h" | |
65 #include "tree-ssa-alias.h" | |
66 #include "internal-fn.h" | |
67 #include "gimple-expr.h" | |
68 #include "is-a.h" | |
69 #include "gimple.h" | |
70 #include "tree-pass.h" | |
71 #include "context.h" | |
72 #include "hash-map.h" | |
73 #include "plugin-api.h" | |
74 #include "ipa-ref.h" | |
75 #include "cgraph.h" | |
76 #include "selftest.h" | |
77 #include "print-rtl.h" | |
78 | |
79 #if CHECKING_P | |
80 | |
81 namespace selftest { | |
82 | |
83 /* Helper function for selftests of function-creation. */ | |
84 | |
85 static tree | |
86 make_fndecl (tree return_type, | |
87 const char *name, | |
88 vec <tree> ¶m_types, | |
89 bool is_variadic = false) | |
90 { | |
91 tree fn_type; | |
92 if (is_variadic) | |
93 fn_type = build_varargs_function_type_array (return_type, | |
94 param_types.length (), | |
95 param_types.address ()); | |
96 else | |
97 fn_type = build_function_type_array (return_type, | |
98 param_types.length (), | |
99 param_types.address ()); | |
100 /* FIXME: this uses input_location: */ | |
101 tree fndecl = build_fn_decl (name, fn_type); | |
102 | |
103 return fndecl; | |
104 } | |
105 | |
106 /* Verify creating a function declaration equivalent to the following | |
107 int test_fndecl_int_void (void); | |
108 C declaration. */ | |
109 | |
110 static void | |
111 test_fndecl_int_void () | |
112 { | |
113 auto_vec <tree> param_types; | |
114 const char *name = "test_fndecl_int_void"; | |
115 tree fndecl = make_fndecl (integer_type_node, | |
116 name, | |
117 param_types); | |
118 ASSERT_TRUE (fndecl != NULL); | |
119 | |
120 /* Verify name of decl. */ | |
121 tree declname = DECL_NAME (fndecl); | |
122 ASSERT_TRUE (declname != NULL); | |
123 ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (declname)); | |
124 /* We expect it to use a *copy* of the string we passed in. */ | |
125 const char *identifier_ptr = IDENTIFIER_POINTER (declname); | |
126 ASSERT_NE (name, identifier_ptr); | |
127 ASSERT_EQ (0, strcmp ("test_fndecl_int_void", identifier_ptr)); | |
128 | |
129 /* Verify type of fndecl. */ | |
130 ASSERT_EQ (FUNCTION_DECL, TREE_CODE (fndecl)); | |
131 tree fntype = TREE_TYPE (fndecl); | |
132 ASSERT_EQ (FUNCTION_TYPE, TREE_CODE (fntype)); | |
133 | |
134 /* Verify return type. */ | |
135 ASSERT_EQ (integer_type_node, TREE_TYPE (fntype)); | |
136 | |
137 /* Verify "void" args. */ | |
138 tree argtypes = TYPE_ARG_TYPES (fntype); | |
139 ASSERT_EQ (TREE_LIST, TREE_CODE (argtypes)); | |
140 ASSERT_EQ (void_type_node, TREE_VALUE (argtypes)); | |
141 ASSERT_EQ (NULL, TREE_CHAIN (argtypes)); | |
142 } | |
143 | |
144 /* Verify creating a function declaration equivalent to the following | |
145 float test_fndecl_float_intchar (int, char); | |
146 C declaration. */ | |
147 | |
148 static void | |
149 test_fndecl_float_intchar () | |
150 { | |
151 auto_vec <tree> param_types; | |
152 param_types.safe_push (integer_type_node); | |
153 param_types.safe_push (char_type_node); | |
154 const char *name = "test_fndecl_float_intchar"; | |
155 tree fndecl = make_fndecl (float_type_node, | |
156 name, | |
157 param_types); | |
158 ASSERT_TRUE (fndecl != NULL); | |
159 | |
160 /* Verify name of decl. */ | |
161 tree declname = DECL_NAME (fndecl); | |
162 ASSERT_TRUE (declname != NULL); | |
163 ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (declname)); | |
164 /* We expect it to use a *copy* of the string we passed in. */ | |
165 const char *identifier_ptr = IDENTIFIER_POINTER (declname); | |
166 ASSERT_NE (name, identifier_ptr); | |
167 ASSERT_EQ (0, strcmp (name, identifier_ptr)); | |
168 | |
169 /* Verify type of fndecl. */ | |
170 ASSERT_EQ (FUNCTION_DECL, TREE_CODE (fndecl)); | |
171 tree fntype = TREE_TYPE (fndecl); | |
172 ASSERT_EQ (FUNCTION_TYPE, TREE_CODE (fntype)); | |
173 | |
174 /* Verify return type. */ | |
175 ASSERT_EQ (float_type_node, TREE_TYPE (fntype)); | |
176 | |
177 /* Verify "(int, char)" args. */ | |
178 tree arg0 = TYPE_ARG_TYPES (fntype); | |
179 ASSERT_EQ (TREE_LIST, TREE_CODE (arg0)); | |
180 ASSERT_EQ (integer_type_node, TREE_VALUE (arg0)); | |
181 tree arg1 = TREE_CHAIN (arg0); | |
182 ASSERT_TRUE (arg1 != NULL); | |
183 ASSERT_EQ (TREE_LIST, TREE_CODE (arg1)); | |
184 ASSERT_EQ (char_type_node, TREE_VALUE (arg1)); | |
185 tree argterm = TREE_CHAIN (arg1); | |
186 ASSERT_TRUE (argterm != NULL); | |
187 ASSERT_EQ (TREE_LIST, TREE_CODE (argterm)); | |
188 ASSERT_EQ (void_type_node, TREE_VALUE (argterm)); | |
189 ASSERT_EQ (NULL, TREE_CHAIN (argterm)); | |
190 } | |
191 | |
192 /* The test cases using these helper functions take a trivial function: | |
193 | |
194 int test_fn (void) { return 42; } | |
195 | |
196 and test various conversions done to it: | |
197 | |
198 - gimplification | |
199 - construction of the CFG | |
200 - conversion to SSA form | |
201 - expansion to RTL form | |
202 | |
203 In avoid having one overlong test case, this is broken | |
204 up into separate test cases for each stage, with helper functions | |
205 to minimize code duplication. | |
206 | |
207 Another approach would be to attempt to directly construct a function | |
208 in the appropriate representation at each stage, though presumably | |
209 that would exhibit different kinds of failure compared to this | |
210 approach. */ | |
211 | |
212 /* Construct this function: | |
213 int test_fn (void) { return 42; } | |
214 in generic tree form. Return the fndecl. */ | |
215 | |
216 static tree | |
217 build_trivial_generic_function () | |
218 { | |
219 auto_vec <tree> param_types; | |
220 tree fndecl = make_fndecl (integer_type_node, | |
221 "test_fn", | |
222 param_types); | |
223 ASSERT_TRUE (fndecl != NULL); | |
224 | |
225 /* Populate the function. */ | |
226 tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL, | |
227 NULL_TREE, integer_type_node); | |
228 DECL_ARTIFICIAL (retval) = 1; | |
229 DECL_IGNORED_P (retval) = 1; | |
230 DECL_RESULT (fndecl) = retval; | |
231 | |
232 /* Create a BIND_EXPR, and within it, a statement list. */ | |
233 tree stmt_list = alloc_stmt_list (); | |
234 tree_stmt_iterator stmt_iter = tsi_start (stmt_list); | |
235 tree block = make_node (BLOCK); | |
236 tree bind_expr | |
237 = build3 (BIND_EXPR, void_type_node, NULL, stmt_list, block); | |
238 | |
239 tree modify_retval = build2 (MODIFY_EXPR, | |
240 integer_type_node, | |
241 retval, | |
242 build_int_cst (integer_type_node, 42)); | |
243 tree return_stmt = build1 (RETURN_EXPR, | |
244 integer_type_node, | |
245 modify_retval); | |
246 tsi_link_after (&stmt_iter, return_stmt, TSI_CONTINUE_LINKING); | |
247 | |
248 DECL_INITIAL (fndecl) = block; | |
249 BLOCK_SUPERCONTEXT (block) = fndecl; | |
250 | |
251 /* how to add to function? the following appears to be how to | |
252 set the body of a fndecl: */ | |
253 DECL_SAVED_TREE(fndecl) = bind_expr; | |
254 | |
255 /* Ensure that locals appear in the debuginfo. */ | |
256 BLOCK_VARS (block) = BIND_EXPR_VARS (bind_expr); | |
257 | |
258 return fndecl; | |
259 } | |
260 | |
261 /* Construct this function: | |
262 int test_fn (void) { return 42; } | |
263 in "high gimple" form. Return the fndecl. */ | |
264 | |
265 static tree | |
266 build_trivial_high_gimple_function () | |
267 { | |
268 /* Construct a trivial function, and gimplify it: */ | |
269 tree fndecl = build_trivial_generic_function (); | |
270 gimplify_function_tree (fndecl); | |
271 return fndecl; | |
272 } | |
273 | |
274 /* Build a CFG for a function in gimple form. */ | |
275 | |
276 static void | |
277 build_cfg (tree fndecl) | |
278 { | |
279 function *fun = DECL_STRUCT_FUNCTION (fndecl); | |
280 ASSERT_TRUE (fun != NULL); | |
281 ASSERT_EQ (fndecl, fun->decl); | |
282 | |
283 /* We first have to lower control flow; for our trivial test function | |
284 this gives us: | |
285 test_fn () | |
286 { | |
287 D.56 = 42; | |
288 goto <D.57>; | |
289 <D.57>: | |
290 return D.56; | |
291 } | |
292 */ | |
293 gimple_opt_pass *lower_cf_pass = make_pass_lower_cf (g); | |
294 push_cfun (fun); | |
295 lower_cf_pass->execute (fun); | |
296 pop_cfun (); | |
297 delete lower_cf_pass; | |
298 | |
299 /* We can now convert to CFG form; for our trivial test function this | |
300 gives us: | |
301 test_fn () | |
302 { | |
303 <bb 2>: | |
304 D.56 = 42; | |
305 return D.56; | |
306 } | |
307 */ | |
308 gimple_opt_pass *build_cfg_pass = make_pass_build_cfg (g); | |
309 push_cfun (fun); | |
310 build_cfg_pass->execute (fun); | |
311 pop_cfun (); | |
312 delete build_cfg_pass; | |
313 } | |
314 | |
315 /* Convert a gimple+CFG function to SSA form. */ | |
316 | |
317 static void | |
318 convert_to_ssa (tree fndecl) | |
319 { | |
320 function *fun = DECL_STRUCT_FUNCTION (fndecl); | |
321 ASSERT_TRUE (fun != NULL); | |
322 ASSERT_EQ (fndecl, fun->decl); | |
323 | |
324 gimple_opt_pass *build_ssa_pass = make_pass_build_ssa (g); | |
325 push_cfun (fun); | |
326 build_ssa_pass->execute (fun); | |
327 pop_cfun (); | |
328 delete build_ssa_pass; | |
329 } | |
330 | |
331 /* Assuming we have a simple 3-block CFG like this: | |
332 [ENTRY] -> [block2] -> [EXIT] | |
333 get the "real" basic block (block 2). */ | |
334 | |
335 static basic_block | |
336 get_real_block (function *fun) | |
337 { | |
338 ASSERT_TRUE (fun->cfg != NULL); | |
339 ASSERT_EQ (3, n_basic_blocks_for_fn (fun)); | |
340 basic_block bb2 = (*fun->cfg->x_basic_block_info)[2]; | |
341 ASSERT_TRUE (bb2 != NULL); | |
342 return bb2; | |
343 } | |
344 | |
345 /* Verify that we have a simple 3-block CFG: the two "fake" ones, and | |
346 a "real" one: | |
347 [ENTRY] -> [block2] -> [EXIT]. */ | |
348 | |
349 static void | |
350 verify_three_block_cfg (function *fun) | |
351 { | |
352 ASSERT_TRUE (fun->cfg != NULL); | |
353 ASSERT_EQ (3, n_basic_blocks_for_fn (fun)); | |
354 ASSERT_EQ (2, n_edges_for_fn (fun)); | |
355 | |
356 /* The "fake" basic blocks. */ | |
357 basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun); | |
358 ASSERT_TRUE (entry != NULL); | |
359 ASSERT_EQ (ENTRY_BLOCK, entry->index); | |
360 | |
361 basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun); | |
362 ASSERT_TRUE (exit != NULL); | |
363 ASSERT_EQ (EXIT_BLOCK, exit->index); | |
364 | |
365 /* The "real" basic block. */ | |
366 basic_block bb2 = get_real_block (fun); | |
367 ASSERT_TRUE (bb2 != NULL); | |
368 ASSERT_EQ (2, bb2->index); | |
369 | |
370 /* Verify connectivity. */ | |
371 ASSERT_EQ (NULL, entry->preds); | |
372 ASSERT_EQ (1, entry->succs->length ()); | |
373 | |
374 edge from_entry_to_bb2 = (*entry->succs)[0]; | |
375 ASSERT_EQ (entry, from_entry_to_bb2->src); | |
376 ASSERT_EQ (bb2, from_entry_to_bb2->dest); | |
377 | |
378 ASSERT_EQ (1, bb2->preds->length ()); | |
379 ASSERT_EQ (from_entry_to_bb2, (*bb2->preds)[0]); | |
380 ASSERT_EQ (1, bb2->succs->length ()); | |
381 | |
382 edge from_bb2_to_exit = (*bb2->succs)[0]; | |
383 ASSERT_EQ (bb2, from_bb2_to_exit->src); | |
384 ASSERT_EQ (exit, from_bb2_to_exit->dest); | |
385 | |
386 ASSERT_EQ (1, exit->preds->length ()); | |
387 ASSERT_EQ (from_bb2_to_exit, (*exit->preds)[0]); | |
388 ASSERT_EQ (NULL, exit->succs); | |
389 } | |
390 | |
391 /* As above, but additionally verify the gimple statements are sane. */ | |
392 | |
393 static void | |
394 verify_three_block_gimple_cfg (function *fun) | |
395 { | |
396 verify_three_block_cfg (fun); | |
397 | |
398 /* The "fake" basic blocks should be flagged as gimple, but with have no | |
399 statements. */ | |
400 basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun); | |
401 ASSERT_TRUE (entry != NULL); | |
402 ASSERT_EQ (0, entry->flags & BB_RTL); | |
403 ASSERT_EQ (NULL, bb_seq (entry)); | |
404 | |
405 basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun); | |
406 ASSERT_TRUE (exit != NULL); | |
407 ASSERT_EQ (0, entry->flags & BB_RTL); | |
408 ASSERT_EQ (NULL, bb_seq (exit)); | |
409 | |
410 /* The "real" basic block should be flagged as gimple, and have one | |
411 or more statements. */ | |
412 basic_block bb2 = get_real_block (fun); | |
413 ASSERT_TRUE (bb2 != NULL); | |
414 ASSERT_EQ (0, entry->flags & BB_RTL); | |
415 ASSERT_TRUE (bb_seq (bb2) != NULL); | |
416 } | |
417 | |
418 /* As above, but additionally verify the RTL insns are sane. */ | |
419 | |
420 void | |
421 verify_three_block_rtl_cfg (function *fun) | |
422 { | |
423 verify_three_block_cfg (fun); | |
424 | |
425 /* The "fake" basic blocks should be flagged as RTL, but with no | |
426 insns. */ | |
427 basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun); | |
428 ASSERT_TRUE (entry != NULL); | |
429 ASSERT_EQ (BB_RTL, entry->flags & BB_RTL); | |
430 ASSERT_EQ (NULL, BB_HEAD (entry)); | |
431 | |
432 basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun); | |
433 ASSERT_TRUE (exit != NULL); | |
434 ASSERT_EQ (BB_RTL, exit->flags & BB_RTL); | |
435 ASSERT_EQ (NULL, BB_HEAD (exit)); | |
436 | |
437 /* The "real" basic block should be flagged as RTL, and have one | |
438 or more insns. */ | |
439 basic_block bb2 = get_real_block (fun); | |
440 ASSERT_TRUE (bb2 != NULL); | |
441 ASSERT_EQ (BB_RTL, bb2->flags & BB_RTL); | |
442 ASSERT_TRUE (BB_HEAD (bb2) != NULL); | |
443 } | |
444 | |
445 /* Test converting our trivial function: | |
446 int test_fn (void) { return 42; } | |
447 to gimple form. */ | |
448 | |
449 static void | |
450 test_gimplification () | |
451 { | |
452 tree fndecl = build_trivial_generic_function (); | |
453 | |
454 /* Convert to gimple: */ | |
455 gimplify_function_tree (fndecl); | |
456 | |
457 /* Verify that we got gimple out of it. */ | |
458 | |
459 /* The function is now in GIMPLE form but the CFG has not been | |
460 built yet. */ | |
461 | |
462 /* We should have a struct function for the decl. */ | |
463 function *fun = DECL_STRUCT_FUNCTION (fndecl); | |
464 ASSERT_TRUE (fun != NULL); | |
465 ASSERT_EQ (fndecl, fun->decl); | |
466 | |
467 /* We expect a GIMPLE_BIND, with two gimple statements within it: | |
468 tmp = 42; | |
469 return tmp; */ | |
470 | |
471 gimple_seq seq_fn_body = gimple_body (fndecl); | |
472 ASSERT_TRUE (seq_fn_body != NULL); | |
473 gimple *bind_stmt = gimple_seq_first_stmt (seq_fn_body); | |
474 ASSERT_EQ (GIMPLE_BIND, gimple_code (bind_stmt)); | |
475 ASSERT_EQ (NULL, bind_stmt->next); | |
476 | |
477 gimple_seq seq_bind_body = gimple_bind_body (as_a <gbind *> (bind_stmt)); | |
478 | |
479 /* Verify that we have the 2 statements we expect. */ | |
480 ASSERT_TRUE (seq_bind_body != NULL); | |
481 gimple *stmt1 = gimple_seq_first_stmt (seq_bind_body); | |
482 ASSERT_TRUE (stmt1 != NULL); | |
483 ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt1)); | |
484 gimple *stmt2 = stmt1->next; | |
485 ASSERT_TRUE (stmt2 != NULL); | |
486 ASSERT_EQ (stmt1, stmt2->prev); | |
487 ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt2)); | |
488 } | |
489 | |
490 /* Test of building a CFG for a function in high gimple form. */ | |
491 | |
492 static void | |
493 test_building_cfg () | |
494 { | |
495 /* Construct a trivial function, and gimplify it: */ | |
496 tree fndecl = build_trivial_high_gimple_function (); | |
497 function *fun = DECL_STRUCT_FUNCTION (fndecl); | |
498 ASSERT_TRUE (fun != NULL); | |
499 | |
500 /* Build a CFG. */ | |
501 build_cfg (fndecl); | |
502 | |
503 /* The CFG-building code constructs a 4-block cfg (with | |
504 ENTRY and EXIT): | |
505 test_fn () | |
506 { | |
507 <bb 2>: | |
508 D.65 = 42; | |
509 | |
510 <bb 3>: | |
511 return D.65; | |
512 } | |
513 and then ought to merge blocks 2 and 3 in cleanup_tree_cfg. | |
514 | |
515 Hence we should end up with a simple 3-block cfg, the two "fake" ones, | |
516 and a "real" one: | |
517 [ENTRY] -> [block2] -> [EXIT] | |
518 with code like this: | |
519 test_fn () | |
520 { | |
521 <bb 2>: | |
522 D.56 = 42; | |
523 return D.56; | |
524 } | |
525 */ | |
526 verify_three_block_gimple_cfg (fun); | |
527 | |
528 /* Verify the statements within the "real" block. */ | |
529 basic_block bb2 = get_real_block (fun); | |
530 gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2)); | |
531 ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a)); | |
532 gimple *stmt_b = stmt_a->next; | |
533 ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt_b)); | |
534 ASSERT_EQ (NULL, stmt_b->next); | |
535 } | |
536 | |
537 /* Test of conversion of gimple to SSA form. */ | |
538 | |
539 static void | |
540 test_conversion_to_ssa () | |
541 { | |
542 /* As above, construct a trivial function, gimplify it, and build a CFG: */ | |
543 tree fndecl = build_trivial_high_gimple_function (); | |
544 function *fun = DECL_STRUCT_FUNCTION (fndecl); | |
545 ASSERT_TRUE (fun != NULL); | |
546 build_cfg (fndecl); | |
547 | |
548 convert_to_ssa (fndecl); | |
549 | |
550 verify_three_block_gimple_cfg (fun); | |
551 | |
552 /* For out trivial test function we should now have something like | |
553 this: | |
554 test_fn () | |
555 { | |
556 <bb 2>: | |
557 _1 = 42; | |
558 return _1; | |
559 } | |
560 */ | |
561 basic_block bb2 = get_real_block (fun); | |
562 gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2)); | |
563 ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a)); | |
564 | |
565 gimple *stmt_b = stmt_a->next; | |
566 ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt_b)); | |
567 ASSERT_EQ (NULL, stmt_b->next); | |
568 | |
569 greturn *return_stmt = as_a <greturn *> (stmt_b); | |
570 ASSERT_EQ (SSA_NAME, TREE_CODE (gimple_return_retval (return_stmt))); | |
571 } | |
572 | |
573 /* Test of expansion from gimple-ssa to RTL. */ | |
574 | |
575 static void | |
576 test_expansion_to_rtl () | |
577 { | |
578 /* As above, construct a trivial function, gimplify it, build a CFG, | |
579 and convert to SSA: */ | |
580 tree fndecl = build_trivial_high_gimple_function (); | |
581 function *fun = DECL_STRUCT_FUNCTION (fndecl); | |
582 ASSERT_TRUE (fun != NULL); | |
583 build_cfg (fndecl); | |
584 convert_to_ssa (fndecl); | |
585 | |
586 /* We need a cgraph_node for it. */ | |
587 cgraph_node::get_create (fndecl); | |
588 /* Normally, cgraph_node::expand () would call | |
589 init_function_start (and a bunch of other stuff), | |
590 and invoke the expand pass, but it also runs | |
591 all of the other passes. So just do the minimum | |
592 needed to get from gimple-SSA to RTL. */ | |
593 rtl_opt_pass *expand_pass = make_pass_expand (g); | |
594 push_cfun (fun); | |
595 init_function_start (fndecl); | |
596 expand_pass->execute (fun); | |
597 pop_cfun (); | |
598 delete expand_pass; | |
599 | |
600 /* On x86_64, I get this: | |
601 (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK) | |
602 (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG) | |
603 (insn 5 2 6 2 (set (reg:SI 87 [ D.59 ]) | |
604 (const_int 42 [0x2a])) -1 (nil)) | |
605 (insn 6 5 10 2 (set (reg:SI 88 [ <retval> ]) | |
606 (reg:SI 87 [ D.59 ])) -1 (nil)) | |
607 (insn 10 6 11 2 (set (reg/i:SI 0 ax) | |
608 (reg:SI 88 [ <retval> ])) -1 (nil)) | |
609 (insn 11 10 0 2 (use (reg/i:SI 0 ax)) -1 (nil)) | |
610 | |
611 On cr16-elf I get this: | |
612 (note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK) | |
613 (insn 2 4 3 2 (set (reg:SI 24) | |
614 (reg/f:SI 16 virtual-incoming-args)) -1 | |
615 (nil)) | |
616 (note 3 2 6 2 NOTE_INSN_FUNCTION_BEG) | |
617 (insn 6 3 7 2 (set (reg:HI 22 [ _1 ]) | |
618 (const_int 42 [0x2a])) -1 | |
619 (nil)) | |
620 (insn 7 6 11 2 (set (reg:HI 23 [ <retval> ]) | |
621 (reg:HI 22 [ _1 ])) -1 | |
622 (nil)) | |
623 (insn 11 7 12 2 (set (reg/i:HI 0 r0) | |
624 (reg:HI 23 [ <retval> ])) -1 | |
625 (nil)) | |
626 (insn 12 11 0 2 (use (reg/i:HI 0 r0)) -1 | |
627 (nil)). */ | |
628 verify_three_block_rtl_cfg (fun); | |
629 | |
630 /* Verify as much of the RTL as we can whilst avoiding | |
631 target-specific behavior. */ | |
632 basic_block bb2 = get_real_block (fun); | |
633 | |
634 /* Expect a NOTE_INSN_BASIC_BLOCK... */ | |
635 rtx_insn *insn = BB_HEAD (bb2); | |
636 ASSERT_TRUE (insn != NULL); | |
637 ASSERT_EQ (NOTE, insn->code); | |
638 ASSERT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (insn)); | |
639 ASSERT_EQ (bb2, NOTE_BASIC_BLOCK (insn)); | |
640 | |
641 /* ...etc; any further checks are likely to over-specify things | |
642 and run us into target dependencies. */ | |
643 | |
644 /* Verify that print_rtl_function is sane. */ | |
645 named_temp_file tmp_out (".rtl"); | |
646 FILE *outfile = fopen (tmp_out.get_filename (), "w"); | |
647 print_rtx_function (outfile, fun, true); | |
648 fclose (outfile); | |
649 | |
650 char *dump = read_file (SELFTEST_LOCATION, tmp_out.get_filename ()); | |
651 ASSERT_STR_CONTAINS (dump, "(function \"test_fn\"\n"); | |
652 ASSERT_STR_CONTAINS (dump, " (insn-chain\n"); | |
653 ASSERT_STR_CONTAINS (dump, " (block 2\n"); | |
654 ASSERT_STR_CONTAINS (dump, " (edge-from entry (flags \"FALLTHRU\"))\n"); | |
655 ASSERT_STR_CONTAINS (dump, " (cinsn "); /* ...etc. */ | |
656 ASSERT_STR_CONTAINS (dump, " (edge-to exit (flags \"FALLTHRU\"))\n"); | |
657 ASSERT_STR_CONTAINS (dump, " ) ;; block 2\n"); | |
658 ASSERT_STR_CONTAINS (dump, " ) ;; insn-chain\n"); | |
659 ASSERT_STR_CONTAINS (dump, " (crtl\n"); | |
660 ASSERT_STR_CONTAINS (dump, " ) ;; crtl\n"); | |
661 ASSERT_STR_CONTAINS (dump, ") ;; function \"test_fn\"\n"); | |
662 | |
663 free (dump); | |
664 } | |
665 | |
666 /* Run all of the selftests within this file. */ | |
667 | |
668 void | |
669 function_tests_c_tests () | |
670 { | |
671 test_fndecl_int_void (); | |
672 test_fndecl_float_intchar (); | |
673 test_gimplification (); | |
674 test_building_cfg (); | |
675 test_conversion_to_ssa (); | |
676 test_expansion_to_rtl (); | |
677 } | |
678 | |
679 } // namespace selftest | |
680 | |
681 #endif /* #if CHECKING_P */ |