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 *);

Reply via email to