138fd1498Szrj /* Unit tests for function-handling.
238fd1498Szrj Copyright (C) 2015-2018 Free Software Foundation, Inc.
338fd1498Szrj
438fd1498Szrj This file is part of GCC.
538fd1498Szrj
638fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
738fd1498Szrj the terms of the GNU General Public License as published by the Free
838fd1498Szrj Software Foundation; either version 3, or (at your option) any later
938fd1498Szrj version.
1038fd1498Szrj
1138fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1238fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1338fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1438fd1498Szrj for more details.
1538fd1498Szrj
1638fd1498Szrj You should have received a copy of the GNU General Public License
1738fd1498Szrj along with GCC; see the file COPYING3. If not see
1838fd1498Szrj <http://www.gnu.org/licenses/>. */
1938fd1498Szrj
2038fd1498Szrj #include "config.h"
2138fd1498Szrj #include "system.h"
2238fd1498Szrj #include "coretypes.h"
2338fd1498Szrj #include "tm.h"
2438fd1498Szrj #include "opts.h"
2538fd1498Szrj #include "hash-set.h"
2638fd1498Szrj #include "fixed-value.h"
2738fd1498Szrj #include "alias.h"
2838fd1498Szrj #include "flags.h"
2938fd1498Szrj #include "symtab.h"
3038fd1498Szrj #include "tree-core.h"
3138fd1498Szrj #include "stor-layout.h"
3238fd1498Szrj #include "tree.h"
3338fd1498Szrj #include "stringpool.h"
3438fd1498Szrj #include "stor-layout.h"
3538fd1498Szrj #include "rtl.h"
3638fd1498Szrj #include "predict.h"
3738fd1498Szrj #include "vec.h"
3838fd1498Szrj #include "hashtab.h"
3938fd1498Szrj #include "hash-set.h"
4038fd1498Szrj #include "hard-reg-set.h"
4138fd1498Szrj #include "input.h"
4238fd1498Szrj #include "function.h"
4338fd1498Szrj #include "dominance.h"
4438fd1498Szrj #include "cfg.h"
4538fd1498Szrj #include "cfganal.h"
4638fd1498Szrj #include "basic-block.h"
4738fd1498Szrj #include "tree-ssa-alias.h"
4838fd1498Szrj #include "internal-fn.h"
4938fd1498Szrj #include "gimple-fold.h"
5038fd1498Szrj #include "gimple-expr.h"
5138fd1498Szrj #include "toplev.h"
5238fd1498Szrj #include "print-tree.h"
5338fd1498Szrj #include "tree-iterator.h"
5438fd1498Szrj #include "gimplify.h"
5538fd1498Szrj #include "tree-cfg.h"
5638fd1498Szrj #include "basic-block.h"
5738fd1498Szrj #include "alias.h"
5838fd1498Szrj #include "symtab.h"
5938fd1498Szrj #include "inchash.h"
6038fd1498Szrj #include "tree.h"
6138fd1498Szrj #include "fold-const.h"
6238fd1498Szrj #include "stor-layout.h"
6338fd1498Szrj #include "stmt.h"
6438fd1498Szrj #include "hash-table.h"
6538fd1498Szrj #include "tree-ssa-alias.h"
6638fd1498Szrj #include "internal-fn.h"
6738fd1498Szrj #include "gimple-expr.h"
6838fd1498Szrj #include "is-a.h"
6938fd1498Szrj #include "gimple.h"
7038fd1498Szrj #include "tree-pass.h"
7138fd1498Szrj #include "context.h"
7238fd1498Szrj #include "hash-map.h"
7338fd1498Szrj #include "plugin-api.h"
7438fd1498Szrj #include "ipa-ref.h"
7538fd1498Szrj #include "cgraph.h"
7638fd1498Szrj #include "selftest.h"
7738fd1498Szrj #include "print-rtl.h"
7838fd1498Szrj
7938fd1498Szrj #if CHECKING_P
8038fd1498Szrj
8138fd1498Szrj namespace selftest {
8238fd1498Szrj
8338fd1498Szrj /* Helper function for selftests of function-creation. */
8438fd1498Szrj
8538fd1498Szrj static tree
8638fd1498Szrj make_fndecl (tree return_type,
8738fd1498Szrj const char *name,
8838fd1498Szrj vec <tree> ¶m_types,
8938fd1498Szrj bool is_variadic = false)
9038fd1498Szrj {
9138fd1498Szrj tree fn_type;
9238fd1498Szrj if (is_variadic)
9338fd1498Szrj fn_type = build_varargs_function_type_array (return_type,
9438fd1498Szrj param_types.length (),
9538fd1498Szrj param_types.address ());
9638fd1498Szrj else
9738fd1498Szrj fn_type = build_function_type_array (return_type,
9838fd1498Szrj param_types.length (),
9938fd1498Szrj param_types.address ());
10038fd1498Szrj /* FIXME: this uses input_location: */
10138fd1498Szrj tree fndecl = build_fn_decl (name, fn_type);
10238fd1498Szrj
10338fd1498Szrj return fndecl;
10438fd1498Szrj }
10538fd1498Szrj
10638fd1498Szrj /* Verify creating a function declaration equivalent to the following
10738fd1498Szrj int test_fndecl_int_void (void);
10838fd1498Szrj C declaration. */
10938fd1498Szrj
11038fd1498Szrj static void
test_fndecl_int_void()11138fd1498Szrj test_fndecl_int_void ()
11238fd1498Szrj {
11338fd1498Szrj auto_vec <tree> param_types;
11438fd1498Szrj const char *name = "test_fndecl_int_void";
11538fd1498Szrj tree fndecl = make_fndecl (integer_type_node,
11638fd1498Szrj name,
11738fd1498Szrj param_types);
11838fd1498Szrj ASSERT_TRUE (fndecl != NULL);
11938fd1498Szrj
12038fd1498Szrj /* Verify name of decl. */
12138fd1498Szrj tree declname = DECL_NAME (fndecl);
12238fd1498Szrj ASSERT_TRUE (declname != NULL);
12338fd1498Szrj ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
12438fd1498Szrj /* We expect it to use a *copy* of the string we passed in. */
12538fd1498Szrj const char *identifier_ptr = IDENTIFIER_POINTER (declname);
12638fd1498Szrj ASSERT_NE (name, identifier_ptr);
12738fd1498Szrj ASSERT_EQ (0, strcmp ("test_fndecl_int_void", identifier_ptr));
12838fd1498Szrj
12938fd1498Szrj /* Verify type of fndecl. */
13038fd1498Szrj ASSERT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
13138fd1498Szrj tree fntype = TREE_TYPE (fndecl);
13238fd1498Szrj ASSERT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
13338fd1498Szrj
13438fd1498Szrj /* Verify return type. */
13538fd1498Szrj ASSERT_EQ (integer_type_node, TREE_TYPE (fntype));
13638fd1498Szrj
13738fd1498Szrj /* Verify "void" args. */
13838fd1498Szrj tree argtypes = TYPE_ARG_TYPES (fntype);
13938fd1498Szrj ASSERT_EQ (TREE_LIST, TREE_CODE (argtypes));
14038fd1498Szrj ASSERT_EQ (void_type_node, TREE_VALUE (argtypes));
14138fd1498Szrj ASSERT_EQ (NULL, TREE_CHAIN (argtypes));
14238fd1498Szrj }
14338fd1498Szrj
14438fd1498Szrj /* Verify creating a function declaration equivalent to the following
14538fd1498Szrj float test_fndecl_float_intchar (int, char);
14638fd1498Szrj C declaration. */
14738fd1498Szrj
14838fd1498Szrj static void
test_fndecl_float_intchar()14938fd1498Szrj test_fndecl_float_intchar ()
15038fd1498Szrj {
15138fd1498Szrj auto_vec <tree> param_types;
15238fd1498Szrj param_types.safe_push (integer_type_node);
15338fd1498Szrj param_types.safe_push (char_type_node);
15438fd1498Szrj const char *name = "test_fndecl_float_intchar";
15538fd1498Szrj tree fndecl = make_fndecl (float_type_node,
15638fd1498Szrj name,
15738fd1498Szrj param_types);
15838fd1498Szrj ASSERT_TRUE (fndecl != NULL);
15938fd1498Szrj
16038fd1498Szrj /* Verify name of decl. */
16138fd1498Szrj tree declname = DECL_NAME (fndecl);
16238fd1498Szrj ASSERT_TRUE (declname != NULL);
16338fd1498Szrj ASSERT_EQ (IDENTIFIER_NODE, TREE_CODE (declname));
16438fd1498Szrj /* We expect it to use a *copy* of the string we passed in. */
16538fd1498Szrj const char *identifier_ptr = IDENTIFIER_POINTER (declname);
16638fd1498Szrj ASSERT_NE (name, identifier_ptr);
16738fd1498Szrj ASSERT_EQ (0, strcmp (name, identifier_ptr));
16838fd1498Szrj
16938fd1498Szrj /* Verify type of fndecl. */
17038fd1498Szrj ASSERT_EQ (FUNCTION_DECL, TREE_CODE (fndecl));
17138fd1498Szrj tree fntype = TREE_TYPE (fndecl);
17238fd1498Szrj ASSERT_EQ (FUNCTION_TYPE, TREE_CODE (fntype));
17338fd1498Szrj
17438fd1498Szrj /* Verify return type. */
17538fd1498Szrj ASSERT_EQ (float_type_node, TREE_TYPE (fntype));
17638fd1498Szrj
17738fd1498Szrj /* Verify "(int, char)" args. */
17838fd1498Szrj tree arg0 = TYPE_ARG_TYPES (fntype);
17938fd1498Szrj ASSERT_EQ (TREE_LIST, TREE_CODE (arg0));
18038fd1498Szrj ASSERT_EQ (integer_type_node, TREE_VALUE (arg0));
18138fd1498Szrj tree arg1 = TREE_CHAIN (arg0);
18238fd1498Szrj ASSERT_TRUE (arg1 != NULL);
18338fd1498Szrj ASSERT_EQ (TREE_LIST, TREE_CODE (arg1));
18438fd1498Szrj ASSERT_EQ (char_type_node, TREE_VALUE (arg1));
18538fd1498Szrj tree argterm = TREE_CHAIN (arg1);
18638fd1498Szrj ASSERT_TRUE (argterm != NULL);
18738fd1498Szrj ASSERT_EQ (TREE_LIST, TREE_CODE (argterm));
18838fd1498Szrj ASSERT_EQ (void_type_node, TREE_VALUE (argterm));
18938fd1498Szrj ASSERT_EQ (NULL, TREE_CHAIN (argterm));
19038fd1498Szrj }
19138fd1498Szrj
19238fd1498Szrj /* The test cases using these helper functions take a trivial function:
19338fd1498Szrj
19438fd1498Szrj int test_fn (void) { return 42; }
19538fd1498Szrj
19638fd1498Szrj and test various conversions done to it:
19738fd1498Szrj
19838fd1498Szrj - gimplification
19938fd1498Szrj - construction of the CFG
20038fd1498Szrj - conversion to SSA form
20138fd1498Szrj - expansion to RTL form
20238fd1498Szrj
20338fd1498Szrj In avoid having one overlong test case, this is broken
20438fd1498Szrj up into separate test cases for each stage, with helper functions
20538fd1498Szrj to minimize code duplication.
20638fd1498Szrj
20738fd1498Szrj Another approach would be to attempt to directly construct a function
20838fd1498Szrj in the appropriate representation at each stage, though presumably
20938fd1498Szrj that would exhibit different kinds of failure compared to this
21038fd1498Szrj approach. */
21138fd1498Szrj
21238fd1498Szrj /* Construct this function:
21338fd1498Szrj int test_fn (void) { return 42; }
21438fd1498Szrj in generic tree form. Return the fndecl. */
21538fd1498Szrj
21638fd1498Szrj static tree
build_trivial_generic_function()21738fd1498Szrj build_trivial_generic_function ()
21838fd1498Szrj {
21938fd1498Szrj auto_vec <tree> param_types;
22038fd1498Szrj tree fndecl = make_fndecl (integer_type_node,
22138fd1498Szrj "test_fn",
22238fd1498Szrj param_types);
22338fd1498Szrj ASSERT_TRUE (fndecl != NULL);
22438fd1498Szrj
22538fd1498Szrj /* Populate the function. */
22638fd1498Szrj tree retval = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
22738fd1498Szrj NULL_TREE, integer_type_node);
22838fd1498Szrj DECL_ARTIFICIAL (retval) = 1;
22938fd1498Szrj DECL_IGNORED_P (retval) = 1;
23038fd1498Szrj DECL_RESULT (fndecl) = retval;
23138fd1498Szrj
23238fd1498Szrj /* Create a BIND_EXPR, and within it, a statement list. */
23338fd1498Szrj tree stmt_list = alloc_stmt_list ();
23438fd1498Szrj tree_stmt_iterator stmt_iter = tsi_start (stmt_list);
23538fd1498Szrj tree block = make_node (BLOCK);
23638fd1498Szrj tree bind_expr
23738fd1498Szrj = build3 (BIND_EXPR, void_type_node, NULL, stmt_list, block);
23838fd1498Szrj
23938fd1498Szrj tree modify_retval = build2 (MODIFY_EXPR,
24038fd1498Szrj integer_type_node,
24138fd1498Szrj retval,
24238fd1498Szrj build_int_cst (integer_type_node, 42));
24338fd1498Szrj tree return_stmt = build1 (RETURN_EXPR,
24438fd1498Szrj integer_type_node,
24538fd1498Szrj modify_retval);
24638fd1498Szrj tsi_link_after (&stmt_iter, return_stmt, TSI_CONTINUE_LINKING);
24738fd1498Szrj
24838fd1498Szrj DECL_INITIAL (fndecl) = block;
24938fd1498Szrj BLOCK_SUPERCONTEXT (block) = fndecl;
25038fd1498Szrj
25138fd1498Szrj /* how to add to function? the following appears to be how to
25238fd1498Szrj set the body of a fndecl: */
25338fd1498Szrj DECL_SAVED_TREE(fndecl) = bind_expr;
25438fd1498Szrj
25538fd1498Szrj /* Ensure that locals appear in the debuginfo. */
25638fd1498Szrj BLOCK_VARS (block) = BIND_EXPR_VARS (bind_expr);
25738fd1498Szrj
25838fd1498Szrj return fndecl;
25938fd1498Szrj }
26038fd1498Szrj
26138fd1498Szrj /* Construct this function:
26238fd1498Szrj int test_fn (void) { return 42; }
26338fd1498Szrj in "high gimple" form. Return the fndecl. */
26438fd1498Szrj
26538fd1498Szrj static tree
build_trivial_high_gimple_function()26638fd1498Szrj build_trivial_high_gimple_function ()
26738fd1498Szrj {
26838fd1498Szrj /* Construct a trivial function, and gimplify it: */
26938fd1498Szrj tree fndecl = build_trivial_generic_function ();
27038fd1498Szrj gimplify_function_tree (fndecl);
27138fd1498Szrj return fndecl;
27238fd1498Szrj }
27338fd1498Szrj
27438fd1498Szrj /* Build a CFG for a function in gimple form. */
27538fd1498Szrj
27638fd1498Szrj static void
build_cfg(tree fndecl)27738fd1498Szrj build_cfg (tree fndecl)
27838fd1498Szrj {
27938fd1498Szrj function *fun = DECL_STRUCT_FUNCTION (fndecl);
28038fd1498Szrj ASSERT_TRUE (fun != NULL);
28138fd1498Szrj ASSERT_EQ (fndecl, fun->decl);
28238fd1498Szrj
28338fd1498Szrj /* We first have to lower control flow; for our trivial test function
28438fd1498Szrj this gives us:
28538fd1498Szrj test_fn ()
28638fd1498Szrj {
28738fd1498Szrj D.56 = 42;
28838fd1498Szrj goto <D.57>;
28938fd1498Szrj <D.57>:
29038fd1498Szrj return D.56;
29138fd1498Szrj }
29238fd1498Szrj */
29338fd1498Szrj gimple_opt_pass *lower_cf_pass = make_pass_lower_cf (g);
29438fd1498Szrj push_cfun (fun);
29538fd1498Szrj lower_cf_pass->execute (fun);
29638fd1498Szrj pop_cfun ();
29738fd1498Szrj delete lower_cf_pass;
29838fd1498Szrj
29938fd1498Szrj /* We can now convert to CFG form; for our trivial test function this
30038fd1498Szrj gives us:
30138fd1498Szrj test_fn ()
30238fd1498Szrj {
30338fd1498Szrj <bb 2>:
30438fd1498Szrj D.56 = 42;
30538fd1498Szrj return D.56;
30638fd1498Szrj }
30738fd1498Szrj */
30838fd1498Szrj gimple_opt_pass *build_cfg_pass = make_pass_build_cfg (g);
30938fd1498Szrj push_cfun (fun);
31038fd1498Szrj build_cfg_pass->execute (fun);
31138fd1498Szrj pop_cfun ();
31238fd1498Szrj delete build_cfg_pass;
31338fd1498Szrj }
31438fd1498Szrj
31538fd1498Szrj /* Convert a gimple+CFG function to SSA form. */
31638fd1498Szrj
31738fd1498Szrj static void
convert_to_ssa(tree fndecl)31838fd1498Szrj convert_to_ssa (tree fndecl)
31938fd1498Szrj {
32038fd1498Szrj function *fun = DECL_STRUCT_FUNCTION (fndecl);
32138fd1498Szrj ASSERT_TRUE (fun != NULL);
32238fd1498Szrj ASSERT_EQ (fndecl, fun->decl);
32338fd1498Szrj
32438fd1498Szrj gimple_opt_pass *build_ssa_pass = make_pass_build_ssa (g);
32538fd1498Szrj push_cfun (fun);
32638fd1498Szrj build_ssa_pass->execute (fun);
32738fd1498Szrj pop_cfun ();
32838fd1498Szrj delete build_ssa_pass;
32938fd1498Szrj }
33038fd1498Szrj
33138fd1498Szrj /* Assuming we have a simple 3-block CFG like this:
33238fd1498Szrj [ENTRY] -> [block2] -> [EXIT]
33338fd1498Szrj get the "real" basic block (block 2). */
33438fd1498Szrj
33538fd1498Szrj static basic_block
get_real_block(function * fun)33638fd1498Szrj get_real_block (function *fun)
33738fd1498Szrj {
33838fd1498Szrj ASSERT_TRUE (fun->cfg != NULL);
33938fd1498Szrj ASSERT_EQ (3, n_basic_blocks_for_fn (fun));
34038fd1498Szrj basic_block bb2 = (*fun->cfg->x_basic_block_info)[2];
34138fd1498Szrj ASSERT_TRUE (bb2 != NULL);
34238fd1498Szrj return bb2;
34338fd1498Szrj }
34438fd1498Szrj
34538fd1498Szrj /* Verify that we have a simple 3-block CFG: the two "fake" ones, and
34638fd1498Szrj a "real" one:
34738fd1498Szrj [ENTRY] -> [block2] -> [EXIT]. */
34838fd1498Szrj
34938fd1498Szrj static void
verify_three_block_cfg(function * fun)35038fd1498Szrj verify_three_block_cfg (function *fun)
35138fd1498Szrj {
35238fd1498Szrj ASSERT_TRUE (fun->cfg != NULL);
35338fd1498Szrj ASSERT_EQ (3, n_basic_blocks_for_fn (fun));
35438fd1498Szrj ASSERT_EQ (2, n_edges_for_fn (fun));
35538fd1498Szrj
35638fd1498Szrj /* The "fake" basic blocks. */
35738fd1498Szrj basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
35838fd1498Szrj ASSERT_TRUE (entry != NULL);
35938fd1498Szrj ASSERT_EQ (ENTRY_BLOCK, entry->index);
36038fd1498Szrj
36138fd1498Szrj basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
36238fd1498Szrj ASSERT_TRUE (exit != NULL);
36338fd1498Szrj ASSERT_EQ (EXIT_BLOCK, exit->index);
36438fd1498Szrj
36538fd1498Szrj /* The "real" basic block. */
36638fd1498Szrj basic_block bb2 = get_real_block (fun);
36738fd1498Szrj ASSERT_TRUE (bb2 != NULL);
36838fd1498Szrj ASSERT_EQ (2, bb2->index);
36938fd1498Szrj
37038fd1498Szrj /* Verify connectivity. */
37138fd1498Szrj ASSERT_EQ (NULL, entry->preds);
37238fd1498Szrj ASSERT_EQ (1, entry->succs->length ());
37338fd1498Szrj
37438fd1498Szrj edge from_entry_to_bb2 = (*entry->succs)[0];
37538fd1498Szrj ASSERT_EQ (entry, from_entry_to_bb2->src);
37638fd1498Szrj ASSERT_EQ (bb2, from_entry_to_bb2->dest);
37738fd1498Szrj
37838fd1498Szrj ASSERT_EQ (1, bb2->preds->length ());
37938fd1498Szrj ASSERT_EQ (from_entry_to_bb2, (*bb2->preds)[0]);
38038fd1498Szrj ASSERT_EQ (1, bb2->succs->length ());
38138fd1498Szrj
38238fd1498Szrj edge from_bb2_to_exit = (*bb2->succs)[0];
38338fd1498Szrj ASSERT_EQ (bb2, from_bb2_to_exit->src);
38438fd1498Szrj ASSERT_EQ (exit, from_bb2_to_exit->dest);
38538fd1498Szrj
38638fd1498Szrj ASSERT_EQ (1, exit->preds->length ());
38738fd1498Szrj ASSERT_EQ (from_bb2_to_exit, (*exit->preds)[0]);
38838fd1498Szrj ASSERT_EQ (NULL, exit->succs);
38938fd1498Szrj }
39038fd1498Szrj
39138fd1498Szrj /* As above, but additionally verify the gimple statements are sane. */
39238fd1498Szrj
39338fd1498Szrj static void
verify_three_block_gimple_cfg(function * fun)39438fd1498Szrj verify_three_block_gimple_cfg (function *fun)
39538fd1498Szrj {
39638fd1498Szrj verify_three_block_cfg (fun);
39738fd1498Szrj
39838fd1498Szrj /* The "fake" basic blocks should be flagged as gimple, but with have no
39938fd1498Szrj statements. */
40038fd1498Szrj basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
40138fd1498Szrj ASSERT_TRUE (entry != NULL);
40238fd1498Szrj ASSERT_EQ (0, entry->flags & BB_RTL);
40338fd1498Szrj ASSERT_EQ (NULL, bb_seq (entry));
40438fd1498Szrj
40538fd1498Szrj basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
40638fd1498Szrj ASSERT_TRUE (exit != NULL);
40738fd1498Szrj ASSERT_EQ (0, entry->flags & BB_RTL);
40838fd1498Szrj ASSERT_EQ (NULL, bb_seq (exit));
40938fd1498Szrj
41038fd1498Szrj /* The "real" basic block should be flagged as gimple, and have one
41138fd1498Szrj or more statements. */
41238fd1498Szrj basic_block bb2 = get_real_block (fun);
41338fd1498Szrj ASSERT_TRUE (bb2 != NULL);
41438fd1498Szrj ASSERT_EQ (0, entry->flags & BB_RTL);
41538fd1498Szrj ASSERT_TRUE (bb_seq (bb2) != NULL);
41638fd1498Szrj }
41738fd1498Szrj
41838fd1498Szrj /* As above, but additionally verify the RTL insns are sane. */
41938fd1498Szrj
42038fd1498Szrj void
verify_three_block_rtl_cfg(function * fun)42138fd1498Szrj verify_three_block_rtl_cfg (function *fun)
42238fd1498Szrj {
42338fd1498Szrj verify_three_block_cfg (fun);
42438fd1498Szrj
42538fd1498Szrj /* The "fake" basic blocks should be flagged as RTL, but with no
42638fd1498Szrj insns. */
42738fd1498Szrj basic_block entry = ENTRY_BLOCK_PTR_FOR_FN (fun);
42838fd1498Szrj ASSERT_TRUE (entry != NULL);
42938fd1498Szrj ASSERT_EQ (BB_RTL, entry->flags & BB_RTL);
43038fd1498Szrj ASSERT_EQ (NULL, BB_HEAD (entry));
43138fd1498Szrj
43238fd1498Szrj basic_block exit = EXIT_BLOCK_PTR_FOR_FN (fun);
43338fd1498Szrj ASSERT_TRUE (exit != NULL);
43438fd1498Szrj ASSERT_EQ (BB_RTL, exit->flags & BB_RTL);
43538fd1498Szrj ASSERT_EQ (NULL, BB_HEAD (exit));
43638fd1498Szrj
43738fd1498Szrj /* The "real" basic block should be flagged as RTL, and have one
43838fd1498Szrj or more insns. */
43938fd1498Szrj basic_block bb2 = get_real_block (fun);
44038fd1498Szrj ASSERT_TRUE (bb2 != NULL);
44138fd1498Szrj ASSERT_EQ (BB_RTL, bb2->flags & BB_RTL);
44238fd1498Szrj ASSERT_TRUE (BB_HEAD (bb2) != NULL);
44338fd1498Szrj }
44438fd1498Szrj
44538fd1498Szrj /* Test converting our trivial function:
44638fd1498Szrj int test_fn (void) { return 42; }
44738fd1498Szrj to gimple form. */
44838fd1498Szrj
44938fd1498Szrj static void
test_gimplification()45038fd1498Szrj test_gimplification ()
45138fd1498Szrj {
45238fd1498Szrj tree fndecl = build_trivial_generic_function ();
45338fd1498Szrj
45438fd1498Szrj /* Convert to gimple: */
45538fd1498Szrj gimplify_function_tree (fndecl);
45638fd1498Szrj
45738fd1498Szrj /* Verify that we got gimple out of it. */
45838fd1498Szrj
45938fd1498Szrj /* The function is now in GIMPLE form but the CFG has not been
46038fd1498Szrj built yet. */
46138fd1498Szrj
46238fd1498Szrj /* We should have a struct function for the decl. */
46338fd1498Szrj function *fun = DECL_STRUCT_FUNCTION (fndecl);
46438fd1498Szrj ASSERT_TRUE (fun != NULL);
46538fd1498Szrj ASSERT_EQ (fndecl, fun->decl);
46638fd1498Szrj
46738fd1498Szrj /* We expect a GIMPLE_BIND, with two gimple statements within it:
46838fd1498Szrj tmp = 42;
46938fd1498Szrj return tmp; */
47038fd1498Szrj
47138fd1498Szrj gimple_seq seq_fn_body = gimple_body (fndecl);
47238fd1498Szrj ASSERT_TRUE (seq_fn_body != NULL);
47338fd1498Szrj gimple *bind_stmt = gimple_seq_first_stmt (seq_fn_body);
47438fd1498Szrj ASSERT_EQ (GIMPLE_BIND, gimple_code (bind_stmt));
47538fd1498Szrj ASSERT_EQ (NULL, bind_stmt->next);
47638fd1498Szrj
47738fd1498Szrj gimple_seq seq_bind_body = gimple_bind_body (as_a <gbind *> (bind_stmt));
47838fd1498Szrj
47938fd1498Szrj /* Verify that we have the 2 statements we expect. */
48038fd1498Szrj ASSERT_TRUE (seq_bind_body != NULL);
48138fd1498Szrj gimple *stmt1 = gimple_seq_first_stmt (seq_bind_body);
48238fd1498Szrj ASSERT_TRUE (stmt1 != NULL);
48338fd1498Szrj ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt1));
48438fd1498Szrj gimple *stmt2 = stmt1->next;
48538fd1498Szrj ASSERT_TRUE (stmt2 != NULL);
48638fd1498Szrj ASSERT_EQ (stmt1, stmt2->prev);
48738fd1498Szrj ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt2));
48838fd1498Szrj }
48938fd1498Szrj
49038fd1498Szrj /* Test of building a CFG for a function in high gimple form. */
49138fd1498Szrj
49238fd1498Szrj static void
test_building_cfg()49338fd1498Szrj test_building_cfg ()
49438fd1498Szrj {
49538fd1498Szrj /* Construct a trivial function, and gimplify it: */
49638fd1498Szrj tree fndecl = build_trivial_high_gimple_function ();
49738fd1498Szrj function *fun = DECL_STRUCT_FUNCTION (fndecl);
49838fd1498Szrj ASSERT_TRUE (fun != NULL);
49938fd1498Szrj
50038fd1498Szrj /* Build a CFG. */
50138fd1498Szrj build_cfg (fndecl);
50238fd1498Szrj
50338fd1498Szrj /* The CFG-building code constructs a 4-block cfg (with
50438fd1498Szrj ENTRY and EXIT):
50538fd1498Szrj test_fn ()
50638fd1498Szrj {
50738fd1498Szrj <bb 2>:
50838fd1498Szrj D.65 = 42;
50938fd1498Szrj
51038fd1498Szrj <bb 3>:
51138fd1498Szrj return D.65;
51238fd1498Szrj }
51338fd1498Szrj and then ought to merge blocks 2 and 3 in cleanup_tree_cfg.
51438fd1498Szrj
51538fd1498Szrj Hence we should end up with a simple 3-block cfg, the two "fake" ones,
51638fd1498Szrj and a "real" one:
51738fd1498Szrj [ENTRY] -> [block2] -> [EXIT]
51838fd1498Szrj with code like this:
51938fd1498Szrj test_fn ()
52038fd1498Szrj {
52138fd1498Szrj <bb 2>:
52238fd1498Szrj D.56 = 42;
52338fd1498Szrj return D.56;
52438fd1498Szrj }
52538fd1498Szrj */
52638fd1498Szrj verify_three_block_gimple_cfg (fun);
52738fd1498Szrj
52838fd1498Szrj /* Verify the statements within the "real" block. */
52938fd1498Szrj basic_block bb2 = get_real_block (fun);
53038fd1498Szrj gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
53138fd1498Szrj ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
53238fd1498Szrj gimple *stmt_b = stmt_a->next;
53338fd1498Szrj ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
53438fd1498Szrj ASSERT_EQ (NULL, stmt_b->next);
53538fd1498Szrj }
53638fd1498Szrj
53738fd1498Szrj /* Test of conversion of gimple to SSA form. */
53838fd1498Szrj
53938fd1498Szrj static void
test_conversion_to_ssa()54038fd1498Szrj test_conversion_to_ssa ()
54138fd1498Szrj {
54238fd1498Szrj /* As above, construct a trivial function, gimplify it, and build a CFG: */
54338fd1498Szrj tree fndecl = build_trivial_high_gimple_function ();
54438fd1498Szrj function *fun = DECL_STRUCT_FUNCTION (fndecl);
54538fd1498Szrj ASSERT_TRUE (fun != NULL);
54638fd1498Szrj build_cfg (fndecl);
54738fd1498Szrj
54838fd1498Szrj convert_to_ssa (fndecl);
54938fd1498Szrj
55038fd1498Szrj verify_three_block_gimple_cfg (fun);
55138fd1498Szrj
55238fd1498Szrj /* For out trivial test function we should now have something like
55338fd1498Szrj this:
55438fd1498Szrj test_fn ()
55538fd1498Szrj {
55638fd1498Szrj <bb 2>:
55738fd1498Szrj _1 = 42;
55838fd1498Szrj return _1;
55938fd1498Szrj }
56038fd1498Szrj */
56138fd1498Szrj basic_block bb2 = get_real_block (fun);
56238fd1498Szrj gimple *stmt_a = gimple_seq_first_stmt (bb_seq (bb2));
56338fd1498Szrj ASSERT_EQ (GIMPLE_ASSIGN, gimple_code (stmt_a));
56438fd1498Szrj
56538fd1498Szrj gimple *stmt_b = stmt_a->next;
56638fd1498Szrj ASSERT_EQ (GIMPLE_RETURN, gimple_code (stmt_b));
56738fd1498Szrj ASSERT_EQ (NULL, stmt_b->next);
56838fd1498Szrj
56938fd1498Szrj greturn *return_stmt = as_a <greturn *> (stmt_b);
57038fd1498Szrj ASSERT_EQ (SSA_NAME, TREE_CODE (gimple_return_retval (return_stmt)));
57138fd1498Szrj }
57238fd1498Szrj
57338fd1498Szrj /* Test of expansion from gimple-ssa to RTL. */
57438fd1498Szrj
57538fd1498Szrj static void
test_expansion_to_rtl()57638fd1498Szrj test_expansion_to_rtl ()
57738fd1498Szrj {
57838fd1498Szrj /* As above, construct a trivial function, gimplify it, build a CFG,
57938fd1498Szrj and convert to SSA: */
58038fd1498Szrj tree fndecl = build_trivial_high_gimple_function ();
58138fd1498Szrj function *fun = DECL_STRUCT_FUNCTION (fndecl);
58238fd1498Szrj ASSERT_TRUE (fun != NULL);
58338fd1498Szrj build_cfg (fndecl);
58438fd1498Szrj convert_to_ssa (fndecl);
58538fd1498Szrj
58638fd1498Szrj /* We need a cgraph_node for it. */
58738fd1498Szrj cgraph_node::get_create (fndecl);
58838fd1498Szrj /* Normally, cgraph_node::expand () would call
58938fd1498Szrj init_function_start (and a bunch of other stuff),
59038fd1498Szrj and invoke the expand pass, but it also runs
59138fd1498Szrj all of the other passes. So just do the minimum
59238fd1498Szrj needed to get from gimple-SSA to RTL. */
59338fd1498Szrj rtl_opt_pass *expand_pass = make_pass_expand (g);
59438fd1498Szrj push_cfun (fun);
59538fd1498Szrj init_function_start (fndecl);
59638fd1498Szrj expand_pass->execute (fun);
59738fd1498Szrj pop_cfun ();
59838fd1498Szrj delete expand_pass;
59938fd1498Szrj
60038fd1498Szrj /* On x86_64, I get this:
60138fd1498Szrj (note 3 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
60238fd1498Szrj (note 2 3 5 2 NOTE_INSN_FUNCTION_BEG)
60338fd1498Szrj (insn 5 2 6 2 (set (reg:SI 87 [ D.59 ])
60438fd1498Szrj (const_int 42 [0x2a])) -1 (nil))
60538fd1498Szrj (insn 6 5 10 2 (set (reg:SI 88 [ <retval> ])
60638fd1498Szrj (reg:SI 87 [ D.59 ])) -1 (nil))
60738fd1498Szrj (insn 10 6 11 2 (set (reg/i:SI 0 ax)
60838fd1498Szrj (reg:SI 88 [ <retval> ])) -1 (nil))
60938fd1498Szrj (insn 11 10 0 2 (use (reg/i:SI 0 ax)) -1 (nil))
61038fd1498Szrj
61138fd1498Szrj On cr16-elf I get this:
61238fd1498Szrj (note 4 1 2 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
61338fd1498Szrj (insn 2 4 3 2 (set (reg:SI 24)
61438fd1498Szrj (reg/f:SI 16 virtual-incoming-args)) -1
61538fd1498Szrj (nil))
61638fd1498Szrj (note 3 2 6 2 NOTE_INSN_FUNCTION_BEG)
61738fd1498Szrj (insn 6 3 7 2 (set (reg:HI 22 [ _1 ])
61838fd1498Szrj (const_int 42 [0x2a])) -1
61938fd1498Szrj (nil))
62038fd1498Szrj (insn 7 6 11 2 (set (reg:HI 23 [ <retval> ])
62138fd1498Szrj (reg:HI 22 [ _1 ])) -1
62238fd1498Szrj (nil))
62338fd1498Szrj (insn 11 7 12 2 (set (reg/i:HI 0 r0)
62438fd1498Szrj (reg:HI 23 [ <retval> ])) -1
62538fd1498Szrj (nil))
62638fd1498Szrj (insn 12 11 0 2 (use (reg/i:HI 0 r0)) -1
62738fd1498Szrj (nil)). */
62838fd1498Szrj verify_three_block_rtl_cfg (fun);
62938fd1498Szrj
63038fd1498Szrj /* Verify as much of the RTL as we can whilst avoiding
63138fd1498Szrj target-specific behavior. */
63238fd1498Szrj basic_block bb2 = get_real_block (fun);
63338fd1498Szrj
63438fd1498Szrj /* Expect a NOTE_INSN_BASIC_BLOCK... */
63538fd1498Szrj rtx_insn *insn = BB_HEAD (bb2);
63638fd1498Szrj ASSERT_TRUE (insn != NULL);
63738fd1498Szrj ASSERT_EQ (NOTE, insn->code);
63838fd1498Szrj ASSERT_EQ (NOTE_INSN_BASIC_BLOCK, NOTE_KIND (insn));
63938fd1498Szrj ASSERT_EQ (bb2, NOTE_BASIC_BLOCK (insn));
64038fd1498Szrj
64138fd1498Szrj /* ...etc; any further checks are likely to over-specify things
64238fd1498Szrj and run us into target dependencies. */
64338fd1498Szrj
64438fd1498Szrj /* Verify that print_rtl_function is sane. */
64538fd1498Szrj named_temp_file tmp_out (".rtl");
64638fd1498Szrj FILE *outfile = fopen (tmp_out.get_filename (), "w");
64738fd1498Szrj print_rtx_function (outfile, fun, true);
64838fd1498Szrj fclose (outfile);
64938fd1498Szrj
65038fd1498Szrj char *dump = read_file (SELFTEST_LOCATION, tmp_out.get_filename ());
65138fd1498Szrj ASSERT_STR_CONTAINS (dump, "(function \"test_fn\"\n");
65238fd1498Szrj ASSERT_STR_CONTAINS (dump, " (insn-chain\n");
65338fd1498Szrj ASSERT_STR_CONTAINS (dump, " (block 2\n");
65438fd1498Szrj ASSERT_STR_CONTAINS (dump, " (edge-from entry (flags \"FALLTHRU\"))\n");
65538fd1498Szrj ASSERT_STR_CONTAINS (dump, " (cinsn "); /* ...etc. */
65638fd1498Szrj ASSERT_STR_CONTAINS (dump, " (edge-to exit (flags \"FALLTHRU\"))\n");
65738fd1498Szrj ASSERT_STR_CONTAINS (dump, " ) ;; block 2\n");
65838fd1498Szrj ASSERT_STR_CONTAINS (dump, " ) ;; insn-chain\n");
65938fd1498Szrj ASSERT_STR_CONTAINS (dump, " (crtl\n");
66038fd1498Szrj ASSERT_STR_CONTAINS (dump, " ) ;; crtl\n");
66138fd1498Szrj ASSERT_STR_CONTAINS (dump, ") ;; function \"test_fn\"\n");
66238fd1498Szrj
66338fd1498Szrj free (dump);
664*58e805e6Szrj free_after_compilation (fun);
66538fd1498Szrj }
66638fd1498Szrj
66738fd1498Szrj /* Run all of the selftests within this file. */
66838fd1498Szrj
66938fd1498Szrj void
function_tests_c_tests()67038fd1498Szrj function_tests_c_tests ()
67138fd1498Szrj {
67238fd1498Szrj test_fndecl_int_void ();
67338fd1498Szrj test_fndecl_float_intchar ();
67438fd1498Szrj test_gimplification ();
67538fd1498Szrj test_building_cfg ();
67638fd1498Szrj test_conversion_to_ssa ();
67738fd1498Szrj test_expansion_to_rtl ();
67838fd1498Szrj }
67938fd1498Szrj
68038fd1498Szrj } // namespace selftest
68138fd1498Szrj
68238fd1498Szrj #endif /* #if CHECKING_P */
683