In this patch, I am passing labels and vars with internal function and handling them in tree-cfg for parsing PHI. For first label, label_to_block() gives correct basic block and I am getting proper edges but for other labels the function is giving NULL.
test-case : void __GIMPLE () foo() { int a; int a_2; int a_3; int a_1; bb_2: a_2 = 3; goto bb_4; bb_3: a_3 = 6; goto bb_4; bb_4: a_1 = __PHI (bb_2: a_2, bb_3: a_3); a_1 = a_1 + 1; return; } On 1 July 2016 at 17:33, Richard Biener <richard.guent...@gmail.com> wrote: > On Fri, Jul 1, 2016 at 1:57 PM, Prasad Ghangal <prasad.ghan...@gmail.com> > wrote: >> On 29 June 2016 at 12:42, Richard Biener <richard.guent...@gmail.com> wrote: >>> On Tue, Jun 28, 2016 at 4:16 PM, Prasad Ghangal >>> <prasad.ghan...@gmail.com> wrote: >>>> Hi, >>>> >>>> For handling PHI, it expects cfg to be built before. So I was >>>> wondering how are we going to handle this? Do we need to build cfg >>>> while parsing only? >>> >>> For handling PHIs we need to have a CFG in the sense that the GIMPLE PHI >>> data structures are built in a way to have the PHI argument index correspond >>> to CFG predecessor edge index. As we'd like to parse phis with args >>> corresponding >>> to predecessor block labels, like >>> >>> a: >>> i_1 = 1; >>> goto p; >>> >>> b: >>> i_2 = 2; >>> goto p; >>> >>> p: >>> i_3 = __PHI (a: i_1, b: i_2); >>> >>> I think that a possibility is to leave those PHIs as internal function >>> with label / arg >>> pairs and have CFG construction lower them to real PHIs. >>> >>> Of course the parser could as well build a CFG on its own but I think >>> we should use >>> the easy way out for now. >>> >>> Thus you'd have to modify CFG construction a bit to lower the internal >>> function calls. >> >> Currently I am just building internal call using >> gimple_build_call_internal_vec (), and detecting (and removing for >> now) it after edge creation in tree-cfg. I was observing >> internal-fn.def, do I need to make entry in internal-fn.def and write >> expand function? > > You should add an entry and a stub expand function (like those > others that simply have gcc_unreachable in them). > > Richard. > >>> >>> Richard. >>>> >>>> >>>> >>>> Thanks, >>>> Prasad
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index f2e62ca..138ca4f 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -512,6 +512,7 @@ const struct c_common_resword c_common_reswords[] = { "__volatile", RID_VOLATILE, 0 }, { "__volatile__", RID_VOLATILE, 0 }, { "__GIMPLE", RID_GIMPLE, D_CONLY }, + { "__PHI", RID_PHI, D_CONLY}, { "alignas", RID_ALIGNAS, D_CXXONLY | D_CXX11 | D_CXXWARN }, { "alignof", RID_ALIGNOF, D_CXXONLY | D_CXX11 | D_CXXWARN }, { "asm", RID_ASM, D_ASM }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 23a401d..ede3549 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -107,6 +107,9 @@ enum rid /* "__GIMPLE", for the GIMPLE-parsing extension to the C frontend. */ RID_GIMPLE, + /* "__PHI", for parsing PHI function in GIMPLE FE */ + RID_PHI, + /* C11 */ RID_ALIGNAS, RID_GENERIC, diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index d8e7ba9..fffe7ea 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -18338,6 +18338,57 @@ c_parser_gimple_expression (c_parser *parser, gimple_seq *seq) return; } + if (c_parser_next_token_is_keyword (parser, RID_PHI)) + { + c_parser_consume_token (parser); + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + return; + } + + gcall *call_stmt; + /* Gimplify internal functions. */ + tree arg; + vec<tree> vargs = vNULL; + + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + c_parser_consume_token (parser); + + while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + { + if (c_parser_next_token_is (parser, CPP_NAME) && + c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + arg = lookup_label_for_goto (c_parser_peek_token (parser)->location, + c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + + if (c_parser_next_token_is (parser, CPP_COLON)) + c_parser_consume_token (parser); + vargs.safe_push (arg); + } + else if (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + } + else + { + arg = c_parser_gimple_unary_expression (parser).value; + vargs.safe_push (arg); + } + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + + call_stmt = gimple_build_call_internal_vec (IFN_PHI, vargs); + gimple_call_set_lhs (call_stmt, lhs.value); + gimple_set_location (call_stmt, UNKNOWN_LOCATION); + gimple_seq_add_stmt (seq, call_stmt); + return; + } + exp_location = c_parser_peek_token (parser)->location; rhs = c_parser_gimple_binary_expression (parser, &subcode); rhs = convert_lvalue_to_rvalue (exp_location, rhs, true, true); diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index c867ddc..eefa4e4 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -2361,3 +2361,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 e729d85..c385ab0 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 bb31465..9c39dd67 100644 --- a/gcc/internal-fn.h +++ b/gcc/internal-fn.h @@ -174,5 +174,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/tree-cfg.c b/gcc/tree-cfg.c index 7fc24ba..620372c 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -169,6 +169,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) @@ -344,6 +345,50 @@ replace_loop_annotate (void) } } +/* Lower internal PHI function from GIMPLE FE */ +static void +lower_phi_internal_fn () +{ + basic_block bb, pred; + gimple_stmt_iterator gsi; + tree lhs; + gphi *phi_node; + gimple *stmt; + int len, capacity; + /* 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); gsi_next (&gsi)) + { + stmt = gsi_stmt (gsi); + if (gimple_code (stmt) != GIMPLE_CALL) + continue; + + if (gimple_call_internal_p (stmt) && gimple_call_internal_fn (stmt) == IFN_PHI) + { + gsi_remove (&gsi, true); + int i; + lhs = gimple_call_lhs (stmt); + + phi_node = create_phi_node (lhs, bb); + + for (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_replace (&gsi, phi_node, true); + } + } + } +} static unsigned int execute_build_cfg (void) @@ -360,6 +405,7 @@ execute_build_cfg (void) cleanup_tree_cfg (); loop_optimizer_init (AVOID_CFG_MODIFICATIONS); replace_loop_annotate (); + lower_phi_internal_fn (); return 0; } @@ -3339,6 +3385,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 {