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 <[email protected]> wrote:
> On Fri, Jul 1, 2016 at 1:57 PM, Prasad Ghangal <[email protected]>
> wrote:
>> On 29 June 2016 at 12:42, Richard Biener <[email protected]> wrote:
>>> On Tue, Jun 28, 2016 at 4:16 PM, Prasad Ghangal
>>> <[email protected]> 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
{