These are the middle-end changes and additions to the testsuite. They are pretty self-contained, I've organized the changelog entries below in areas of changes:
1) dump changes - we add a -gimple dump modifier that allows most function dumps to be directy fed back into the GIMPLE FE 2) pass manager changes to implement the startwith("pass-name") feature which implements unit-testing for GIMPLE passes 3) support for "SSA" input, a __PHI stmt that is lowered once the CFG is built, a facility to allow a specific SSA name to be allocated plus a small required change in the SSA rewriter to allow for pre-existing PHI arguments Bootstrapped and tested on x86_64-unknown-linux-gnu (together with [1/2]). I can approve all these changes myself but any comments are welcome. Thanks, Richard. 2016-10-28 Prasad Ghangal <prasad.ghan...@gmail.com> Richard Biener <rguent...@suse.de> * dumpfile.h (TDF_GIMPLE): Add. * dumpfile.c (dump_options): Add gimple. * gimple-pretty-print.c (dump_gimple_switch): Adjust dump for TDF_GIMPLE. (dump_gimple_label): Likewise. (dump_gimple_phi): Likewise. (dump_gimple_bb_header): Likewise. (dump_phi_nodes): Likewise. (pp_cfg_jump): Likewise. Pass in dump flags. (dump_implicit_edges): Adjust. * passes.c (pass_init_dump_file): Do not dump function header for TDF_GIMPLE. * tree-cfg.c (dump_function_to_file): Dump function return type and __GIMPLE keyword for TDF_GIMPLE. Change guard for dumping GIMPLE stmts. * tree-pretty-print.c (dump_decl_name): Adjust dump for TDF_GIMPLE. (dump_generic_node): Likewise. * function.h (struct function): Add pass_startwith member. * passes.c (execute_one_pass): Implement startwith. * tree-ssanames.c (make_ssa_name_fn): New argument, check for version and assign proper version for parsed ssa names. * tree-ssanames.h (make_ssa_name_fn): Add new argument to the function. * internal-fn.c (expand_PHI): New function. * internal-fn.h (expand_PHI): Declared here. * internal-fn.def: New defination for PHI. * tree-cfg.c (lower_phi_internal_fn): New function. (build_gimple_cfg): Call it. (verify_gimple_call): Condition for passing label as arg in internal function PHI. * tree-into-ssa.c (rewrite_add_phi_arguments): Handle already present PHIs with arguments. testsuite/ * gcc.dg/gimplefe-1.c: New testcase. * gcc.dg/gimplefe-2.c: Likewise. * gcc.dg/gimplefe-3.c: Likewise. * gcc.dg/gimplefe-4.c: Likewise. * gcc.dg/gimplefe-5.c: Likewise. * gcc.dg/gimplefe-6.c: Likewise. * gcc.dg/gimplefe-7.c: Likewise. * gcc.dg/gimplefe-8.c: Likewise. * gcc.dg/gimplefe-9.c: Likewise. * gcc.dg/gimplefe-10.c: Likewise. * gcc.dg/gimplefe-11.c: Likewise. * gcc.dg/gimplefe-12.c: Likewise. * gcc.dg/gimplefe-13.c: Likewise. * gcc.dg/gimplefe-14.c: Likewise. * gcc.dg/gimplefe-15.c: Likewise. * gcc.dg/gimplefe-16.c: Likewise. * gcc.dg/gimplefe-17.c: Likewise. * gcc.dg/gimplefe-18.c: Likewise. diff --git a/gcc/dumpfile.c b/gcc/dumpfile.c index 74522a6..e9483bc 100644 --- a/gcc/dumpfile.c +++ b/gcc/dumpfile.c @@ -108,13 +108,15 @@ static const struct dump_option_value_info dump_options[] = {"nouid", TDF_NOUID}, {"enumerate_locals", TDF_ENUMERATE_LOCALS}, {"scev", TDF_SCEV}, + {"gimple", TDF_GIMPLE}, {"optimized", MSG_OPTIMIZED_LOCATIONS}, {"missed", MSG_MISSED_OPTIMIZATION}, {"note", MSG_NOTE}, {"optall", MSG_ALL}, {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA | TDF_STMTADDR | TDF_GRAPH | TDF_DIAGNOSTIC | TDF_VERBOSE - | TDF_RHS_ONLY | TDF_NOUID | TDF_ENUMERATE_LOCALS | TDF_SCEV)}, + | TDF_RHS_ONLY | TDF_NOUID | TDF_ENUMERATE_LOCALS | TDF_SCEV + | TDF_GIMPLE)}, {NULL, 0} }; diff --git a/gcc/dumpfile.h b/gcc/dumpfile.h index 3f08b16..b7d70f2 100644 --- a/gcc/dumpfile.h +++ b/gcc/dumpfile.h @@ -82,9 +82,10 @@ enum tree_dump_index #define TDF_CSELIB (1 << 23) /* Dump cselib details. */ #define TDF_SCEV (1 << 24) /* Dump SCEV details. */ #define TDF_COMMENT (1 << 25) /* Dump lines with prefix ";;" */ -#define MSG_OPTIMIZED_LOCATIONS (1 << 26) /* -fopt-info optimized sources */ -#define MSG_MISSED_OPTIMIZATION (1 << 27) /* missed opportunities */ -#define MSG_NOTE (1 << 28) /* general optimization info */ +#define TDF_GIMPLE (1 << 26) /* Dump in GIMPLE FE syntax */ +#define MSG_OPTIMIZED_LOCATIONS (1 << 27) /* -fopt-info optimized sources */ +#define MSG_MISSED_OPTIMIZATION (1 << 28) /* missed opportunities */ +#define MSG_NOTE (1 << 29) /* general optimization info */ #define MSG_ALL (MSG_OPTIMIZED_LOCATIONS | MSG_MISSED_OPTIMIZATION \ | MSG_NOTE) diff --git a/gcc/function.h b/gcc/function.h index 590a490..600c6a0 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -234,6 +234,9 @@ struct GTY(()) function { /* The loops in this function. */ struct loops *x_current_loops; + /* Filled by the GIMPLE FE, pass to start compilation with. */ + char *pass_startwith; + /* The stack usage of this function. */ struct stack_usage *su; diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 10bf801..9d47f7f 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -887,7 +887,10 @@ dump_gimple_switch (pretty_printer *buffer, gswitch *gs, int spc, { pp_string (buffer, "switch ("); dump_generic_node (buffer, gimple_switch_index (gs), spc, flags, true); - pp_string (buffer, ") <"); + if (flags & TDF_GIMPLE) + pp_string (buffer, ") {"); + else + pp_string (buffer, ") <"); } for (i = 0; i < gimple_switch_num_labels (gs); i++) @@ -898,9 +901,17 @@ dump_gimple_switch (pretty_printer *buffer, gswitch *gs, int spc, pp_space (buffer); dump_generic_node (buffer, CASE_LABEL (case_label), spc, flags, false); if (i < gimple_switch_num_labels (gs) - 1) - pp_string (buffer, ", "); + { + if (flags & TDF_GIMPLE) + pp_string (buffer, "; "); + else + pp_string (buffer, ", "); + } } - pp_greater (buffer); + if (flags & TDF_GIMPLE) + pp_string (buffer, "; }"); + else + pp_greater (buffer); } @@ -956,12 +967,14 @@ dump_gimple_label (pretty_printer *buffer, glabel *gs, int spc, int flags) { tree label = gimple_label_label (gs); if (flags & TDF_RAW) - dump_gimple_fmt (buffer, spc, flags, "%G <%T>", gs, label); + dump_gimple_fmt (buffer, spc, flags, "%G <%T>", gs, label); else { dump_generic_node (buffer, label, spc, flags, false); pp_colon (buffer); } + if (flags & TDF_GIMPLE) + return; if (DECL_NONLOCAL (label)) pp_string (buffer, " [non-local]"); if ((flags & TDF_EH) && EH_LANDING_PAD_NR (label)) @@ -2033,21 +2046,44 @@ dump_gimple_phi (pretty_printer *buffer, gphi *phi, int spc, bool comment, else { dump_generic_node (buffer, lhs, spc, flags, false); - pp_string (buffer, " = PHI <"); + if (flags & TDF_GIMPLE) + pp_string (buffer, " = __PHI ("); + else + pp_string (buffer, " = PHI <"); } for (i = 0; i < gimple_phi_num_args (phi); i++) { if ((flags & TDF_LINENO) && gimple_phi_arg_has_location (phi, i)) dump_location (buffer, gimple_phi_arg_location (phi, i)); + if (flags & TDF_GIMPLE) + { + basic_block src = gimple_phi_arg_edge (phi, i)->src; + gimple *stmt = first_stmt (src); + if (!stmt || gimple_code (stmt) != GIMPLE_LABEL) + { + pp_string (buffer, "bb_"); + pp_decimal_int (buffer, src->index); + } + else + dump_generic_node (buffer, gimple_label_label (as_a <glabel *> (stmt)), 0, flags, + false); + pp_string (buffer, ": "); + } dump_generic_node (buffer, gimple_phi_arg_def (phi, i), spc, flags, false); - pp_left_paren (buffer); - pp_decimal_int (buffer, gimple_phi_arg_edge (phi, i)->src->index); - pp_right_paren (buffer); + if (! (flags & TDF_GIMPLE)) + { + pp_left_paren (buffer); + pp_decimal_int (buffer, gimple_phi_arg_edge (phi, i)->src->index); + pp_right_paren (buffer); + } if (i < gimple_phi_num_args (phi) - 1) pp_string (buffer, ", "); } - pp_greater (buffer); + if (flags & TDF_GIMPLE) + pp_string (buffer, ");"); + else + pp_greater (buffer); } @@ -2496,7 +2532,12 @@ dump_gimple_bb_header (FILE *outf, basic_block bb, int indent, int flags) { gimple *stmt = first_stmt (bb); if (!stmt || gimple_code (stmt) != GIMPLE_LABEL) - fprintf (outf, "%*s<bb %d>:\n", indent, "", bb->index); + { + if (flags & TDF_GIMPLE) + fprintf (outf, "%*sbb_%d:\n", indent, "", bb->index); + else + fprintf (outf, "%*s<bb %d>:\n", indent, "", bb->index); + } } } @@ -2529,7 +2570,8 @@ dump_phi_nodes (pretty_printer *buffer, basic_block bb, int indent, int flags) if (!virtual_operand_p (gimple_phi_result (phi)) || (flags & TDF_VOPS)) { INDENT (indent); - dump_gimple_phi (buffer, phi, indent, true, flags); + dump_gimple_phi (buffer, phi, indent, + (flags & TDF_GIMPLE) ? false : true, flags); pp_newline (buffer); } } @@ -2540,26 +2582,32 @@ dump_phi_nodes (pretty_printer *buffer, basic_block bb, int indent, int flags) to BUFFER. */ static void -pp_cfg_jump (pretty_printer *buffer, basic_block bb) +pp_cfg_jump (pretty_printer *buffer, basic_block bb, int flags) { - gimple *stmt; - - stmt = first_stmt (bb); - - pp_string (buffer, "goto <bb "); - pp_decimal_int (buffer, bb->index); - pp_greater (buffer); - if (stmt && gimple_code (stmt) == GIMPLE_LABEL) + if (flags & TDF_GIMPLE) { - pp_string (buffer, " ("); - dump_generic_node (buffer, - gimple_label_label (as_a <glabel *> (stmt)), - 0, 0, false); - pp_right_paren (buffer); + pp_string (buffer, "goto bb_"); + pp_decimal_int (buffer, bb->index); pp_semicolon (buffer); } else - pp_semicolon (buffer); + { + gimple *stmt = first_stmt (bb); + pp_string (buffer, "goto <bb "); + pp_decimal_int (buffer, bb->index); + pp_greater (buffer); + if (stmt && gimple_code (stmt) == GIMPLE_LABEL) + { + pp_string (buffer, " ("); + dump_generic_node (buffer, + gimple_label_label (as_a <glabel *> (stmt)), + 0, 0, false); + pp_right_paren (buffer); + pp_semicolon (buffer); + } + else + pp_semicolon (buffer); + } } @@ -2587,11 +2635,11 @@ dump_implicit_edges (pretty_printer *buffer, basic_block bb, int indent, extract_true_false_edges_from_block (bb, &true_edge, &false_edge); INDENT (indent + 2); - pp_cfg_jump (buffer, true_edge->dest); + pp_cfg_jump (buffer, true_edge->dest, flags); newline_and_indent (buffer, indent); pp_string (buffer, "else"); newline_and_indent (buffer, indent + 2); - pp_cfg_jump (buffer, false_edge->dest); + pp_cfg_jump (buffer, false_edge->dest, flags); pp_newline (buffer); return; } @@ -2608,7 +2656,7 @@ dump_implicit_edges (pretty_printer *buffer, basic_block bb, int indent, && e->goto_locus != UNKNOWN_LOCATION) dump_location (buffer, e->goto_locus); - pp_cfg_jump (buffer, e->dest); + pp_cfg_jump (buffer, e->dest, flags); pp_newline (buffer); } } diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index 4477697..9fcff2e 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -2438,3 +2438,9 @@ expand_internal_call (gcall *stmt) { expand_internal_call (gimple_call_internal_fn (stmt), stmt); } + +void +expand_PHI (internal_fn, gcall *) +{ + gcc_unreachable (); +} diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index 28863df..e3075be 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -169,6 +169,7 @@ DEF_INTERNAL_FN (VA_ARG, ECF_NOTHROW | ECF_LEAF, NULL) other such optimizations. The first argument distinguishes between uses. See internal-fn.h for usage. */ DEF_INTERNAL_FN (UNIQUE, ECF_NOTHROW, NULL) +DEF_INTERNAL_FN (PHI, 0, NULL) /* DIM_SIZE and DIM_POS return the size of a particular compute dimension and the executing thread's position within that diff --git a/gcc/internal-fn.h b/gcc/internal-fn.h index 4e5dbaa..672a60f 100644 --- a/gcc/internal-fn.h +++ b/gcc/internal-fn.h @@ -178,5 +178,6 @@ extern bool set_edom_supported_p (void); extern void expand_internal_call (gcall *); extern void expand_internal_call (internal_fn, gcall *); +extern void expand_PHI (internal_fn, gcall *); #endif diff --git a/gcc/passes.c b/gcc/passes.c index e78f9ed..51d0d84 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -2099,7 +2099,7 @@ pass_init_dump_file (opt_pass *pass) release_dump_file_name (); dump_file_name = dumps->get_dump_file_name (pass->static_pass_number); dumps->dump_start (pass->static_pass_number, &dump_flags); - if (dump_file && current_function_decl) + if (dump_file && current_function_decl && ! (dump_flags & TDF_GIMPLE)) dump_function_header (dump_file, current_function_decl, dump_flags); if (initializing_dump && dump_file && (dump_flags & TDF_GRAPH) @@ -2313,6 +2313,35 @@ execute_one_pass (opt_pass *pass) return false; } + /* For skipping passes until startwith pass */ + if (cfun + && cfun->pass_startwith + /* But we can't skip the lowering phase yet -- ideally we'd + drive that phase fully via properties. */ + && (cfun->curr_properties & PROP_ssa)) + { + size_t namelen = strlen (pass->name); + if (! strncmp (pass->name, cfun->pass_startwith, namelen)) + { + /* The following supports starting with the Nth invocation + of a pass (where N does not necessarily is equal to the + dump file suffix). */ + if (cfun->pass_startwith[namelen] == '\0' + || (cfun->pass_startwith[namelen] == '1' + && cfun->pass_startwith[namelen + 1] == '\0')) + cfun->pass_startwith = NULL; + else + { + if (cfun->pass_startwith[namelen + 1] != '\0') + return true; + --cfun->pass_startwith[namelen]; + return true; + } + } + else + return true; + } + /* Pass execution event trigger: useful to identify passes being executed. */ invoke_plugin_callbacks (PLUGIN_PASS_EXECUTION, pass); @@ -2428,7 +2457,7 @@ execute_pass_list_1 (opt_pass *pass) if (cfun == NULL) return; if (execute_one_pass (pass) && pass->sub) - execute_pass_list_1 (pass->sub); + execute_pass_list_1 (pass->sub); pass = pass->next; } while (pass); diff --git a/gcc/testsuite/gcc.dg/gimplefe-1.c b/gcc/testsuite/gcc.dg/gimplefe-1.c new file mode 100644 index 0000000..a81ed1f --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-1.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-fgimple" } */ + +int i; +void __GIMPLE foo() +{ + i = 1; +} diff --git a/gcc/testsuite/gcc.dg/gimplefe-10.c b/gcc/testsuite/gcc.dg/gimplefe-10.c new file mode 100644 index 0000000..7f63c58 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-10.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-fgimple" } */ + +int __GIMPLE() bar(int a, int b, int c) +{ + a = 1; + b = a + 1; + c = b * 4; + return b; +} + +void __GIMPLE() foo() +{ + int a; + int b; + int c; + b = bar(a, b, c); +} diff --git a/gcc/testsuite/gcc.dg/gimplefe-11.c b/gcc/testsuite/gcc.dg/gimplefe-11.c new file mode 100644 index 0000000..e1483f4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-11.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-fgimple" } */ + +void __GIMPLE() bar(int a, int b, int c) +{ + a = 1; + b = a + 1; + c = b * 4; + return; +} + +void __GIMPLE() foo() +{ + int a; + int b; + int c; + bar(a, b, c); +} diff --git a/gcc/testsuite/gcc.dg/gimplefe-12.c b/gcc/testsuite/gcc.dg/gimplefe-12.c new file mode 100644 index 0000000..2863228 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-12.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fgimple" } */ + +void __GIMPLE (startwith ("ccp1")) foo () +{ + int a; + int b; + a = b + 2; + return; +} diff --git a/gcc/testsuite/gcc.dg/gimplefe-13.c b/gcc/testsuite/gcc.dg/gimplefe-13.c new file mode 100644 index 0000000..f0af761 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-13.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fgimple" } */ + +void __GIMPLE (startwith ("dse2")) foo () +{ + int a; + +bb_2: + if (a > 4) + goto bb_3; + else + goto bb_4; + +bb_3: + a_2 = 10; + goto bb_5; + +bb_4: + a_3 = 20; + +bb_5: + a_1 = __PHI (bb_3: a_2, bb_4: a_3); + a_4 = a_1 + 4; + +return; +} diff --git a/gcc/testsuite/gcc.dg/gimplefe-14.c b/gcc/testsuite/gcc.dg/gimplefe-14.c new file mode 100644 index 0000000..c0dd54a --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-14.c @@ -0,0 +1,29 @@ +/* { dg-do run } */ +/* { dg-options "-O -fgimple" } */ + +int __GIMPLE () +main (int argc, char * * argv) +{ + int a; + + bb_2: + switch (argc_2(D)) {default: L2; case 1: L0; case 2: L1; } + +L0: + a_4 = 0; + goto bb_6; + +L1: + a_3 = 3; + goto bb_6; + +L2: + a_5 = -1; + + bb_6: + a_1 = __PHI (L0: a_4, L1: a_3, L2: a_5); + return a_1; + +} + + diff --git a/gcc/testsuite/gcc.dg/gimplefe-15.c b/gcc/testsuite/gcc.dg/gimplefe-15.c new file mode 100644 index 0000000..ca99031 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-15.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fgimple" } */ + +struct Y { int b[2]; }; +struct X { int a; struct Y y; }; +struct X x; + +int __GIMPLE () +foo (struct X *p, _Complex int q) +{ + int b; + b = __real q; + p->a = b; + x.y.b[b] = b; + b = p->y.b[1]; + b = x.a; + return b; +} diff --git a/gcc/testsuite/gcc.dg/gimplefe-16.c b/gcc/testsuite/gcc.dg/gimplefe-16.c new file mode 100644 index 0000000..2949249 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-16.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fgimple" } */ + +struct Y { int b[2]; }; +struct X { int a; struct Y y; }; +struct X x; + +int __GIMPLE () +foo (struct X *p, _Complex int q) +{ + int b; + b_1 = __real q; + p_4(D)->a = b_1; + x.y.b[b_1] = b_1; + b_2 = p->y.b[1]; + b_3 = x.a; + return b_3; +} diff --git a/gcc/testsuite/gcc.dg/gimplefe-17.c b/gcc/testsuite/gcc.dg/gimplefe-17.c new file mode 100644 index 0000000..c5633ee --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-17.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-fgimple -fdump-tree-ssa" } */ + +int +__GIMPLE () * +foo () +{ + int _1; + int j; + int *b; + _1 = 1; +bb1: + if (_1) + goto bb3; + else + goto bb2; + +bb2: + b_2 = (int *)0; + +bb3: + b_4 = __PHI (bb1: b_3(D), bb2: b_2); + return b_4; +} + +/* { dg-final { scan-tree-dump-not "_1_" "ssa" } } */ diff --git a/gcc/testsuite/gcc.dg/gimplefe-18.c b/gcc/testsuite/gcc.dg/gimplefe-18.c new file mode 100644 index 0000000..ba918b2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-18.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-fgimple" } */ + +int +__GIMPLE () * +foo () +{ + int _1; + int j; + int *b; + _1 = 1; +bb1: + if (_1) + goto bb3; + else + goto bb2; + +bb2: + b_2 = (int *)0; + +bb3: + b_4 = __PHI (bb1: &j, bb2: b_2); + return b_4; +} diff --git a/gcc/testsuite/gcc.dg/gimplefe-2.c b/gcc/testsuite/gcc.dg/gimplefe-2.c new file mode 100644 index 0000000..e3a23cf --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-2.c @@ -0,0 +1,11 @@ +/* { dg-do compile }*/ +/* { dg-options "-fgimple" } */ + +int a; +void __GIMPLE () foo () +{ + int b; + b = a; + b = b + 1; + a = b; +} diff --git a/gcc/testsuite/gcc.dg/gimplefe-3.c b/gcc/testsuite/gcc.dg/gimplefe-3.c new file mode 100644 index 0000000..595365e --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-3.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-fgimple" } */ + +void __GIMPLE () foo () +{ + int *b; + *b = 1; +} diff --git a/gcc/testsuite/gcc.dg/gimplefe-4.c b/gcc/testsuite/gcc.dg/gimplefe-4.c new file mode 100644 index 0000000..3600c7c --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-4.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-fgimple" } */ + +void __GIMPLE () foo () +{ + int a; + char b; + a = (int) b; + return; +} diff --git a/gcc/testsuite/gcc.dg/gimplefe-5.c b/gcc/testsuite/gcc.dg/gimplefe-5.c new file mode 100644 index 0000000..1dab4af --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-5.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-fgimple" } */ + +int a; +void __GIMPLE () foo () +{ + int b; + int c; + +bb_2: + b = a; + if (b > 3) + goto bb_3; + else + goto bb_4; + +bb_3: + b = c + 4; + goto bb_5; + +bb_4: + b = b + 1; + goto bb_5; + +bb_5: + a = b; + return; +} diff --git a/gcc/testsuite/gcc.dg/gimplefe-6.c b/gcc/testsuite/gcc.dg/gimplefe-6.c new file mode 100644 index 0000000..242e08f --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-6.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-fgimple" } */ + +void __GIMPLE () foo () +{ + int a; + int b; + int c; + int d; + +bb_2: + a = ~b; + b = a << c; + c = a & b; + d = b | c; + +bb_3: + return; +} diff --git a/gcc/testsuite/gcc.dg/gimplefe-7.c b/gcc/testsuite/gcc.dg/gimplefe-7.c new file mode 100644 index 0000000..6125541 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-7.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-fgimple" } */ + +void __GIMPLE () foo () +{ + int a; + +bb_2: + if (a > 4) + goto bb_3; + else + goto bb_4; + +bb_3: + a_2 = 10; + goto bb_5; + +bb_4: + a_3 = 20; + +bb_5: + a_1 = __PHI (bb_3: a_2, bb_4: a_3); + a_4 = a_1 + 4; + +return; +} + diff --git a/gcc/testsuite/gcc.dg/gimplefe-8.c b/gcc/testsuite/gcc.dg/gimplefe-8.c new file mode 100644 index 0000000..4936bec --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-8.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-fgimple" } */ + +int __GIMPLE () foo () +{ + int a; + int b; + +bb_2: + b = a_1(D) + 1; +bb_3: + return b; +} diff --git a/gcc/testsuite/gcc.dg/gimplefe-9.c b/gcc/testsuite/gcc.dg/gimplefe-9.c new file mode 100644 index 0000000..a24be273 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gimplefe-9.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-fgimple" } */ + +int __GIMPLE() bar() +{ + int a; + a = a + 1; + return a; +} + +void __GIMPLE() foo() +{ + int b; + b = bar(); +} diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index dfa82aa..e99e102 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -170,6 +170,7 @@ static edge find_taken_edge_computed_goto (basic_block, tree); static edge find_taken_edge_cond_expr (basic_block, tree); static edge find_taken_edge_switch_expr (gswitch *, basic_block, tree); static tree find_case_label_for_value (gswitch *, tree); +static void lower_phi_internal_fn (); void init_empty_tree_cfg_for_function (struct function *fn) @@ -244,6 +245,7 @@ build_gimple_cfg (gimple_seq seq) discriminator_per_locus = new hash_table<locus_discrim_hasher> (13); make_edges (); assign_discriminators (); + lower_phi_internal_fn (); cleanup_dead_labels (); delete discriminator_per_locus; discriminator_per_locus = NULL; @@ -345,6 +347,49 @@ replace_loop_annotate (void) } } +/* Lower internal PHI function from GIMPLE FE. */ + +static void +lower_phi_internal_fn () +{ + basic_block bb, pred = NULL; + gimple_stmt_iterator gsi; + tree lhs; + gphi *phi_node; + gimple *stmt; + + /* After edge creation, handle __PHI function from GIMPLE FE. */ + FOR_EACH_BB_FN (bb, cfun) + { + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);) + { + stmt = gsi_stmt (gsi); + if (! gimple_call_internal_p (stmt, IFN_PHI)) + { + gsi_next (&gsi); + continue; + } + + lhs = gimple_call_lhs (stmt); + phi_node = create_phi_node (lhs, bb); + + /* Add arguments to the PHI node. */ + for (unsigned i = 0; i < gimple_call_num_args (stmt); ++i) + { + tree arg = gimple_call_arg (stmt, i); + if (TREE_CODE (arg) == LABEL_DECL) + pred = label_to_block (arg); + else + { + edge e = find_edge (pred, bb); + add_phi_arg (phi_node, arg, e, UNKNOWN_LOCATION); + } + } + + gsi_remove (&gsi, true); + } + } +} static unsigned int execute_build_cfg (void) @@ -3337,6 +3382,11 @@ verify_gimple_call (gcall *stmt) debug_generic_stmt (fn); return true; } + /* FIXME : for passing label as arg in internal fn PHI from GIMPLE FE*/ + else if (gimple_call_internal_fn (stmt) == IFN_PHI) + { + return false; + } } else { @@ -7497,7 +7547,14 @@ dump_function_to_file (tree fndecl, FILE *file, int flags) } current_function_decl = fndecl; - fprintf (file, "%s %s(", function_name (fun), tmclone ? "[tm-clone] " : ""); + if (flags & TDF_GIMPLE) + { + print_generic_expr (file, TREE_TYPE (TREE_TYPE (fndecl)), + dump_flags | TDF_SLIM); + fprintf (file, " __GIMPLE ()\n%s (", function_name (fun)); + } + else + fprintf (file, "%s %s(", function_name (fun), tmclone ? "[tm-clone] " : ""); arg = DECL_ARGUMENTS (fndecl); while (arg) @@ -7609,7 +7666,7 @@ dump_function_to_file (tree fndecl, FILE *file, int flags) fprintf (file, "}\n"); } - else if (DECL_SAVED_TREE (fndecl) == NULL) + else if (fun->curr_properties & PROP_gimple_any) { /* The function is now in GIMPLE form but the CFG has not been built yet. Emit the single sequence of GIMPLE statements diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c index e5b59a7..0e78845 100644 --- a/gcc/tree-into-ssa.c +++ b/gcc/tree-into-ssa.c @@ -1378,12 +1378,20 @@ rewrite_add_phi_arguments (basic_block bb) for (gsi = gsi_start_phis (e->dest); !gsi_end_p (gsi); gsi_next (&gsi)) { - tree currdef, res; + tree currdef, res, argvar; location_t loc; phi = gsi.phi (); res = gimple_phi_result (phi); - currdef = get_reaching_def (SSA_NAME_VAR (res)); + /* If we have pre-existing PHI (via the GIMPLE FE) its args may + be different vars than existing vars and they may be constants + as well. Note the following supports partial SSA for PHI args. */ + argvar = gimple_phi_arg_def (phi, e->dest_idx); + if (argvar && ! DECL_P (argvar)) + continue; + if (!argvar) + argvar = SSA_NAME_VAR (res); + currdef = get_reaching_def (argvar); /* Virtual operand PHI args do not need a location. */ if (virtual_operand_p (res)) loc = UNKNOWN_LOCATION; diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index ebbf606..096eefd 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -257,10 +257,11 @@ dump_decl_name (pretty_printer *pp, tree node, int flags) else pp_tree_identifier (pp, DECL_NAME (node)); } + char uid_sep = (flags & TDF_GIMPLE) ? '_' : '.'; if ((flags & TDF_UID) || DECL_NAME (node) == NULL_TREE) { if (TREE_CODE (node) == LABEL_DECL && LABEL_DECL_UID (node) != -1) - pp_printf (pp, "L.%d", (int) LABEL_DECL_UID (node)); + pp_printf (pp, "L%c%d", uid_sep, (int) LABEL_DECL_UID (node)); else if (TREE_CODE (node) == DEBUG_EXPR_DECL) { if (flags & TDF_NOUID) @@ -274,7 +275,7 @@ dump_decl_name (pretty_printer *pp, tree node, int flags) if (flags & TDF_NOUID) pp_printf (pp, "%c.xxxx", c); else - pp_printf (pp, "%c.%u", c, DECL_UID (node)); + pp_printf (pp, "%c%c%u", c, uid_sep, DECL_UID (node)); } } if ((flags & TDF_ALIAS) && DECL_PT_UID (node) != DECL_UID (node)) @@ -1762,13 +1763,23 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, int flags, if (DECL_NAME (node)) dump_decl_name (pp, node, flags); else if (LABEL_DECL_UID (node) != -1) - pp_printf (pp, "<L%d>", (int) LABEL_DECL_UID (node)); + { + if (flags & TDF_GIMPLE) + pp_printf (pp, "L%d", (int) LABEL_DECL_UID (node)); + else + pp_printf (pp, "<L%d>", (int) LABEL_DECL_UID (node)); + } else { if (flags & TDF_NOUID) pp_string (pp, "<D.xxxx>"); else - pp_printf (pp, "<D.%u>", DECL_UID (node)); + { + if (flags & TDF_GIMPLE) + pp_printf (pp, "<D%u>", DECL_UID (node)); + else + pp_printf (pp, "<D.%u>", DECL_UID (node)); + } } break; @@ -2695,7 +2706,8 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, int flags, && SSA_NAME_VAR (node) && DECL_NAMELESS (SSA_NAME_VAR (node))) dump_fancy_name (pp, SSA_NAME_IDENTIFIER (node)); - else + else if (! (flags & TDF_GIMPLE) + || SSA_NAME_VAR (node)) dump_generic_node (pp, SSA_NAME_IDENTIFIER (node), spc, flags, false); } diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c index 913d142..bd5d10a 100644 --- a/gcc/tree-ssanames.c +++ b/gcc/tree-ssanames.c @@ -252,10 +252,12 @@ flush_ssaname_freelist (void) /* Return an SSA_NAME node for variable VAR defined in statement STMT in function FN. STMT may be an empty statement for artificial references (e.g., default definitions created when a variable is - used without a preceding definition). */ + used without a preceding definition). If VERISON is not zero then + allocate the SSA name with that version. */ tree -make_ssa_name_fn (struct function *fn, tree var, gimple *stmt) +make_ssa_name_fn (struct function *fn, tree var, gimple *stmt, + unsigned int version) { tree t; use_operand_p imm; @@ -265,8 +267,19 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt) || TREE_CODE (var) == RESULT_DECL || (TYPE_P (var) && is_gimple_reg_type (var))); + /* Get the specified SSA name version. */ + if (version != 0) + { + t = make_node (SSA_NAME); + SSA_NAME_VERSION (t) = version; + if (version >= SSANAMES (fn)->length ()) + vec_safe_grow_cleared (SSANAMES (fn), version + 1); + gcc_assert ((*SSANAMES (fn))[version] == NULL); + (*SSANAMES (fn))[version] = t; + ssa_name_nodes_created++; + } /* If our free list has an element, then use it. */ - if (!vec_safe_is_empty (FREE_SSANAMES (fn))) + else if (!vec_safe_is_empty (FREE_SSANAMES (fn))) { t = FREE_SSANAMES (fn)->pop (); ssa_name_nodes_reused++; diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h index d39cc9d..57e887e 100644 --- a/gcc/tree-ssanames.h +++ b/gcc/tree-ssanames.h @@ -78,7 +78,8 @@ extern bool ssa_name_has_boolean_range (tree); extern void init_ssanames (struct function *, int); extern void fini_ssanames (struct function *); extern void ssanames_print_statistics (void); -extern tree make_ssa_name_fn (struct function *, tree, gimple *); +extern tree make_ssa_name_fn (struct function *, tree, gimple *, + unsigned int version = 0); extern void release_ssa_name_fn (struct function *, tree); extern bool get_ptr_info_alignment (struct ptr_info_def *, unsigned int *, unsigned int *);