public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH][RFC] Teach GIMPLE FE to build proper CFG + SSA (+ loops)
@ 2019-03-12 19:59 Richard Biener
  2019-03-13  7:23 ` Bin.Cheng
  0 siblings, 1 reply; 5+ messages in thread
From: Richard Biener @ 2019-03-12 19:59 UTC (permalink / raw)
  To: gcc-patches


This makes an attempt at fixing the most annoying parts of the GIMPLE
FE unit testing - the lack of proper CFG preservation and hoops you
need to jump through to make the CFG and SSA builders happy.

Due to this the __GIMPLE specifiers takes two new flags, "cfg"
for GIMPLE-with-a-CFG and "ssa" for GIMPLE-with-a-CFG-and-SSA.
When there is a CFG you need to start basic-block boundaries with

__BB(index):

where 'index' is the basic-block index.  That implicitely defines
a label __BBindex for use in goto stmts and friends (but doesn't
actually add a GIMPLE_LABEL).

The parsing code isn't defensive right now so you need to watch
out to not use index 0 or 1 (entry and exit block) which are
only implicitely present.

As a proof of concept I added one BB annotation - loop_header(num)
where "num" is the loop number.  This means you can now also
have loop structures preserved (to some extent - the loop tree is
not explicitely represented nor are loop fathers, both are re-built
via fixup).

I've not yet adjusted -gimple dumping.

I've adjusted all testcases I could find.

The CFG build inside the frontend is a bit awkward (spread out...),
likewise some functionality is asking for split-out.

This is mainly a RFC for whether you think this is forward looking
enough.  Future enhancements would include EH and abnormal edges
via stmt annotations:

__BB(2):
  foo () goto __BB3 __EDGE_EH; // EH edge to BB3

__BB(3):
  setjmp () goto __BB4 __EDGE_AB; // abnormal edge to BB4

__BB(4):
  _1 = _5 / 0. __NOTHROW; // gimple_nothrow_p is true
  _3 = _2 / _4 goto __BB5 __EDGE_EH; // EH edge to BB5

etc.  extra edge flags:

  goto __BB5 __EDGE_EXECUTABLE;

I guess now is the time for bike-shedding.

Richard.

2019-03-12  Richard Biener  <rguenther@suse.de>

	c/
	* c-tree.h (enum c_declspec_il): New.
	(struct c_declspecs): Merge gimple_p and rtl_p into declspec_il
	enum bitfield.
	* c-parser.c (c_parser_declaration_or_fndef): Adjust accordingly.
	Pass start pass and declspec_il to c_parser_parse_gimple_body.
	(c_parser_declspecs): Adjust.
	* gimple-parser.c: Include cfg.h, cfghooks.h, cfganal.h, tree-cfg.h,
	gimple-iterator.h, cfgloop.h, tree-phinodes.h, tree-into-ssa.h
	and bitmap.h.
	(struct gimple_parser_edge): New.
	(edges, current_bb): New globals.
	(c_parser_gimple_parse_bb_spec): New helper.
	(c_parser_parse_gimple_body): Get start pass and IL specification.
	Initialize SSA and CFG.
	(c_parser_gimple_compound_statement): Handle CFG build.
	(c_parser_gimple_statement): Change intermittend __PHI internal
	function arg.
	(c_parser_gimple_or_rtl_pass_list): Handle ssa, cfg flags.
	(c_parser_gimple_goto_stmt): Record edges to build.
	(c_parser_gimple_if_stmt): Likewise.
	* gimple-parser.h (c_parser_parse_gimple_body): Adjust.
	(c_parser_gimple_or_rtl_pass_list): Likewise.

	* gcc.dg/gimplefe-13.c: Adjust.
	...

Index: gcc/c/c-parser.c
===================================================================
--- gcc/c/c-parser.c	(revision 269604)
+++ gcc/c/c-parser.c	(working copy)
@@ -2324,19 +2324,9 @@ c_parser_declaration_or_fndef (c_parser
       DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
 	= c_parser_peek_token (parser)->location;
 
-      /* If the definition was marked with __GIMPLE then parse the
-         function body as GIMPLE.  */
-      if (specs->gimple_p)
-	{
-	  cfun->pass_startwith = specs->gimple_or_rtl_pass;
-	  bool saved = in_late_binary_op;
-	  in_late_binary_op = true;
-	  c_parser_parse_gimple_body (parser);
-	  in_late_binary_op = saved;
-	}
-      /* Similarly, if it was marked with __RTL, use the RTL parser now,
+      /* If the definition was marked with __RTL, use the RTL parser now,
 	 consuming the function body.  */
-      else if (specs->rtl_p)
+      if (specs->declspec_il == cdil_rtl)
 	{
 	  c_parser_parse_rtl_body (parser, specs->gimple_or_rtl_pass);
 
@@ -2350,6 +2340,16 @@ c_parser_declaration_or_fndef (c_parser
 	  finish_function ();
 	  return;
 	}
+      /* If the definition was marked with __GIMPLE then parse the
+         function body as GIMPLE.  */
+      else if (specs->declspec_il != cdil_none)
+	{
+	  bool saved = in_late_binary_op;
+	  in_late_binary_op = true;
+	  c_parser_parse_gimple_body (parser, specs->gimple_or_rtl_pass,
+				      specs->declspec_il);
+	  in_late_binary_op = saved;
+	}
       else
 	fnbody = c_parser_compound_statement (parser);
       tree fndecl = current_function_decl;
@@ -2372,8 +2372,8 @@ c_parser_declaration_or_fndef (c_parser
 	    add_stmt (fnbody);
 	  finish_function ();
 	}
-      /* Get rid of the empty stmt list for GIMPLE.  */
-      if (specs->gimple_p)
+      /* Get rid of the empty stmt list for GIMPLE/RTL.  */
+      if (specs->declspec_il != cdil_none)
 	DECL_SAVED_TREE (fndecl) = NULL_TREE;
 
       break;
@@ -2882,15 +2882,15 @@ c_parser_declspecs (c_parser *parser, st
 	  if (! flag_gimple)
 	    error_at (loc, "%<__GIMPLE%> only valid with %<-fgimple%>");
 	  c_parser_consume_token (parser);
-	  specs->gimple_p = true;
+	  specs->declspec_il = cdil_gimple;
 	  specs->locations[cdw_gimple] = loc;
-	  specs->gimple_or_rtl_pass = c_parser_gimple_or_rtl_pass_list (parser);
+	  c_parser_gimple_or_rtl_pass_list (parser, specs);
 	  break;
 	case RID_RTL:
 	  c_parser_consume_token (parser);
-	  specs->rtl_p = true;
+	  specs->declspec_il = cdil_rtl;
 	  specs->locations[cdw_rtl] = loc;
-	  specs->gimple_or_rtl_pass = c_parser_gimple_or_rtl_pass_list (parser);
+	  c_parser_gimple_or_rtl_pass_list (parser, specs);
 	  break;
 	default:
 	  goto out;
Index: gcc/c/c-tree.h
===================================================================
--- gcc/c/c-tree.h	(revision 269604)
+++ gcc/c/c-tree.h	(working copy)
@@ -288,6 +288,14 @@ enum c_declspec_word {
 			    enumerator.  */
 };
 
+enum c_declspec_il {
+  cdil_none,
+  cdil_gimple,		/* __GIMPLE  */
+  cdil_gimple_cfg,	/* __GIMPLE(cfg)  */
+  cdil_gimple_ssa,	/* __GIMPLE(ssa)  */
+  cdil_rtl		/* __RTL  */
+};
+
 /* A sequence of declaration specifiers in C.  When a new declaration
    specifier is added, please update the enum c_declspec_word above
    accordingly.  */
@@ -326,6 +334,7 @@ struct c_declspecs {
   /* The kind of type specifier if one has been seen, ctsk_none
      otherwise.  */
   ENUM_BITFIELD (c_typespec_kind) typespec_kind : 3;
+  ENUM_BITFIELD (c_declspec_il) declspec_il : 3;
   /* Whether any expressions in typeof specifiers may appear in
      constant expressions.  */
   BOOL_BITFIELD expr_const_operands : 1;
@@ -381,10 +390,6 @@ struct c_declspecs {
   /* Whether any alignment specifier (even with zero alignment) was
      specified.  */
   BOOL_BITFIELD alignas_p : 1;
-  /* Whether any __GIMPLE specifier was specified.  */
-  BOOL_BITFIELD gimple_p : 1;
-  /* Whether any __RTL specifier was specified.  */
-  BOOL_BITFIELD rtl_p : 1;
   /* The address space that the declaration belongs to.  */
   addr_space_t address_space;
 };
Index: gcc/c/gimple-parser.c
===================================================================
--- gcc/c/gimple-parser.c	(revision 269604)
+++ gcc/c/gimple-parser.c	(working copy)
@@ -54,6 +54,15 @@ along with GCC; see the file COPYING3.
 #include "gimple-ssa.h"
 #include "tree-dfa.h"
 #include "internal-fn.h"
+#include "cfg.h"
+#include "cfghooks.h"
+#include "cfganal.h"
+#include "tree-cfg.h"
+#include "gimple-iterator.h"
+#include "cfgloop.h"
+#include "tree-phinodes.h"
+#include "tree-into-ssa.h"
+#include "bitmap.h"
 
 
 /* Gimple parsing functions.  */
@@ -75,11 +84,34 @@ static void c_finish_gimple_return (loca
 static tree c_parser_gimple_paren_condition (c_parser *);
 static void c_parser_gimple_expr_list (c_parser *, vec<tree> *);
 
+struct gimple_parser_edge
+{
+  gimple_parser_edge (int s, int d, int f) : src(s), dest(d), flags(f) {}
+  int src;
+  int dest;
+  int flags;
+};
+
+static vec<gimple_parser_edge> edges = vNULL;
+static basic_block current_bb;
+
+static bool
+c_parser_gimple_parse_bb_spec (tree val, int *index)
+{
+  if (strncmp (IDENTIFIER_POINTER (val), "__BB", 4) != 0)
+    return false;
+  for (const char *p = IDENTIFIER_POINTER (val) + 4; *p; ++p)
+    if (!ISDIGIT (*p))
+      return false;
+  *index = atoi (IDENTIFIER_POINTER (val) + 4);
+  return *index > 0;
+}
 
 /* Parse the body of a function declaration marked with "__GIMPLE".  */
 
 void
-c_parser_parse_gimple_body (c_parser *parser)
+c_parser_parse_gimple_body (c_parser *parser, char *gimple_pass,
+			    enum c_declspec_il cdil)
 {
   gimple_seq seq = NULL;
   gimple_seq body = NULL;
@@ -87,9 +119,34 @@ c_parser_parse_gimple_body (c_parser *pa
   push_scope ();
   location_t loc1 = c_parser_peek_token (parser)->location;
 
+  cfun->pass_startwith = gimple_pass;
   init_tree_ssa (cfun);
 
-  if (! c_parser_gimple_compound_statement (parser, &seq))
+  if (cdil == cdil_gimple)
+    /* While we have SSA names in the IL we do not have a CFG built yet
+       and PHIs are represented using a PHI internal function.  We do
+       have lowered control flow and exception handling (well, we do not
+       have parser support for EH yet).  But as we still have BINDs
+       we have to go through lowering again.  */
+    cfun->curr_properties = PROP_gimple_any;
+  else
+    {
+      /* We have at least cdil_gimple_cfg.  */
+      gimple_register_cfg_hooks ();
+      init_empty_tree_cfg ();
+      /* Initialize the bare loop structure - we are going to only
+         mark headers and leave the rest to fixup.  */
+      set_loops_for_fn (cfun, ggc_cleared_alloc<struct loops> ());
+      init_loops_structure (cfun, loops_for_fn (cfun), 1);
+      loops_state_set (cfun, LOOPS_NEED_FIXUP|LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
+      cfun->curr_properties
+	|= PROP_gimple_lcf | PROP_gimple_leh | PROP_cfg | PROP_loops;
+      if (cdil == cdil_gimple_ssa)
+	cfun->curr_properties |= PROP_ssa;
+    }
+
+  if (! c_parser_gimple_compound_statement (parser, &seq)
+      && cdil == cdil_gimple)
     {
       gimple *ret = gimple_build_return (NULL);
       gimple_seq_add_stmt (&seq, ret);
@@ -104,18 +161,90 @@ c_parser_parse_gimple_body (c_parser *pa
   BLOCK_CHAIN (block) = NULL_TREE;
   TREE_ASM_WRITTEN (block) = 1;
 
-  gbind *bind_stmt = gimple_build_bind (BIND_EXPR_VARS (stmt), NULL,
-					BIND_EXPR_BLOCK (stmt));
-  gimple_bind_set_body (bind_stmt, seq);
-  gimple_seq_add_stmt (&body, bind_stmt);
-  gimple_set_body (current_function_decl, body);
-
-  /* While we have SSA names in the IL we do not have a CFG built yet
-     and PHIs are represented using a PHI internal function.  We do
-     have lowered control flow and exception handling (well, we do not
-     have parser support for EH yet).  But as we still have BINDs
-     we have to go through lowering again.  */
-  cfun->curr_properties = PROP_gimple_any;
+  if (cdil == cdil_gimple)
+    {
+      gbind *bind_stmt = gimple_build_bind (BIND_EXPR_VARS (stmt), NULL,
+					    BIND_EXPR_BLOCK (stmt));
+      gimple_bind_set_body (bind_stmt, seq);
+      gimple_seq_add_stmt (&body, bind_stmt);
+      gimple_set_body (current_function_decl, body);
+    }
+  else
+    {
+      /* Control-flow and binds are lowered, record local decls.  */
+      for (tree var = BIND_EXPR_VARS (stmt); var; var = DECL_CHAIN (var))
+	if (VAR_P (var)
+	    && !DECL_EXTERNAL (var))
+	  add_local_decl (cfun, var);
+      /* We have a CFG.  Build the edges.  */
+      for (unsigned i = 0; i < edges.length (); ++i)
+	make_edge (BASIC_BLOCK_FOR_FN (cfun, edges[i].src),
+		   BASIC_BLOCK_FOR_FN (cfun, edges[i].dest), edges[i].flags);
+      /* Add fallthru edges and edges for case labels.
+	 Entry and exit block are already treated specially.  */
+      basic_block bb;
+      FOR_EACH_BB_FN (bb, cfun)
+	if (EDGE_COUNT (bb->succs) == 0)
+	  {
+	    gimple *last = last_stmt (bb);
+	    if (gswitch *sw = safe_dyn_cast <gswitch *> (last))
+	      for (unsigned i = 0; i < gimple_switch_num_labels (sw); ++i)
+		{
+		  basic_block label_bb = gimple_switch_label_bb (cfun, sw, i);
+		  make_edge (bb, label_bb, 0);
+		}
+	    else if (!last
+		     || !is_gimple_call (last)
+		     || !gimple_call_noreturn_p (last))
+	      make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+	  }
+      /* With SSA lower PHIs parsed as internal function calls and
+	 update stmts.  */
+      if (cdil == cdil_gimple_ssa)
+	{
+	  init_ssa_operands (cfun);
+	  FOR_EACH_BB_FN (bb, cfun)
+	    {
+	      bool phis = true;
+	      for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+		   !gsi_end_p (gsi);)
+		{
+		  gimple *stmt = gsi_stmt (gsi);
+		  if (phis && gimple_call_internal_p (stmt, IFN_PHI))
+		    {
+		      gphi *phi = create_phi_node (gimple_call_lhs (stmt), bb);
+		      for (unsigned i = 0; i < gimple_call_num_args (stmt); i += 2)
+			{
+			  int src_index;
+			  if (c_parser_gimple_parse_bb_spec (gimple_call_arg (stmt, i),
+							     &src_index))
+			    {
+			      edge e = find_edge (BASIC_BLOCK_FOR_FN (cfun, src_index),
+						  bb);
+			      if (e)
+				add_phi_arg (phi, gimple_call_arg (stmt, i + 1), e,
+					     UNKNOWN_LOCATION);
+			    }
+			}
+		      gsi_remove (&gsi, false);
+		    }
+		  else
+		    {
+		      phis = false;
+		      update_stmt (stmt);
+		      gsi_next (&gsi);
+		    }
+		}
+	    }
+	  /* No explicit virtual operands (yet).  */
+	  bitmap_obstack_initialize (NULL);
+	  update_ssa (TODO_update_ssa_only_virtuals);
+	  bitmap_obstack_release (NULL);
+	}
+      fix_loop_structure (NULL);
+    }
+  edges.release ();
+  current_bb = NULL;
 
   dump_function (TDI_gimple, current_function_decl);
 }
@@ -197,6 +326,8 @@ c_parser_gimple_compound_statement (c_pa
 	      if (! c_parser_require (parser, CPP_SEMICOLON,
 				      "expected %<;%>"))
 		return return_p;
+	      if (cfun->curr_properties & PROP_cfg)
+		make_edge (current_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
 	      break;
 	    default:
 	      goto expr_stmt;
@@ -208,6 +339,134 @@ c_parser_gimple_compound_statement (c_pa
 	      c_parser_gimple_label (parser, seq);
 	      break;
 	    }
+	  /* Basic block specification.
+	     __BB (index, ...)  */
+	  if ((cfun->curr_properties & PROP_cfg)
+	      && !strcmp (IDENTIFIER_POINTER
+			    (c_parser_peek_token (parser)->value), "__BB"))
+	    {
+	      c_parser_consume_token (parser);
+	      if (! c_parser_require (parser, CPP_OPEN_PAREN,
+				      "expected %<(%>"))
+		return return_p;
+	      if (c_parser_next_token_is_not (parser, CPP_NUMBER))
+		{
+		  c_parser_error (parser, "expected block index");
+		  return return_p;
+		}
+	      tree tnum = c_parser_peek_token (parser)->value;
+	      if (TREE_CODE (tnum) != INTEGER_CST)
+		{
+		  c_parser_error (parser, "expected block index");
+		  return return_p;
+		}
+	      int index = TREE_INT_CST_LOW (tnum);
+	      int is_loop_header_of = -1;
+	      c_parser_consume_token (parser);
+	      while (c_parser_next_token_is (parser, CPP_COMMA))
+		{
+		  c_parser_consume_token (parser);
+		  if (! c_parser_next_token_is (parser, CPP_NAME))
+		    {
+		      c_parser_error (parser, "expected block specifier");
+		      return return_p;
+		    }
+		  /* loop_header (NUM)  */
+		  if (!strcmp (IDENTIFIER_POINTER
+			         (c_parser_peek_token (parser)->value),
+			       "loop_header"))
+		    {
+		      c_parser_consume_token (parser);
+		      if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+			return return_p;
+		      tree loop_num;
+		      if (! c_parser_next_token_is (parser, CPP_NUMBER)
+			  || TREE_CODE (loop_num
+					  = c_parser_peek_token (parser)->value)
+			       != INTEGER_CST)
+			{
+			  c_parser_error (parser, "expected loop number");
+			  return return_p;
+			}
+		      c_parser_consume_token (parser);
+		      is_loop_header_of = TREE_INT_CST_LOW (loop_num);
+		      if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+			return return_p;
+		    }
+		  else
+		    {
+		      c_parser_error (parser, "unknown block specifier");
+		      return return_p;
+		    }
+		}
+	      if (! c_parser_require (parser, CPP_CLOSE_PAREN,
+				      "expected %<)%>"))
+		return return_p;
+	      if (! c_parser_require (parser, CPP_COLON,
+				      "expected %<:%>"))
+		return return_p;
+
+	      /* Put stmts parsed in the current block.  */
+	      if (!gimple_seq_empty_p (*seq))
+		{
+		  if (!current_bb)
+		    c_parser_error (parser, "stmts without block");
+		  else
+		    {
+		      gimple_stmt_iterator gsi = gsi_start_bb (current_bb);
+		      gsi_insert_seq_after_without_update (&gsi, *seq,
+							   GSI_CONTINUE_LINKING);
+		    }
+		  *seq = NULL;
+		}
+
+	      /* Build an empty block with specified index, linking them
+		 in source order.  */
+	      basic_block bb = alloc_block ();
+	      bb->index = index;
+	      link_block (bb, (current_bb ? current_bb
+			       : ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+	      if (basic_block_info_for_fn (cfun)->length () <= (size_t)index)
+		vec_safe_grow_cleared (basic_block_info_for_fn (cfun),
+				       index + 1);
+	      SET_BASIC_BLOCK_FOR_FN (cfun, index, bb);
+	      if (last_basic_block_for_fn (cfun) <= index)
+		last_basic_block_for_fn (cfun) = index + 1;
+	      n_basic_blocks_for_fn (cfun)++;
+	      if (!current_bb)
+		make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), bb, EDGE_FALLTHRU);
+
+	      /* We leave the proper setting to fixup.  */
+	      struct loop *loop_father = loops_for_fn (cfun)->tree_root;
+	      /* If the new block is a loop header, allocate a loop
+		 struct.  Fixup will take care of proper placement within
+		 the loop tree.  */
+	      if (is_loop_header_of != -1)
+		{
+		  if (number_of_loops (cfun) > (unsigned)is_loop_header_of
+		      && get_loop (cfun, is_loop_header_of) != NULL)
+		    {
+		      c_parser_error (parser, "duplicate loop header");
+		    }
+		  else
+		    {
+		      struct loop *loop = alloc_loop ();
+		      loop->num = is_loop_header_of;
+		      loop->header = bb;
+		      vec_safe_grow_cleared (loops_for_fn (cfun)->larray,
+					     is_loop_header_of + 1);
+		      (*loops_for_fn (cfun)->larray)[is_loop_header_of] = loop;
+		      flow_loop_tree_node_add (loops_for_fn (cfun)->tree_root,
+					       loop);
+		    }
+		  loop_father = get_loop (cfun, is_loop_header_of);
+		}
+	      bb->loop_father = loop_father;
+
+	      /* Stmts now go to the new block.  */
+	      current_bb = bb;
+	      break;
+	    }
 	  goto expr_stmt;
 
 	case CPP_SEMICOLON:
@@ -229,6 +488,22 @@ expr_stmt:
 	}
     }
   c_parser_consume_token (parser);
+
+  /* Put stmts parsed in the current block.  */
+  if ((cfun->curr_properties & PROP_cfg)
+      && !gimple_seq_empty_p (*seq))
+    {
+      if (!current_bb)
+	c_parser_error (parser, "stmts without block");
+      else
+	{
+	  gimple_stmt_iterator gsi = gsi_start_bb (current_bb);
+	  gsi_insert_seq_after_without_update (&gsi, *seq,
+					       GSI_CONTINUE_LINKING);
+	}
+      *seq = NULL;
+    }
+
   return return_p;
 }
 
@@ -373,8 +648,7 @@ c_parser_gimple_statement (c_parser *par
 	  if (c_parser_next_token_is (parser, CPP_NAME)
 	      && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
 	    {
-	      arg = lookup_label_for_goto (loc,
-					   c_parser_peek_token (parser)->value);
+	      arg = c_parser_peek_token (parser)->value;
 	      c_parser_consume_token (parser);
 
 	      if (c_parser_next_token_is (parser, CPP_COLON))
@@ -1288,48 +1562,57 @@ c_parser_gimple_label (c_parser *parser,
      startwith("pass-name")
  */
 
-char *
-c_parser_gimple_or_rtl_pass_list (c_parser *parser)
+void
+c_parser_gimple_or_rtl_pass_list (c_parser *parser, c_declspecs *specs)
 {
   char *pass = NULL;
 
   /* Accept __GIMPLE/__RTL.  */
   if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
-    return NULL;
+    return;
   c_parser_consume_token (parser);
 
-  if (c_parser_next_token_is (parser, CPP_NAME))
+  while (c_parser_next_token_is (parser, CPP_NAME))
     {
       const char *op = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
       c_parser_consume_token (parser);
       if (! strcmp (op, "startwith"))
 	{
 	  if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
-	    return NULL;
+	    return;
 	  if (c_parser_next_token_is_not (parser, CPP_STRING))
 	    {
 	      error_at (c_parser_peek_token (parser)->location,
 			"expected pass name");
-	      return NULL;
+	      return;
 	    }
 	  pass = xstrdup (TREE_STRING_POINTER
 				(c_parser_peek_token (parser)->value));
 	  c_parser_consume_token (parser);
-	  if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
-	    return NULL;
+	  if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<(%>"))
+	    return;
 	}
+      else if (specs->declspec_il != cdil_gimple)
+	/* Allow only one IL specifier and none on RTL.  */
+	;
+      else if (! strcmp (op, "cfg"))
+	specs->declspec_il = cdil_gimple_cfg;
+      else if (! strcmp (op, "ssa"))
+	specs->declspec_il = cdil_gimple_ssa;
       else
 	{
 	  error_at (c_parser_peek_token (parser)->location,
 		    "invalid operation");
-	  return NULL;
+	  return;
 	}
+     if (c_parser_next_token_is (parser, CPP_COMMA))
+       c_parser_consume_token (parser);
     }
 
   if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
-    return NULL;
+    return;
 
-  return pass;
+  specs->gimple_or_rtl_pass = pass;
 }
 
 /* Parse gimple local declaration.
@@ -1433,9 +1716,18 @@ c_parser_gimple_declaration (c_parser *p
 static void
 c_parser_gimple_goto_stmt (location_t loc, tree label, gimple_seq *seq)
 {
+  if (cfun->curr_properties & PROP_cfg)
+    {
+      int dest_index;
+      if (c_parser_gimple_parse_bb_spec (label, &dest_index))
+	{
+	  edges.safe_push (gimple_parser_edge (current_bb->index, dest_index,
+					       EDGE_FALLTHRU));
+	  return;
+	}
+    }
   tree decl = lookup_label_for_goto (loc, label);
   gimple_seq_add_stmt (seq, gimple_build_goto (decl));
-  return;
 }
 
 /* Parse a parenthesized condition.
@@ -1464,7 +1756,7 @@ c_parser_gimple_paren_condition (c_parse
 static void
 c_parser_gimple_if_stmt (c_parser *parser, gimple_seq *seq)
 {
-  tree t_label, f_label, label;
+  tree t_label = NULL_TREE, f_label = NULL_TREE, label;
   location_t loc;
   c_parser_consume_token (parser);
   tree cond = c_parser_gimple_paren_condition (parser);
@@ -1480,7 +1772,13 @@ c_parser_gimple_if_stmt (c_parser *parse
 	}
       label = c_parser_peek_token (parser)->value;
       c_parser_consume_token (parser);
-      t_label = lookup_label_for_goto (loc, label);
+      int dest_index;
+      if ((cfun->curr_properties & PROP_cfg)
+	  && c_parser_gimple_parse_bb_spec (label, &dest_index))
+	edges.safe_push (gimple_parser_edge (current_bb->index, dest_index,
+					     EDGE_TRUE_VALUE));
+      else
+	t_label = lookup_label_for_goto (loc, label);
       if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
 	return;
     }
@@ -1508,7 +1806,13 @@ c_parser_gimple_if_stmt (c_parser *parse
 	  return;
 	}
       label = c_parser_peek_token (parser)->value;
-      f_label = lookup_label_for_goto (loc, label);
+      int dest_index;
+      if ((cfun->curr_properties & PROP_cfg)
+	  && c_parser_gimple_parse_bb_spec (label, &dest_index))
+	edges.safe_push (gimple_parser_edge (current_bb->index, dest_index,
+					     EDGE_FALSE_VALUE));
+      else
+	f_label = lookup_label_for_goto (loc, label);
       c_parser_consume_token (parser);
       if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
 	return;
Index: gcc/c/gimple-parser.h
===================================================================
--- gcc/c/gimple-parser.h	(revision 269604)
+++ gcc/c/gimple-parser.h	(working copy)
@@ -21,7 +21,8 @@ along with GCC; see the file COPYING3.
 #define GCC_GIMPLE_PARSER_H
 
 /* Gimple parsing functions.  */
-extern void c_parser_parse_gimple_body (c_parser *);
-extern char *c_parser_gimple_or_rtl_pass_list (c_parser *);
+extern void c_parser_parse_gimple_body (c_parser *, char *,
+					enum c_declspec_il);
+extern void c_parser_gimple_or_rtl_pass_list (c_parser *, c_declspecs *);
 
 #endif
Index: gcc/testsuite/gcc.dg/gimplefe-13.c
===================================================================
--- gcc/testsuite/gcc.dg/gimplefe-13.c	(revision 269604)
+++ gcc/testsuite/gcc.dg/gimplefe-13.c	(working copy)
@@ -1,25 +1,25 @@
 /* { dg-do compile } */
 /* { dg-options "-O -fgimple" } */
 
-void __GIMPLE (startwith ("dse2")) foo ()
+void __GIMPLE (ssa,startwith ("dse2")) foo ()
 {
   int a;
 
-bb_2:
-  if (a > 4)
-    goto bb_3;
+__BB(2):
+  if (a_5(D) > 4)
+    goto __BB3;
   else
-    goto bb_4;
+    goto __BB4;
 
-bb_3:
+__BB(3):
   a_2 = 10;
-  goto bb_5;
+  goto __BB5;
 
-bb_4:
+__BB(4):
   a_3 = 20;
 
-bb_5:
-  a_1 = __PHI (bb_3: a_2, bb_4: a_3);
+__BB(5):
+  a_1 = __PHI (__BB3: a_2, __BB4: a_3);
   a_4 = a_1 + 4;
 
 return;
Index: gcc/testsuite/gcc.dg/gimplefe-14.c
===================================================================
--- gcc/testsuite/gcc.dg/gimplefe-14.c	(revision 269604)
+++ gcc/testsuite/gcc.dg/gimplefe-14.c	(working copy)
@@ -1,29 +1,32 @@
 /* { dg-do run } */
 /* { dg-options "-O -fgimple" } */
 
-int __GIMPLE ()
+int __GIMPLE (ssa)
 main (int argc, char * * argv)
 {
   int a;
 
-  bb_2:
+  __BB(2):
   /* Because of PR82114 we need to handle also 0 as base metal can have
      argc == 0.  */
   switch (argc_2(D)) {default: L2; case 0: L0; case 1: L0; case 2: L1; }
 
+  __BB(3):
 L0:
   a_4 = 0;
-  goto bb_6;
+  goto __BB6;
 
+  __BB(4):
 L1:
   a_3 = 3;
-  goto bb_6;
+  goto __BB6;
 
+  __BB(5):
 L2:
   a_5 = -1;
 
-  bb_6:
-  a_1 = __PHI (L0: a_4, L1: a_3, L2: a_5);
+  __BB(6):
+  a_1 = __PHI (__BB3: a_4, __BB4: a_3, __BB5: a_5);
   return a_1;
 
 }
Index: gcc/testsuite/gcc.dg/gimplefe-17.c
===================================================================
--- gcc/testsuite/gcc.dg/gimplefe-17.c	(revision 269604)
+++ gcc/testsuite/gcc.dg/gimplefe-17.c	(working copy)
@@ -1,26 +1,29 @@
 /* { dg-do compile } */
-/* { dg-options "-fgimple -fdump-tree-ssa" } */
+/* { dg-options "-fgimple -fdump-tree-fixup_cfg2" } */
 
 int 
-__GIMPLE () *
+__GIMPLE (ssa) *
 foo ()
 {
   int _1;
   int j;
   int *b;
+
+__BB(5):
   _1 = 1;
-bb1:
+
+__BB(2):
   if (_1)
-    goto bb3;
+    goto __BB4;
   else
-    goto bb2;
+    goto __BB3;
 
-bb2:
+__BB(3):
   b_2 = (int *)0;
 
-bb3:
-  b_4 = __PHI (bb1: b_3(D), bb2: b_2);
+__BB(4):
+  b_4 = __PHI (__BB2: b_3(D), __BB3: b_2);
   return b_4;
 }
 
-/* { dg-final { scan-tree-dump-not "_1_" "ssa" } } */
+/* { dg-final { scan-tree-dump-not "_1_" "fixup_cfg2" } } */
Index: gcc/testsuite/gcc.dg/gimplefe-18.c
===================================================================
--- gcc/testsuite/gcc.dg/gimplefe-18.c	(revision 269604)
+++ gcc/testsuite/gcc.dg/gimplefe-18.c	(working copy)
@@ -2,23 +2,26 @@
 /* { dg-options "-fgimple" } */
 
 int
-__GIMPLE () *
+__GIMPLE (ssa) *
 foo ()
 {
   int _1;
   int j;
   int *b;
+
+__BB(2):
   _1 = 1;
-bb1:
+
+__BB(3):
   if (_1)
-    goto bb3;
+    goto __BB5;
   else
-    goto bb2;
+    goto __BB4;
 
-bb2:
+__BB(4):
   b_2 = (int *)0;
 
-bb3:
-  b_4 = __PHI (bb1: &j, bb2: b_2);
+__BB(5):
+  b_4 = __PHI (__BB3: &j, __BB4: b_2);
   return b_4;
 }
Index: gcc/testsuite/gcc.dg/gimplefe-7.c
===================================================================
--- gcc/testsuite/gcc.dg/gimplefe-7.c	(revision 269604)
+++ gcc/testsuite/gcc.dg/gimplefe-7.c	(working copy)
@@ -1,25 +1,25 @@
 /* { dg-do compile } */
 /* { dg-options "-fgimple" } */
 
-void __GIMPLE () foo ()
+void __GIMPLE (ssa) foo ()
 {
   int a;
 
-bb_2:
-  if (a > 4)
-    goto bb_3;
+__BB(2):
+  if (a_5(D) > 4)
+    goto __BB3;
   else
-    goto bb_4;
+    goto __BB4;
 
-bb_3:
+__BB(3):
   a_2 = 10;
-  goto bb_5;
+  goto __BB5;
 
-bb_4:
+__BB(4):
   a_3 = 20;
 
-bb_5:
-  a_1 = __PHI (bb_3: a_2, bb_4: a_3);
+__BB(5):
+  a_1 = __PHI (__BB3: a_2, __BB4: a_3);
   a_4 = a_1 + 4;
 
 return;
Index: gcc/testsuite/gcc.dg/torture/pr89595.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/pr89595.c	(revision 269604)
+++ gcc/testsuite/gcc.dg/torture/pr89595.c	(working copy)
@@ -1,34 +1,38 @@
 /* { dg-do run } */
 /* { dg-additional-options "-fgimple" } */
 
+/* Go back to fix the testcase -- need SSA name on freelist...
+   (allocate all gaps & put them there?)  */
+
 int __attribute__((noipa))
 __GIMPLE(startwith("dom")) bar(int cond, int val)
 {
   int i;
 
+__BB(3):
   if (0 != 0)
-    goto bb_6;
+    goto __BB6;
   else
-    goto bb_2;
+    goto __BB2;
 
-bb_2:
+__BB(2):
   if (cond_5(D) != 0)
-    goto bb_4;
+    goto __BB4;
   else
-    goto bb_5;
+    goto __BB5;
 
-bb_4:
+__BB(4):
   i_6 = val_2(D);
   i_1 = val_2(D) > 0 ? i_6 : 0;
 
-bb_5:
-  i_3 = __PHI (bb_4: i_1, bb_2: 0);
+__BB(5):
+  i_3 = __PHI (__BB4: i_1, __BB2: 0);
   return i_3;
 
-bb_6:
+__BB(6):
   i_4 = 1;
   i_9 = 2;
-  goto bb_2;
+  goto __BB2;
 }
 
 int main()
Index: gcc/testsuite/gcc.dg/tree-ssa/cunroll-13.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/cunroll-13.c	(revision 269604)
+++ gcc/testsuite/gcc.dg/tree-ssa/cunroll-13.c	(working copy)
@@ -9,7 +9,7 @@ typedef int i32;
 
 struct a {i32 a[8];i32 b;};
 
-void __GIMPLE (startwith("fix_loops"))
+void __GIMPLE (ssa,startwith("fix_loops"))
 t (struct a * a)
 {
   i32 i;
@@ -18,37 +18,37 @@ t (struct a * a)
   i32 _9;
   i32 _11;
 
-bb_2:
+__BB(2):
   _11 = a_6(D)->a[0];
   if (_11 != _Literal (i32) 0)
-    goto bb_6;
+    goto __BB6;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_3:
+__BB(3):
   return;
 
-bb_4:
+__BB(4):
   _1 = _2 + _Literal (i32) 1;
   a_6(D)->a[i_19] = _1;
   i_8 = i_19 + _Literal (i32) 1;
   if (i_8 <= _Literal (i32) 123455)
-    goto bb_5;
+    goto __BB5;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_5:
-  i_19 = __PHI (bb_6: _Literal (i32) 1, bb_4: i_8);
+__BB(5):
+  i_19 = __PHI (__BB6: _Literal (i32) 1, __BB4: i_8);
   _2 = a_6(D)->a[i_19];
   if (_2 != _Literal (i32) 0)
-    goto bb_4;
+    goto __BB4;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_6:
+__BB(6):
   _9 = _11 + _Literal (i32) 1;
   a_6(D)->a[0] = _9;
-  goto bb_5;
+  goto __BB5;
 }
 
 /* This testcase relies on the fact that we do not eliminate the redundant test
Index: gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_1g.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_1g.c	(revision 269604)
+++ gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_1g.c	(working copy)
@@ -15,7 +15,7 @@ foo (long int * p, long int * p2, int N1
   long unsigned int _4;
   long int _5;
 
-  bb_2:
+  __BB(2):
   _1 = (long unsigned int) N1_10(D);
   _2 = _1 * 8ul;
   p_limit_12 = p_11(D) + _2;
@@ -23,59 +23,59 @@ foo (long int * p, long int * p2, int N1
   _4 = _3 * 8ul;
   p_limit2_15 = p2_14(D) + _4;
   if (p_11(D) <= p_limit_12)
-    goto bb_3;
+    goto __BB3;
   else
-    goto bb_13;
+    goto __BB13;
 
-  bb_13:
+  __BB(13):
 
-  bb_9:
-  goto bb_6;
+  __BB(9):
+  goto __BB6;
 
-  bb_3:
+  __BB(3):
   p_20 = p_11(D) + 8ul;
   p2_23 = p2_14(D) + 8ul;
   if (p_limit2_15 < p2_23)
-    goto bb_14;
+    goto __BB14;
   else
-    goto bb_7;
+    goto __BB7;
 
-  bb_14:
-  goto bb_9;
+  __BB(14):
+  goto __BB9;
 
-  bb_7:
-  goto bb_5;
+  __BB(7):
+  goto __BB5;
 
-  bb_4:
+  __BB(4):
   p_16 = p_26 + 8ul;
   p2_17 = p2_27 + 8ul;
   if (p_limit2_15 < p2_17)
-    goto bb_11;
+    goto __BB11;
   else
-    goto bb_8;
+    goto __BB8;
 
-  bb_11:
-  goto bb_6;
+  __BB(11):
+  goto __BB6;
 
-  bb_8:
+  __BB(8):
   ;
 
-  bb_5:
-  s_24 = __PHI (bb_7: 0l, bb_8: s_19);
-  p_26 = __PHI (bb_7: p_20, bb_8: p_16);
-  p2_27 = __PHI (bb_7: p2_23, bb_8: p2_17);
+  __BB(5):
+  s_24 = __PHI (__BB7: 0l, __BB8: s_19);
+  p_26 = __PHI (__BB7: p_20, __BB8: p_16);
+  p2_27 = __PHI (__BB7: p2_23, __BB8: p2_17);
   _5 = __MEM <long int> (p_26);
   s_19 = _5 + s_24;
   if (p_limit_12 >= p_26)
-    goto bb_4;
+    goto __BB4;
   else
-    goto bb_12;
+    goto __BB12;
 
-  bb_12:
+  __BB(12):
   ;
 
-  bb_6:
-  s_25 = __PHI (bb_12: s_19, bb_11: s_19, bb_9: 0l);
+  __BB(6):
+  s_25 = __PHI (__BB12: s_19, __BB11: s_19, __BB9: 0l);
   return s_25;
 }
 
Index: gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_2g.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_2g.c	(revision 269604)
+++ gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_2g.c	(working copy)
@@ -3,7 +3,7 @@
 
 /* Exit tests 'i < N1' and 'p2 > p_limit2' can be replaced, so
  * two ivs i and p2 can be eliminate.  */
-long int __GIMPLE (startwith("fix_loops"))
+long int __GIMPLE (ssa,startwith("fix_loops"))
 foo (long int * p, long int * p2, int N1, int N2)
 {
   long int s;
@@ -13,66 +13,66 @@ foo (long int * p, long int * p2, int N1
   long unsigned int _2;
   long int _3;
 
-  bb_2:
+  __BB(2):
   _1 = (long unsigned int) N2_9(D);
   _2 = _1 * 8ul;
   p_limit2_11 = p2_10(D) + _2;
   if (N1_13(D) > 0)
-    goto bb_3;
+    goto __BB3;
   else
-    goto bb_13;
+    goto __BB13;
 
-  bb_13:
+  __BB(13):
 
-  bb_9:
-  goto bb_6;
+  __BB(9):
+  goto __BB6;
 
-  bb_3:
+  __BB(3):
   p_22 = p_12(D) + 8ul;
   p2_23 = p2_10(D) + 8ul;
   if (p_limit2_11 < p2_23)
-    goto bb_14;
+    goto __BB14;
   else
-    goto bb_7;
+    goto __BB7;
 
-  bb_14:
-  goto bb_9;
+  __BB(14):
+  goto __BB9;
 
-  bb_7:
-  goto bb_5;
+  __BB(7):
+  goto __BB5;
 
-  bb_4:
+  __BB(4):
   p_14 = p_27 + 8ul;
   p2_15 = p2_28 + 8ul;
   i_16 = i_29 + 1;
   if (p_limit2_11 < p2_15)
-    goto bb_11;
+    goto __BB11;
   else
-    goto bb_8;
+    goto __BB8;
 
-  bb_11:
-  goto bb_6;
+  __BB(11):
+  goto __BB6;
 
-  bb_8:
+  __BB(8):
   ;
 
-  bb_5:
-  s_25 = __PHI (bb_7: 0l, bb_8: s_18);
-  p_27 = __PHI (bb_7: p_22, bb_8: p_14);
-  p2_28 = __PHI (bb_7: p2_23, bb_8: p2_15);
-  i_29 = __PHI (bb_7: 1, bb_8: i_16);
+  __BB(5):
+  s_25 = __PHI (__BB7: 0l, __BB8: s_18);
+  p_27 = __PHI (__BB7: p_22, __BB8: p_14);
+  p2_28 = __PHI (__BB7: p2_23, __BB8: p2_15);
+  i_29 = __PHI (__BB7: 1, __BB8: i_16);
   _3 = __MEM <long int> (p_27);
   s_18 = _3 + s_25;
   if (N1_13(D) > i_29)
-    goto bb_4;
+    goto __BB4;
   else
-    goto bb_12;
+    goto __BB12;
 
-  bb_12:
+  __BB(12):
   ;
 
-  bb_6:
-  s_26 = __PHI (bb_12: s_18, bb_11: s_18, bb_9: 0l);
+  __BB(6):
+  s_26 = __PHI (__BB12: s_18, __BB11: s_18, __BB9: 0l);
   return s_26;
 }
 
Index: gcc/testsuite/gcc.dg/tree-ssa/scev-3.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/scev-3.c	(revision 269604)
+++ gcc/testsuite/gcc.dg/tree-ssa/scev-3.c	(working copy)
@@ -4,39 +4,39 @@
 int *a_p;
 int a[1000];
 
-void __GIMPLE (startwith ("loop"))
+void __GIMPLE (ssa,startwith ("loop"))
 f (int k)
 {
   int i;
   int * _1;
 
-bb_2:
+__BB(2):
   i_5 = k_4(D);
   if (i_5 <= 999)
-    goto bb_4;
+    goto __BB4;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_3:
+__BB(3):
   return;
 
-bb_4:
+__BB(4):
   ;
 
-bb_5:
-  i_12 = __PHI (bb_6: i_9, bb_4: i_5);
+__BB(5):
+  i_12 = __PHI (__BB6: i_9, __BB4: i_5);
   _1 = &a[i_12];
   a_p = _1;
   __MEM <int[1000]> ((int *)&a)[i_12] = 100;
   i_9 = i_5 + i_12;
   if (i_9 <= 999)
-    goto bb_6;
+    goto __BB6;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_6:
+__BB(6):
   ;
-  goto bb_5;
+  goto __BB5;
 
 }
 
Index: gcc/testsuite/gcc.dg/tree-ssa/scev-4.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/scev-4.c	(revision 269604)
+++ gcc/testsuite/gcc.dg/tree-ssa/scev-4.c	(working copy)
@@ -9,39 +9,39 @@ typedef struct {
 int *a_p;
 S a[1000];
 
-void __GIMPLE (startwith ("loop"))
+void __GIMPLE (ssa, startwith ("loop"))
 f (int k)
 {
   int i;
   int * _1;
 
-bb_2:
+__BB(2):
   i_5 = k_4(D);
   if (i_5 <= 999)
-    goto bb_4;
+    goto __BB4;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_3:
+__BB(3):
   return;
 
-bb_4:
+__BB(4):
   ;
 
-bb_5:
-  i_12 = __PHI (bb_6: i_9, bb_4: i_5);
+__BB(5):
+  i_12 = __PHI (__BB6: i_9, __BB4: i_5);
   _1 = &a[i_12].y;
   a_p = _1;
   __MEM <S[1000]> ((int *)&a)[i_12].y = 100;
   i_9 = i_5 + i_12;
   if (i_9 <= 999)
-    goto bb_6;
+    goto __BB6;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_6:
+__BB(6):
   ;
-  goto bb_5;
+  goto __BB5;
 
 }
 
Index: gcc/testsuite/gcc.dg/tree-ssa/scev-5.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/scev-5.c	(revision 269604)
+++ gcc/testsuite/gcc.dg/tree-ssa/scev-5.c	(working copy)
@@ -4,39 +4,39 @@
 int *a_p;
 int a[1000];
 
-void __GIMPLE (startwith ("loop"))
+void __GIMPLE (ssa,startwith ("loop"))
 f (int k)
 {
   long long int i;
   int * _1;
 
-bb_2:
+__BB(2):
   i_5 = (long long int) k_4(D);
   if (i_5 <= 999ll)
-    goto bb_4;
+    goto __BB4;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_3:
+__BB(3):
   return;
 
-bb_4:
+__BB(4):
   ;
 
-bb_5:
-  i_12 = __PHI (bb_6: i_9, bb_4: i_5);
+__BB(5):
+  i_12 = __PHI (__BB6: i_9, __BB4: i_5);
   _1 = &a[i_12];
   a_p = _1;
   __MEM <int[1000]> ((int *)&a)[i_12] = 100;
   i_9 = i_5 + i_12;
   if (i_9 <= 999ll)
-    goto bb_6;
+    goto __BB6;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_6:
+__BB(6):
   ;
-  goto bb_5;
+  goto __BB5;
 
 }
 
Index: gcc/testsuite/gcc.dg/vect/vect-cond-arith-2.c
===================================================================
--- gcc/testsuite/gcc.dg/vect/vect-cond-arith-2.c	(revision 269604)
+++ gcc/testsuite/gcc.dg/vect/vect-cond-arith-2.c	(working copy)
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-additional-options "-fgimple -fdump-tree-optimized -ffast-math" } */
 
-double __GIMPLE (startwith("loop"))
+double __GIMPLE (ssa, startwith("loop"))
 neg_xi (double *x)
 {
   int i;
@@ -13,13 +13,13 @@ neg_xi (double *x)
   double res;
   unsigned int ivtmp;
 
- bb_1:
-  goto bb_2;
+ __BB(5):
+  goto __BB2;
 
- bb_2:
-  res_1 = __PHI (bb_1: 0.0, bb_3: res_2);
-  i_4 = __PHI (bb_1: 0, bb_3: i_5);
-  ivtmp_6 = __PHI (bb_1: 100U, bb_3: ivtmp_7);
+ __BB(2):
+  res_1 = __PHI (__BB5: 0.0, __BB3: res_2);
+  i_4 = __PHI (__BB5: 0, __BB3: i_5);
+  ivtmp_6 = __PHI (__BB5: 100U, __BB3: ivtmp_7);
   index = (long unsigned int) i_4;
   offset = index * 8UL;
   xi_ptr = x_8(D) + offset;
@@ -29,15 +29,15 @@ neg_xi (double *x)
   i_5 = i_4 + 1;
   ivtmp_7 = ivtmp_6 - 1U;
   if (ivtmp_7 != 0U)
-    goto bb_3;
+    goto __BB3;
   else
-    goto bb_4;
+    goto __BB4;
 
- bb_3:
-  goto bb_2;
+ __BB(3):
+  goto __BB2;
 
- bb_4:
-  res_3 = __PHI (bb_2: res_2);
+ __BB(4):
+  res_3 = __PHI (__BB2: res_2);
   return res_3;
 }
 
Index: gcc/testsuite/gcc.target/aarch64/sve/loop_add_6.c
===================================================================
--- gcc/testsuite/gcc.target/aarch64/sve/loop_add_6.c	(revision 269604)
+++ gcc/testsuite/gcc.target/aarch64/sve/loop_add_6.c	(working copy)
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -ftree-vectorize -fgimple -ffast-math" } */
 
-double __GIMPLE (startwith("loop"))
+double __GIMPLE (ssa, startwith("loop"))
 neg_xi (double *x)
 {
   int i;
@@ -13,13 +13,13 @@ neg_xi (double *x)
   double res;
   unsigned int ivtmp;
 
- bb_1:
-  goto bb_2;
+ __BB(5):
+  goto __BB2;
 
- bb_2:
-  res_1 = __PHI (bb_1: 0.0, bb_3: res_2);
-  i_4 = __PHI (bb_1: 0, bb_3: i_5);
-  ivtmp_6 = __PHI (bb_1: 100U, bb_3: ivtmp_7);
+ __BB(2):
+  res_1 = __PHI (__BB5: 0.0, __BB3: res_2);
+  i_4 = __PHI (__BB5: 0, __BB3: i_5);
+  ivtmp_6 = __PHI (__BB5: 100U, __BB3: ivtmp_7);
   index = (long unsigned int) i_4;
   offset = index * 8UL;
   xi_ptr = x_8(D) + offset;
@@ -29,15 +29,15 @@ neg_xi (double *x)
   i_5 = i_4 + 1;
   ivtmp_7 = ivtmp_6 - 1U;
   if (ivtmp_7 != 0U)
-    goto bb_3;
+    goto __BB3;
   else
-    goto bb_4;
+    goto __BB4;
 
- bb_3:
-  goto bb_2;
+ __BB(3):
+  goto __BB2;
 
- bb_4:
-  res_3 = __PHI (bb_2: res_2);
+ __BB(4):
+  res_3 = __PHI (__BB2: res_2);
   return res_3;
 }
 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH][RFC] Teach GIMPLE FE to build proper CFG + SSA (+ loops)
  2019-03-12 19:59 [PATCH][RFC] Teach GIMPLE FE to build proper CFG + SSA (+ loops) Richard Biener
@ 2019-03-13  7:23 ` Bin.Cheng
  2019-03-13  8:43   ` Richard Biener
  0 siblings, 1 reply; 5+ messages in thread
From: Bin.Cheng @ 2019-03-13  7:23 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches List

On Wed, Mar 13, 2019 at 3:58 AM Richard Biener <rguenther@suse.de> wrote:
>
>
> This makes an attempt at fixing the most annoying parts of the GIMPLE
> FE unit testing - the lack of proper CFG preservation and hoops you
> need to jump through to make the CFG and SSA builders happy.
>
> Due to this the __GIMPLE specifiers takes two new flags, "cfg"
> for GIMPLE-with-a-CFG and "ssa" for GIMPLE-with-a-CFG-and-SSA.
> When there is a CFG you need to start basic-block boundaries with
>
> __BB(index):
>
> where 'index' is the basic-block index.  That implicitely defines
> a label __BBindex for use in goto stmts and friends (but doesn't
> actually add a GIMPLE_LABEL).
>
> The parsing code isn't defensive right now so you need to watch
> out to not use index 0 or 1 (entry and exit block) which are
> only implicitely present.
>
> As a proof of concept I added one BB annotation - loop_header(num)
> where "num" is the loop number.  This means you can now also
> have loop structures preserved (to some extent - the loop tree is
> not explicitely represented nor are loop fathers, both are re-built
> via fixup).
>
> I've not yet adjusted -gimple dumping.
>
> I've adjusted all testcases I could find.
>
> The CFG build inside the frontend is a bit awkward (spread out...),
> likewise some functionality is asking for split-out.
>
> This is mainly a RFC for whether you think this is forward looking
> enough.  Future enhancements would include EH and abnormal edges
> via stmt annotations:
Thanks very much for doing this.  Do we have a centralized
wiki/document on the formal definition?  It would be very helpful even
it's still evolving, otherwise we would need to dig into messages for
fragmented clues.

Thanks,
bin
>
> __BB(2):
>   foo () goto __BB3 __EDGE_EH; // EH edge to BB3
>
> __BB(3):
>   setjmp () goto __BB4 __EDGE_AB; // abnormal edge to BB4
>
> __BB(4):
>   _1 = _5 / 0. __NOTHROW; // gimple_nothrow_p is true
>   _3 = _2 / _4 goto __BB5 __EDGE_EH; // EH edge to BB5
>
> etc.  extra edge flags:
>
>   goto __BB5 __EDGE_EXECUTABLE;
>
> I guess now is the time for bike-shedding.
>
> Richard.
>
> 2019-03-12  Richard Biener  <rguenther@suse.de>
>
>         c/
>         * c-tree.h (enum c_declspec_il): New.
>         (struct c_declspecs): Merge gimple_p and rtl_p into declspec_il
>         enum bitfield.
>         * c-parser.c (c_parser_declaration_or_fndef): Adjust accordingly.
>         Pass start pass and declspec_il to c_parser_parse_gimple_body.
>         (c_parser_declspecs): Adjust.
>         * gimple-parser.c: Include cfg.h, cfghooks.h, cfganal.h, tree-cfg.h,
>         gimple-iterator.h, cfgloop.h, tree-phinodes.h, tree-into-ssa.h
>         and bitmap.h.
>         (struct gimple_parser_edge): New.
>         (edges, current_bb): New globals.
>         (c_parser_gimple_parse_bb_spec): New helper.
>         (c_parser_parse_gimple_body): Get start pass and IL specification.
>         Initialize SSA and CFG.
>         (c_parser_gimple_compound_statement): Handle CFG build.
>         (c_parser_gimple_statement): Change intermittend __PHI internal
>         function arg.
>         (c_parser_gimple_or_rtl_pass_list): Handle ssa, cfg flags.
>         (c_parser_gimple_goto_stmt): Record edges to build.
>         (c_parser_gimple_if_stmt): Likewise.
>         * gimple-parser.h (c_parser_parse_gimple_body): Adjust.
>         (c_parser_gimple_or_rtl_pass_list): Likewise.
>
>         * gcc.dg/gimplefe-13.c: Adjust.
>         ...
>
> Index: gcc/c/c-parser.c
> ===================================================================
> --- gcc/c/c-parser.c    (revision 269604)
> +++ gcc/c/c-parser.c    (working copy)
> @@ -2324,19 +2324,9 @@ c_parser_declaration_or_fndef (c_parser
>        DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
>         = c_parser_peek_token (parser)->location;
>
> -      /* If the definition was marked with __GIMPLE then parse the
> -         function body as GIMPLE.  */
> -      if (specs->gimple_p)
> -       {
> -         cfun->pass_startwith = specs->gimple_or_rtl_pass;
> -         bool saved = in_late_binary_op;
> -         in_late_binary_op = true;
> -         c_parser_parse_gimple_body (parser);
> -         in_late_binary_op = saved;
> -       }
> -      /* Similarly, if it was marked with __RTL, use the RTL parser now,
> +      /* If the definition was marked with __RTL, use the RTL parser now,
>          consuming the function body.  */
> -      else if (specs->rtl_p)
> +      if (specs->declspec_il == cdil_rtl)
>         {
>           c_parser_parse_rtl_body (parser, specs->gimple_or_rtl_pass);
>
> @@ -2350,6 +2340,16 @@ c_parser_declaration_or_fndef (c_parser
>           finish_function ();
>           return;
>         }
> +      /* If the definition was marked with __GIMPLE then parse the
> +         function body as GIMPLE.  */
> +      else if (specs->declspec_il != cdil_none)
> +       {
> +         bool saved = in_late_binary_op;
> +         in_late_binary_op = true;
> +         c_parser_parse_gimple_body (parser, specs->gimple_or_rtl_pass,
> +                                     specs->declspec_il);
> +         in_late_binary_op = saved;
> +       }
>        else
>         fnbody = c_parser_compound_statement (parser);
>        tree fndecl = current_function_decl;
> @@ -2372,8 +2372,8 @@ c_parser_declaration_or_fndef (c_parser
>             add_stmt (fnbody);
>           finish_function ();
>         }
> -      /* Get rid of the empty stmt list for GIMPLE.  */
> -      if (specs->gimple_p)
> +      /* Get rid of the empty stmt list for GIMPLE/RTL.  */
> +      if (specs->declspec_il != cdil_none)
>         DECL_SAVED_TREE (fndecl) = NULL_TREE;
>
>        break;
> @@ -2882,15 +2882,15 @@ c_parser_declspecs (c_parser *parser, st
>           if (! flag_gimple)
>             error_at (loc, "%<__GIMPLE%> only valid with %<-fgimple%>");
>           c_parser_consume_token (parser);
> -         specs->gimple_p = true;
> +         specs->declspec_il = cdil_gimple;
>           specs->locations[cdw_gimple] = loc;
> -         specs->gimple_or_rtl_pass = c_parser_gimple_or_rtl_pass_list (parser);
> +         c_parser_gimple_or_rtl_pass_list (parser, specs);
>           break;
>         case RID_RTL:
>           c_parser_consume_token (parser);
> -         specs->rtl_p = true;
> +         specs->declspec_il = cdil_rtl;
>           specs->locations[cdw_rtl] = loc;
> -         specs->gimple_or_rtl_pass = c_parser_gimple_or_rtl_pass_list (parser);
> +         c_parser_gimple_or_rtl_pass_list (parser, specs);
>           break;
>         default:
>           goto out;
> Index: gcc/c/c-tree.h
> ===================================================================
> --- gcc/c/c-tree.h      (revision 269604)
> +++ gcc/c/c-tree.h      (working copy)
> @@ -288,6 +288,14 @@ enum c_declspec_word {
>                             enumerator.  */
>  };
>
> +enum c_declspec_il {
> +  cdil_none,
> +  cdil_gimple,         /* __GIMPLE  */
> +  cdil_gimple_cfg,     /* __GIMPLE(cfg)  */
> +  cdil_gimple_ssa,     /* __GIMPLE(ssa)  */
> +  cdil_rtl             /* __RTL  */
> +};
> +
>  /* A sequence of declaration specifiers in C.  When a new declaration
>     specifier is added, please update the enum c_declspec_word above
>     accordingly.  */
> @@ -326,6 +334,7 @@ struct c_declspecs {
>    /* The kind of type specifier if one has been seen, ctsk_none
>       otherwise.  */
>    ENUM_BITFIELD (c_typespec_kind) typespec_kind : 3;
> +  ENUM_BITFIELD (c_declspec_il) declspec_il : 3;
>    /* Whether any expressions in typeof specifiers may appear in
>       constant expressions.  */
>    BOOL_BITFIELD expr_const_operands : 1;
> @@ -381,10 +390,6 @@ struct c_declspecs {
>    /* Whether any alignment specifier (even with zero alignment) was
>       specified.  */
>    BOOL_BITFIELD alignas_p : 1;
> -  /* Whether any __GIMPLE specifier was specified.  */
> -  BOOL_BITFIELD gimple_p : 1;
> -  /* Whether any __RTL specifier was specified.  */
> -  BOOL_BITFIELD rtl_p : 1;
>    /* The address space that the declaration belongs to.  */
>    addr_space_t address_space;
>  };
> Index: gcc/c/gimple-parser.c
> ===================================================================
> --- gcc/c/gimple-parser.c       (revision 269604)
> +++ gcc/c/gimple-parser.c       (working copy)
> @@ -54,6 +54,15 @@ along with GCC; see the file COPYING3.
>  #include "gimple-ssa.h"
>  #include "tree-dfa.h"
>  #include "internal-fn.h"
> +#include "cfg.h"
> +#include "cfghooks.h"
> +#include "cfganal.h"
> +#include "tree-cfg.h"
> +#include "gimple-iterator.h"
> +#include "cfgloop.h"
> +#include "tree-phinodes.h"
> +#include "tree-into-ssa.h"
> +#include "bitmap.h"
>
>
>  /* Gimple parsing functions.  */
> @@ -75,11 +84,34 @@ static void c_finish_gimple_return (loca
>  static tree c_parser_gimple_paren_condition (c_parser *);
>  static void c_parser_gimple_expr_list (c_parser *, vec<tree> *);
>
> +struct gimple_parser_edge
> +{
> +  gimple_parser_edge (int s, int d, int f) : src(s), dest(d), flags(f) {}
> +  int src;
> +  int dest;
> +  int flags;
> +};
> +
> +static vec<gimple_parser_edge> edges = vNULL;
> +static basic_block current_bb;
> +
> +static bool
> +c_parser_gimple_parse_bb_spec (tree val, int *index)
> +{
> +  if (strncmp (IDENTIFIER_POINTER (val), "__BB", 4) != 0)
> +    return false;
> +  for (const char *p = IDENTIFIER_POINTER (val) + 4; *p; ++p)
> +    if (!ISDIGIT (*p))
> +      return false;
> +  *index = atoi (IDENTIFIER_POINTER (val) + 4);
> +  return *index > 0;
> +}
>
>  /* Parse the body of a function declaration marked with "__GIMPLE".  */
>
>  void
> -c_parser_parse_gimple_body (c_parser *parser)
> +c_parser_parse_gimple_body (c_parser *parser, char *gimple_pass,
> +                           enum c_declspec_il cdil)
>  {
>    gimple_seq seq = NULL;
>    gimple_seq body = NULL;
> @@ -87,9 +119,34 @@ c_parser_parse_gimple_body (c_parser *pa
>    push_scope ();
>    location_t loc1 = c_parser_peek_token (parser)->location;
>
> +  cfun->pass_startwith = gimple_pass;
>    init_tree_ssa (cfun);
>
> -  if (! c_parser_gimple_compound_statement (parser, &seq))
> +  if (cdil == cdil_gimple)
> +    /* While we have SSA names in the IL we do not have a CFG built yet
> +       and PHIs are represented using a PHI internal function.  We do
> +       have lowered control flow and exception handling (well, we do not
> +       have parser support for EH yet).  But as we still have BINDs
> +       we have to go through lowering again.  */
> +    cfun->curr_properties = PROP_gimple_any;
> +  else
> +    {
> +      /* We have at least cdil_gimple_cfg.  */
> +      gimple_register_cfg_hooks ();
> +      init_empty_tree_cfg ();
> +      /* Initialize the bare loop structure - we are going to only
> +         mark headers and leave the rest to fixup.  */
> +      set_loops_for_fn (cfun, ggc_cleared_alloc<struct loops> ());
> +      init_loops_structure (cfun, loops_for_fn (cfun), 1);
> +      loops_state_set (cfun, LOOPS_NEED_FIXUP|LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
> +      cfun->curr_properties
> +       |= PROP_gimple_lcf | PROP_gimple_leh | PROP_cfg | PROP_loops;
> +      if (cdil == cdil_gimple_ssa)
> +       cfun->curr_properties |= PROP_ssa;
> +    }
> +
> +  if (! c_parser_gimple_compound_statement (parser, &seq)
> +      && cdil == cdil_gimple)
>      {
>        gimple *ret = gimple_build_return (NULL);
>        gimple_seq_add_stmt (&seq, ret);
> @@ -104,18 +161,90 @@ c_parser_parse_gimple_body (c_parser *pa
>    BLOCK_CHAIN (block) = NULL_TREE;
>    TREE_ASM_WRITTEN (block) = 1;
>
> -  gbind *bind_stmt = gimple_build_bind (BIND_EXPR_VARS (stmt), NULL,
> -                                       BIND_EXPR_BLOCK (stmt));
> -  gimple_bind_set_body (bind_stmt, seq);
> -  gimple_seq_add_stmt (&body, bind_stmt);
> -  gimple_set_body (current_function_decl, body);
> -
> -  /* While we have SSA names in the IL we do not have a CFG built yet
> -     and PHIs are represented using a PHI internal function.  We do
> -     have lowered control flow and exception handling (well, we do not
> -     have parser support for EH yet).  But as we still have BINDs
> -     we have to go through lowering again.  */
> -  cfun->curr_properties = PROP_gimple_any;
> +  if (cdil == cdil_gimple)
> +    {
> +      gbind *bind_stmt = gimple_build_bind (BIND_EXPR_VARS (stmt), NULL,
> +                                           BIND_EXPR_BLOCK (stmt));
> +      gimple_bind_set_body (bind_stmt, seq);
> +      gimple_seq_add_stmt (&body, bind_stmt);
> +      gimple_set_body (current_function_decl, body);
> +    }
> +  else
> +    {
> +      /* Control-flow and binds are lowered, record local decls.  */
> +      for (tree var = BIND_EXPR_VARS (stmt); var; var = DECL_CHAIN (var))
> +       if (VAR_P (var)
> +           && !DECL_EXTERNAL (var))
> +         add_local_decl (cfun, var);
> +      /* We have a CFG.  Build the edges.  */
> +      for (unsigned i = 0; i < edges.length (); ++i)
> +       make_edge (BASIC_BLOCK_FOR_FN (cfun, edges[i].src),
> +                  BASIC_BLOCK_FOR_FN (cfun, edges[i].dest), edges[i].flags);
> +      /* Add fallthru edges and edges for case labels.
> +        Entry and exit block are already treated specially.  */
> +      basic_block bb;
> +      FOR_EACH_BB_FN (bb, cfun)
> +       if (EDGE_COUNT (bb->succs) == 0)
> +         {
> +           gimple *last = last_stmt (bb);
> +           if (gswitch *sw = safe_dyn_cast <gswitch *> (last))
> +             for (unsigned i = 0; i < gimple_switch_num_labels (sw); ++i)
> +               {
> +                 basic_block label_bb = gimple_switch_label_bb (cfun, sw, i);
> +                 make_edge (bb, label_bb, 0);
> +               }
> +           else if (!last
> +                    || !is_gimple_call (last)
> +                    || !gimple_call_noreturn_p (last))
> +             make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
> +         }
> +      /* With SSA lower PHIs parsed as internal function calls and
> +        update stmts.  */
> +      if (cdil == cdil_gimple_ssa)
> +       {
> +         init_ssa_operands (cfun);
> +         FOR_EACH_BB_FN (bb, cfun)
> +           {
> +             bool phis = true;
> +             for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
> +                  !gsi_end_p (gsi);)
> +               {
> +                 gimple *stmt = gsi_stmt (gsi);
> +                 if (phis && gimple_call_internal_p (stmt, IFN_PHI))
> +                   {
> +                     gphi *phi = create_phi_node (gimple_call_lhs (stmt), bb);
> +                     for (unsigned i = 0; i < gimple_call_num_args (stmt); i += 2)
> +                       {
> +                         int src_index;
> +                         if (c_parser_gimple_parse_bb_spec (gimple_call_arg (stmt, i),
> +                                                            &src_index))
> +                           {
> +                             edge e = find_edge (BASIC_BLOCK_FOR_FN (cfun, src_index),
> +                                                 bb);
> +                             if (e)
> +                               add_phi_arg (phi, gimple_call_arg (stmt, i + 1), e,
> +                                            UNKNOWN_LOCATION);
> +                           }
> +                       }
> +                     gsi_remove (&gsi, false);
> +                   }
> +                 else
> +                   {
> +                     phis = false;
> +                     update_stmt (stmt);
> +                     gsi_next (&gsi);
> +                   }
> +               }
> +           }
> +         /* No explicit virtual operands (yet).  */
> +         bitmap_obstack_initialize (NULL);
> +         update_ssa (TODO_update_ssa_only_virtuals);
> +         bitmap_obstack_release (NULL);
> +       }
> +      fix_loop_structure (NULL);
> +    }
> +  edges.release ();
> +  current_bb = NULL;
>
>    dump_function (TDI_gimple, current_function_decl);
>  }
> @@ -197,6 +326,8 @@ c_parser_gimple_compound_statement (c_pa
>               if (! c_parser_require (parser, CPP_SEMICOLON,
>                                       "expected %<;%>"))
>                 return return_p;
> +             if (cfun->curr_properties & PROP_cfg)
> +               make_edge (current_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
>               break;
>             default:
>               goto expr_stmt;
> @@ -208,6 +339,134 @@ c_parser_gimple_compound_statement (c_pa
>               c_parser_gimple_label (parser, seq);
>               break;
>             }
> +         /* Basic block specification.
> +            __BB (index, ...)  */
> +         if ((cfun->curr_properties & PROP_cfg)
> +             && !strcmp (IDENTIFIER_POINTER
> +                           (c_parser_peek_token (parser)->value), "__BB"))
> +           {
> +             c_parser_consume_token (parser);
> +             if (! c_parser_require (parser, CPP_OPEN_PAREN,
> +                                     "expected %<(%>"))
> +               return return_p;
> +             if (c_parser_next_token_is_not (parser, CPP_NUMBER))
> +               {
> +                 c_parser_error (parser, "expected block index");
> +                 return return_p;
> +               }
> +             tree tnum = c_parser_peek_token (parser)->value;
> +             if (TREE_CODE (tnum) != INTEGER_CST)
> +               {
> +                 c_parser_error (parser, "expected block index");
> +                 return return_p;
> +               }
> +             int index = TREE_INT_CST_LOW (tnum);
> +             int is_loop_header_of = -1;
> +             c_parser_consume_token (parser);
> +             while (c_parser_next_token_is (parser, CPP_COMMA))
> +               {
> +                 c_parser_consume_token (parser);
> +                 if (! c_parser_next_token_is (parser, CPP_NAME))
> +                   {
> +                     c_parser_error (parser, "expected block specifier");
> +                     return return_p;
> +                   }
> +                 /* loop_header (NUM)  */
> +                 if (!strcmp (IDENTIFIER_POINTER
> +                                (c_parser_peek_token (parser)->value),
> +                              "loop_header"))
> +                   {
> +                     c_parser_consume_token (parser);
> +                     if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
> +                       return return_p;
> +                     tree loop_num;
> +                     if (! c_parser_next_token_is (parser, CPP_NUMBER)
> +                         || TREE_CODE (loop_num
> +                                         = c_parser_peek_token (parser)->value)
> +                              != INTEGER_CST)
> +                       {
> +                         c_parser_error (parser, "expected loop number");
> +                         return return_p;
> +                       }
> +                     c_parser_consume_token (parser);
> +                     is_loop_header_of = TREE_INT_CST_LOW (loop_num);
> +                     if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
> +                       return return_p;
> +                   }
> +                 else
> +                   {
> +                     c_parser_error (parser, "unknown block specifier");
> +                     return return_p;
> +                   }
> +               }
> +             if (! c_parser_require (parser, CPP_CLOSE_PAREN,
> +                                     "expected %<)%>"))
> +               return return_p;
> +             if (! c_parser_require (parser, CPP_COLON,
> +                                     "expected %<:%>"))
> +               return return_p;
> +
> +             /* Put stmts parsed in the current block.  */
> +             if (!gimple_seq_empty_p (*seq))
> +               {
> +                 if (!current_bb)
> +                   c_parser_error (parser, "stmts without block");
> +                 else
> +                   {
> +                     gimple_stmt_iterator gsi = gsi_start_bb (current_bb);
> +                     gsi_insert_seq_after_without_update (&gsi, *seq,
> +                                                          GSI_CONTINUE_LINKING);
> +                   }
> +                 *seq = NULL;
> +               }
> +
> +             /* Build an empty block with specified index, linking them
> +                in source order.  */
> +             basic_block bb = alloc_block ();
> +             bb->index = index;
> +             link_block (bb, (current_bb ? current_bb
> +                              : ENTRY_BLOCK_PTR_FOR_FN (cfun)));
> +             if (basic_block_info_for_fn (cfun)->length () <= (size_t)index)
> +               vec_safe_grow_cleared (basic_block_info_for_fn (cfun),
> +                                      index + 1);
> +             SET_BASIC_BLOCK_FOR_FN (cfun, index, bb);
> +             if (last_basic_block_for_fn (cfun) <= index)
> +               last_basic_block_for_fn (cfun) = index + 1;
> +             n_basic_blocks_for_fn (cfun)++;
> +             if (!current_bb)
> +               make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), bb, EDGE_FALLTHRU);
> +
> +             /* We leave the proper setting to fixup.  */
> +             struct loop *loop_father = loops_for_fn (cfun)->tree_root;
> +             /* If the new block is a loop header, allocate a loop
> +                struct.  Fixup will take care of proper placement within
> +                the loop tree.  */
> +             if (is_loop_header_of != -1)
> +               {
> +                 if (number_of_loops (cfun) > (unsigned)is_loop_header_of
> +                     && get_loop (cfun, is_loop_header_of) != NULL)
> +                   {
> +                     c_parser_error (parser, "duplicate loop header");
> +                   }
> +                 else
> +                   {
> +                     struct loop *loop = alloc_loop ();
> +                     loop->num = is_loop_header_of;
> +                     loop->header = bb;
> +                     vec_safe_grow_cleared (loops_for_fn (cfun)->larray,
> +                                            is_loop_header_of + 1);
> +                     (*loops_for_fn (cfun)->larray)[is_loop_header_of] = loop;
> +                     flow_loop_tree_node_add (loops_for_fn (cfun)->tree_root,
> +                                              loop);
> +                   }
> +                 loop_father = get_loop (cfun, is_loop_header_of);
> +               }
> +             bb->loop_father = loop_father;
> +
> +             /* Stmts now go to the new block.  */
> +             current_bb = bb;
> +             break;
> +           }
>           goto expr_stmt;
>
>         case CPP_SEMICOLON:
> @@ -229,6 +488,22 @@ expr_stmt:
>         }
>      }
>    c_parser_consume_token (parser);
> +
> +  /* Put stmts parsed in the current block.  */
> +  if ((cfun->curr_properties & PROP_cfg)
> +      && !gimple_seq_empty_p (*seq))
> +    {
> +      if (!current_bb)
> +       c_parser_error (parser, "stmts without block");
> +      else
> +       {
> +         gimple_stmt_iterator gsi = gsi_start_bb (current_bb);
> +         gsi_insert_seq_after_without_update (&gsi, *seq,
> +                                              GSI_CONTINUE_LINKING);
> +       }
> +      *seq = NULL;
> +    }
> +
>    return return_p;
>  }
>
> @@ -373,8 +648,7 @@ c_parser_gimple_statement (c_parser *par
>           if (c_parser_next_token_is (parser, CPP_NAME)
>               && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
>             {
> -             arg = lookup_label_for_goto (loc,
> -                                          c_parser_peek_token (parser)->value);
> +             arg = c_parser_peek_token (parser)->value;
>               c_parser_consume_token (parser);
>
>               if (c_parser_next_token_is (parser, CPP_COLON))
> @@ -1288,48 +1562,57 @@ c_parser_gimple_label (c_parser *parser,
>       startwith("pass-name")
>   */
>
> -char *
> -c_parser_gimple_or_rtl_pass_list (c_parser *parser)
> +void
> +c_parser_gimple_or_rtl_pass_list (c_parser *parser, c_declspecs *specs)
>  {
>    char *pass = NULL;
>
>    /* Accept __GIMPLE/__RTL.  */
>    if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
> -    return NULL;
> +    return;
>    c_parser_consume_token (parser);
>
> -  if (c_parser_next_token_is (parser, CPP_NAME))
> +  while (c_parser_next_token_is (parser, CPP_NAME))
>      {
>        const char *op = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
>        c_parser_consume_token (parser);
>        if (! strcmp (op, "startwith"))
>         {
>           if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
> -           return NULL;
> +           return;
>           if (c_parser_next_token_is_not (parser, CPP_STRING))
>             {
>               error_at (c_parser_peek_token (parser)->location,
>                         "expected pass name");
> -             return NULL;
> +             return;
>             }
>           pass = xstrdup (TREE_STRING_POINTER
>                                 (c_parser_peek_token (parser)->value));
>           c_parser_consume_token (parser);
> -         if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
> -           return NULL;
> +         if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<(%>"))
> +           return;
>         }
> +      else if (specs->declspec_il != cdil_gimple)
> +       /* Allow only one IL specifier and none on RTL.  */
> +       ;
> +      else if (! strcmp (op, "cfg"))
> +       specs->declspec_il = cdil_gimple_cfg;
> +      else if (! strcmp (op, "ssa"))
> +       specs->declspec_il = cdil_gimple_ssa;
>        else
>         {
>           error_at (c_parser_peek_token (parser)->location,
>                     "invalid operation");
> -         return NULL;
> +         return;
>         }
> +     if (c_parser_next_token_is (parser, CPP_COMMA))
> +       c_parser_consume_token (parser);
>      }
>
>    if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
> -    return NULL;
> +    return;
>
> -  return pass;
> +  specs->gimple_or_rtl_pass = pass;
>  }
>
>  /* Parse gimple local declaration.
> @@ -1433,9 +1716,18 @@ c_parser_gimple_declaration (c_parser *p
>  static void
>  c_parser_gimple_goto_stmt (location_t loc, tree label, gimple_seq *seq)
>  {
> +  if (cfun->curr_properties & PROP_cfg)
> +    {
> +      int dest_index;
> +      if (c_parser_gimple_parse_bb_spec (label, &dest_index))
> +       {
> +         edges.safe_push (gimple_parser_edge (current_bb->index, dest_index,
> +                                              EDGE_FALLTHRU));
> +         return;
> +       }
> +    }
>    tree decl = lookup_label_for_goto (loc, label);
>    gimple_seq_add_stmt (seq, gimple_build_goto (decl));
> -  return;
>  }
>
>  /* Parse a parenthesized condition.
> @@ -1464,7 +1756,7 @@ c_parser_gimple_paren_condition (c_parse
>  static void
>  c_parser_gimple_if_stmt (c_parser *parser, gimple_seq *seq)
>  {
> -  tree t_label, f_label, label;
> +  tree t_label = NULL_TREE, f_label = NULL_TREE, label;
>    location_t loc;
>    c_parser_consume_token (parser);
>    tree cond = c_parser_gimple_paren_condition (parser);
> @@ -1480,7 +1772,13 @@ c_parser_gimple_if_stmt (c_parser *parse
>         }
>        label = c_parser_peek_token (parser)->value;
>        c_parser_consume_token (parser);
> -      t_label = lookup_label_for_goto (loc, label);
> +      int dest_index;
> +      if ((cfun->curr_properties & PROP_cfg)
> +         && c_parser_gimple_parse_bb_spec (label, &dest_index))
> +       edges.safe_push (gimple_parser_edge (current_bb->index, dest_index,
> +                                            EDGE_TRUE_VALUE));
> +      else
> +       t_label = lookup_label_for_goto (loc, label);
>        if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
>         return;
>      }
> @@ -1508,7 +1806,13 @@ c_parser_gimple_if_stmt (c_parser *parse
>           return;
>         }
>        label = c_parser_peek_token (parser)->value;
> -      f_label = lookup_label_for_goto (loc, label);
> +      int dest_index;
> +      if ((cfun->curr_properties & PROP_cfg)
> +         && c_parser_gimple_parse_bb_spec (label, &dest_index))
> +       edges.safe_push (gimple_parser_edge (current_bb->index, dest_index,
> +                                            EDGE_FALSE_VALUE));
> +      else
> +       f_label = lookup_label_for_goto (loc, label);
>        c_parser_consume_token (parser);
>        if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
>         return;
> Index: gcc/c/gimple-parser.h
> ===================================================================
> --- gcc/c/gimple-parser.h       (revision 269604)
> +++ gcc/c/gimple-parser.h       (working copy)
> @@ -21,7 +21,8 @@ along with GCC; see the file COPYING3.
>  #define GCC_GIMPLE_PARSER_H
>
>  /* Gimple parsing functions.  */
> -extern void c_parser_parse_gimple_body (c_parser *);
> -extern char *c_parser_gimple_or_rtl_pass_list (c_parser *);
> +extern void c_parser_parse_gimple_body (c_parser *, char *,
> +                                       enum c_declspec_il);
> +extern void c_parser_gimple_or_rtl_pass_list (c_parser *, c_declspecs *);
>
>  #endif
> Index: gcc/testsuite/gcc.dg/gimplefe-13.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/gimplefe-13.c  (revision 269604)
> +++ gcc/testsuite/gcc.dg/gimplefe-13.c  (working copy)
> @@ -1,25 +1,25 @@
>  /* { dg-do compile } */
>  /* { dg-options "-O -fgimple" } */
>
> -void __GIMPLE (startwith ("dse2")) foo ()
> +void __GIMPLE (ssa,startwith ("dse2")) foo ()
>  {
>    int a;
>
> -bb_2:
> -  if (a > 4)
> -    goto bb_3;
> +__BB(2):
> +  if (a_5(D) > 4)
> +    goto __BB3;
>    else
> -    goto bb_4;
> +    goto __BB4;
>
> -bb_3:
> +__BB(3):
>    a_2 = 10;
> -  goto bb_5;
> +  goto __BB5;
>
> -bb_4:
> +__BB(4):
>    a_3 = 20;
>
> -bb_5:
> -  a_1 = __PHI (bb_3: a_2, bb_4: a_3);
> +__BB(5):
> +  a_1 = __PHI (__BB3: a_2, __BB4: a_3);
>    a_4 = a_1 + 4;
>
>  return;
> Index: gcc/testsuite/gcc.dg/gimplefe-14.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/gimplefe-14.c  (revision 269604)
> +++ gcc/testsuite/gcc.dg/gimplefe-14.c  (working copy)
> @@ -1,29 +1,32 @@
>  /* { dg-do run } */
>  /* { dg-options "-O -fgimple" } */
>
> -int __GIMPLE ()
> +int __GIMPLE (ssa)
>  main (int argc, char * * argv)
>  {
>    int a;
>
> -  bb_2:
> +  __BB(2):
>    /* Because of PR82114 we need to handle also 0 as base metal can have
>       argc == 0.  */
>    switch (argc_2(D)) {default: L2; case 0: L0; case 1: L0; case 2: L1; }
>
> +  __BB(3):
>  L0:
>    a_4 = 0;
> -  goto bb_6;
> +  goto __BB6;
>
> +  __BB(4):
>  L1:
>    a_3 = 3;
> -  goto bb_6;
> +  goto __BB6;
>
> +  __BB(5):
>  L2:
>    a_5 = -1;
>
> -  bb_6:
> -  a_1 = __PHI (L0: a_4, L1: a_3, L2: a_5);
> +  __BB(6):
> +  a_1 = __PHI (__BB3: a_4, __BB4: a_3, __BB5: a_5);
>    return a_1;
>
>  }
> Index: gcc/testsuite/gcc.dg/gimplefe-17.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/gimplefe-17.c  (revision 269604)
> +++ gcc/testsuite/gcc.dg/gimplefe-17.c  (working copy)
> @@ -1,26 +1,29 @@
>  /* { dg-do compile } */
> -/* { dg-options "-fgimple -fdump-tree-ssa" } */
> +/* { dg-options "-fgimple -fdump-tree-fixup_cfg2" } */
>
>  int
> -__GIMPLE () *
> +__GIMPLE (ssa) *
>  foo ()
>  {
>    int _1;
>    int j;
>    int *b;
> +
> +__BB(5):
>    _1 = 1;
> -bb1:
> +
> +__BB(2):
>    if (_1)
> -    goto bb3;
> +    goto __BB4;
>    else
> -    goto bb2;
> +    goto __BB3;
>
> -bb2:
> +__BB(3):
>    b_2 = (int *)0;
>
> -bb3:
> -  b_4 = __PHI (bb1: b_3(D), bb2: b_2);
> +__BB(4):
> +  b_4 = __PHI (__BB2: b_3(D), __BB3: b_2);
>    return b_4;
>  }
>
> -/* { dg-final { scan-tree-dump-not "_1_" "ssa" } } */
> +/* { dg-final { scan-tree-dump-not "_1_" "fixup_cfg2" } } */
> Index: gcc/testsuite/gcc.dg/gimplefe-18.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/gimplefe-18.c  (revision 269604)
> +++ gcc/testsuite/gcc.dg/gimplefe-18.c  (working copy)
> @@ -2,23 +2,26 @@
>  /* { dg-options "-fgimple" } */
>
>  int
> -__GIMPLE () *
> +__GIMPLE (ssa) *
>  foo ()
>  {
>    int _1;
>    int j;
>    int *b;
> +
> +__BB(2):
>    _1 = 1;
> -bb1:
> +
> +__BB(3):
>    if (_1)
> -    goto bb3;
> +    goto __BB5;
>    else
> -    goto bb2;
> +    goto __BB4;
>
> -bb2:
> +__BB(4):
>    b_2 = (int *)0;
>
> -bb3:
> -  b_4 = __PHI (bb1: &j, bb2: b_2);
> +__BB(5):
> +  b_4 = __PHI (__BB3: &j, __BB4: b_2);
>    return b_4;
>  }
> Index: gcc/testsuite/gcc.dg/gimplefe-7.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/gimplefe-7.c   (revision 269604)
> +++ gcc/testsuite/gcc.dg/gimplefe-7.c   (working copy)
> @@ -1,25 +1,25 @@
>  /* { dg-do compile } */
>  /* { dg-options "-fgimple" } */
>
> -void __GIMPLE () foo ()
> +void __GIMPLE (ssa) foo ()
>  {
>    int a;
>
> -bb_2:
> -  if (a > 4)
> -    goto bb_3;
> +__BB(2):
> +  if (a_5(D) > 4)
> +    goto __BB3;
>    else
> -    goto bb_4;
> +    goto __BB4;
>
> -bb_3:
> +__BB(3):
>    a_2 = 10;
> -  goto bb_5;
> +  goto __BB5;
>
> -bb_4:
> +__BB(4):
>    a_3 = 20;
>
> -bb_5:
> -  a_1 = __PHI (bb_3: a_2, bb_4: a_3);
> +__BB(5):
> +  a_1 = __PHI (__BB3: a_2, __BB4: a_3);
>    a_4 = a_1 + 4;
>
>  return;
> Index: gcc/testsuite/gcc.dg/torture/pr89595.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/torture/pr89595.c      (revision 269604)
> +++ gcc/testsuite/gcc.dg/torture/pr89595.c      (working copy)
> @@ -1,34 +1,38 @@
>  /* { dg-do run } */
>  /* { dg-additional-options "-fgimple" } */
>
> +/* Go back to fix the testcase -- need SSA name on freelist...
> +   (allocate all gaps & put them there?)  */
> +
>  int __attribute__((noipa))
>  __GIMPLE(startwith("dom")) bar(int cond, int val)
>  {
>    int i;
>
> +__BB(3):
>    if (0 != 0)
> -    goto bb_6;
> +    goto __BB6;
>    else
> -    goto bb_2;
> +    goto __BB2;
>
> -bb_2:
> +__BB(2):
>    if (cond_5(D) != 0)
> -    goto bb_4;
> +    goto __BB4;
>    else
> -    goto bb_5;
> +    goto __BB5;
>
> -bb_4:
> +__BB(4):
>    i_6 = val_2(D);
>    i_1 = val_2(D) > 0 ? i_6 : 0;
>
> -bb_5:
> -  i_3 = __PHI (bb_4: i_1, bb_2: 0);
> +__BB(5):
> +  i_3 = __PHI (__BB4: i_1, __BB2: 0);
>    return i_3;
>
> -bb_6:
> +__BB(6):
>    i_4 = 1;
>    i_9 = 2;
> -  goto bb_2;
> +  goto __BB2;
>  }
>
>  int main()
> Index: gcc/testsuite/gcc.dg/tree-ssa/cunroll-13.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/tree-ssa/cunroll-13.c  (revision 269604)
> +++ gcc/testsuite/gcc.dg/tree-ssa/cunroll-13.c  (working copy)
> @@ -9,7 +9,7 @@ typedef int i32;
>
>  struct a {i32 a[8];i32 b;};
>
> -void __GIMPLE (startwith("fix_loops"))
> +void __GIMPLE (ssa,startwith("fix_loops"))
>  t (struct a * a)
>  {
>    i32 i;
> @@ -18,37 +18,37 @@ t (struct a * a)
>    i32 _9;
>    i32 _11;
>
> -bb_2:
> +__BB(2):
>    _11 = a_6(D)->a[0];
>    if (_11 != _Literal (i32) 0)
> -    goto bb_6;
> +    goto __BB6;
>    else
> -    goto bb_3;
> +    goto __BB3;
>
> -bb_3:
> +__BB(3):
>    return;
>
> -bb_4:
> +__BB(4):
>    _1 = _2 + _Literal (i32) 1;
>    a_6(D)->a[i_19] = _1;
>    i_8 = i_19 + _Literal (i32) 1;
>    if (i_8 <= _Literal (i32) 123455)
> -    goto bb_5;
> +    goto __BB5;
>    else
> -    goto bb_3;
> +    goto __BB3;
>
> -bb_5:
> -  i_19 = __PHI (bb_6: _Literal (i32) 1, bb_4: i_8);
> +__BB(5):
> +  i_19 = __PHI (__BB6: _Literal (i32) 1, __BB4: i_8);
>    _2 = a_6(D)->a[i_19];
>    if (_2 != _Literal (i32) 0)
> -    goto bb_4;
> +    goto __BB4;
>    else
> -    goto bb_3;
> +    goto __BB3;
>
> -bb_6:
> +__BB(6):
>    _9 = _11 + _Literal (i32) 1;
>    a_6(D)->a[0] = _9;
> -  goto bb_5;
> +  goto __BB5;
>  }
>
>  /* This testcase relies on the fact that we do not eliminate the redundant test
> Index: gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_1g.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_1g.c       (revision 269604)
> +++ gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_1g.c       (working copy)
> @@ -15,7 +15,7 @@ foo (long int * p, long int * p2, int N1
>    long unsigned int _4;
>    long int _5;
>
> -  bb_2:
> +  __BB(2):
>    _1 = (long unsigned int) N1_10(D);
>    _2 = _1 * 8ul;
>    p_limit_12 = p_11(D) + _2;
> @@ -23,59 +23,59 @@ foo (long int * p, long int * p2, int N1
>    _4 = _3 * 8ul;
>    p_limit2_15 = p2_14(D) + _4;
>    if (p_11(D) <= p_limit_12)
> -    goto bb_3;
> +    goto __BB3;
>    else
> -    goto bb_13;
> +    goto __BB13;
>
> -  bb_13:
> +  __BB(13):
>
> -  bb_9:
> -  goto bb_6;
> +  __BB(9):
> +  goto __BB6;
>
> -  bb_3:
> +  __BB(3):
>    p_20 = p_11(D) + 8ul;
>    p2_23 = p2_14(D) + 8ul;
>    if (p_limit2_15 < p2_23)
> -    goto bb_14;
> +    goto __BB14;
>    else
> -    goto bb_7;
> +    goto __BB7;
>
> -  bb_14:
> -  goto bb_9;
> +  __BB(14):
> +  goto __BB9;
>
> -  bb_7:
> -  goto bb_5;
> +  __BB(7):
> +  goto __BB5;
>
> -  bb_4:
> +  __BB(4):
>    p_16 = p_26 + 8ul;
>    p2_17 = p2_27 + 8ul;
>    if (p_limit2_15 < p2_17)
> -    goto bb_11;
> +    goto __BB11;
>    else
> -    goto bb_8;
> +    goto __BB8;
>
> -  bb_11:
> -  goto bb_6;
> +  __BB(11):
> +  goto __BB6;
>
> -  bb_8:
> +  __BB(8):
>    ;
>
> -  bb_5:
> -  s_24 = __PHI (bb_7: 0l, bb_8: s_19);
> -  p_26 = __PHI (bb_7: p_20, bb_8: p_16);
> -  p2_27 = __PHI (bb_7: p2_23, bb_8: p2_17);
> +  __BB(5):
> +  s_24 = __PHI (__BB7: 0l, __BB8: s_19);
> +  p_26 = __PHI (__BB7: p_20, __BB8: p_16);
> +  p2_27 = __PHI (__BB7: p2_23, __BB8: p2_17);
>    _5 = __MEM <long int> (p_26);
>    s_19 = _5 + s_24;
>    if (p_limit_12 >= p_26)
> -    goto bb_4;
> +    goto __BB4;
>    else
> -    goto bb_12;
> +    goto __BB12;
>
> -  bb_12:
> +  __BB(12):
>    ;
>
> -  bb_6:
> -  s_25 = __PHI (bb_12: s_19, bb_11: s_19, bb_9: 0l);
> +  __BB(6):
> +  s_25 = __PHI (__BB12: s_19, __BB11: s_19, __BB9: 0l);
>    return s_25;
>  }
>
> Index: gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_2g.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_2g.c       (revision 269604)
> +++ gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_2g.c       (working copy)
> @@ -3,7 +3,7 @@
>
>  /* Exit tests 'i < N1' and 'p2 > p_limit2' can be replaced, so
>   * two ivs i and p2 can be eliminate.  */
> -long int __GIMPLE (startwith("fix_loops"))
> +long int __GIMPLE (ssa,startwith("fix_loops"))
>  foo (long int * p, long int * p2, int N1, int N2)
>  {
>    long int s;
> @@ -13,66 +13,66 @@ foo (long int * p, long int * p2, int N1
>    long unsigned int _2;
>    long int _3;
>
> -  bb_2:
> +  __BB(2):
>    _1 = (long unsigned int) N2_9(D);
>    _2 = _1 * 8ul;
>    p_limit2_11 = p2_10(D) + _2;
>    if (N1_13(D) > 0)
> -    goto bb_3;
> +    goto __BB3;
>    else
> -    goto bb_13;
> +    goto __BB13;
>
> -  bb_13:
> +  __BB(13):
>
> -  bb_9:
> -  goto bb_6;
> +  __BB(9):
> +  goto __BB6;
>
> -  bb_3:
> +  __BB(3):
>    p_22 = p_12(D) + 8ul;
>    p2_23 = p2_10(D) + 8ul;
>    if (p_limit2_11 < p2_23)
> -    goto bb_14;
> +    goto __BB14;
>    else
> -    goto bb_7;
> +    goto __BB7;
>
> -  bb_14:
> -  goto bb_9;
> +  __BB(14):
> +  goto __BB9;
>
> -  bb_7:
> -  goto bb_5;
> +  __BB(7):
> +  goto __BB5;
>
> -  bb_4:
> +  __BB(4):
>    p_14 = p_27 + 8ul;
>    p2_15 = p2_28 + 8ul;
>    i_16 = i_29 + 1;
>    if (p_limit2_11 < p2_15)
> -    goto bb_11;
> +    goto __BB11;
>    else
> -    goto bb_8;
> +    goto __BB8;
>
> -  bb_11:
> -  goto bb_6;
> +  __BB(11):
> +  goto __BB6;
>
> -  bb_8:
> +  __BB(8):
>    ;
>
> -  bb_5:
> -  s_25 = __PHI (bb_7: 0l, bb_8: s_18);
> -  p_27 = __PHI (bb_7: p_22, bb_8: p_14);
> -  p2_28 = __PHI (bb_7: p2_23, bb_8: p2_15);
> -  i_29 = __PHI (bb_7: 1, bb_8: i_16);
> +  __BB(5):
> +  s_25 = __PHI (__BB7: 0l, __BB8: s_18);
> +  p_27 = __PHI (__BB7: p_22, __BB8: p_14);
> +  p2_28 = __PHI (__BB7: p2_23, __BB8: p2_15);
> +  i_29 = __PHI (__BB7: 1, __BB8: i_16);
>    _3 = __MEM <long int> (p_27);
>    s_18 = _3 + s_25;
>    if (N1_13(D) > i_29)
> -    goto bb_4;
> +    goto __BB4;
>    else
> -    goto bb_12;
> +    goto __BB12;
>
> -  bb_12:
> +  __BB(12):
>    ;
>
> -  bb_6:
> -  s_26 = __PHI (bb_12: s_18, bb_11: s_18, bb_9: 0l);
> +  __BB(6):
> +  s_26 = __PHI (__BB12: s_18, __BB11: s_18, __BB9: 0l);
>    return s_26;
>  }
>
> Index: gcc/testsuite/gcc.dg/tree-ssa/scev-3.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/tree-ssa/scev-3.c      (revision 269604)
> +++ gcc/testsuite/gcc.dg/tree-ssa/scev-3.c      (working copy)
> @@ -4,39 +4,39 @@
>  int *a_p;
>  int a[1000];
>
> -void __GIMPLE (startwith ("loop"))
> +void __GIMPLE (ssa,startwith ("loop"))
>  f (int k)
>  {
>    int i;
>    int * _1;
>
> -bb_2:
> +__BB(2):
>    i_5 = k_4(D);
>    if (i_5 <= 999)
> -    goto bb_4;
> +    goto __BB4;
>    else
> -    goto bb_3;
> +    goto __BB3;
>
> -bb_3:
> +__BB(3):
>    return;
>
> -bb_4:
> +__BB(4):
>    ;
>
> -bb_5:
> -  i_12 = __PHI (bb_6: i_9, bb_4: i_5);
> +__BB(5):
> +  i_12 = __PHI (__BB6: i_9, __BB4: i_5);
>    _1 = &a[i_12];
>    a_p = _1;
>    __MEM <int[1000]> ((int *)&a)[i_12] = 100;
>    i_9 = i_5 + i_12;
>    if (i_9 <= 999)
> -    goto bb_6;
> +    goto __BB6;
>    else
> -    goto bb_3;
> +    goto __BB3;
>
> -bb_6:
> +__BB(6):
>    ;
> -  goto bb_5;
> +  goto __BB5;
>
>  }
>
> Index: gcc/testsuite/gcc.dg/tree-ssa/scev-4.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/tree-ssa/scev-4.c      (revision 269604)
> +++ gcc/testsuite/gcc.dg/tree-ssa/scev-4.c      (working copy)
> @@ -9,39 +9,39 @@ typedef struct {
>  int *a_p;
>  S a[1000];
>
> -void __GIMPLE (startwith ("loop"))
> +void __GIMPLE (ssa, startwith ("loop"))
>  f (int k)
>  {
>    int i;
>    int * _1;
>
> -bb_2:
> +__BB(2):
>    i_5 = k_4(D);
>    if (i_5 <= 999)
> -    goto bb_4;
> +    goto __BB4;
>    else
> -    goto bb_3;
> +    goto __BB3;
>
> -bb_3:
> +__BB(3):
>    return;
>
> -bb_4:
> +__BB(4):
>    ;
>
> -bb_5:
> -  i_12 = __PHI (bb_6: i_9, bb_4: i_5);
> +__BB(5):
> +  i_12 = __PHI (__BB6: i_9, __BB4: i_5);
>    _1 = &a[i_12].y;
>    a_p = _1;
>    __MEM <S[1000]> ((int *)&a)[i_12].y = 100;
>    i_9 = i_5 + i_12;
>    if (i_9 <= 999)
> -    goto bb_6;
> +    goto __BB6;
>    else
> -    goto bb_3;
> +    goto __BB3;
>
> -bb_6:
> +__BB(6):
>    ;
> -  goto bb_5;
> +  goto __BB5;
>
>  }
>
> Index: gcc/testsuite/gcc.dg/tree-ssa/scev-5.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/tree-ssa/scev-5.c      (revision 269604)
> +++ gcc/testsuite/gcc.dg/tree-ssa/scev-5.c      (working copy)
> @@ -4,39 +4,39 @@
>  int *a_p;
>  int a[1000];
>
> -void __GIMPLE (startwith ("loop"))
> +void __GIMPLE (ssa,startwith ("loop"))
>  f (int k)
>  {
>    long long int i;
>    int * _1;
>
> -bb_2:
> +__BB(2):
>    i_5 = (long long int) k_4(D);
>    if (i_5 <= 999ll)
> -    goto bb_4;
> +    goto __BB4;
>    else
> -    goto bb_3;
> +    goto __BB3;
>
> -bb_3:
> +__BB(3):
>    return;
>
> -bb_4:
> +__BB(4):
>    ;
>
> -bb_5:
> -  i_12 = __PHI (bb_6: i_9, bb_4: i_5);
> +__BB(5):
> +  i_12 = __PHI (__BB6: i_9, __BB4: i_5);
>    _1 = &a[i_12];
>    a_p = _1;
>    __MEM <int[1000]> ((int *)&a)[i_12] = 100;
>    i_9 = i_5 + i_12;
>    if (i_9 <= 999ll)
> -    goto bb_6;
> +    goto __BB6;
>    else
> -    goto bb_3;
> +    goto __BB3;
>
> -bb_6:
> +__BB(6):
>    ;
> -  goto bb_5;
> +  goto __BB5;
>
>  }
>
> Index: gcc/testsuite/gcc.dg/vect/vect-cond-arith-2.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/vect/vect-cond-arith-2.c       (revision 269604)
> +++ gcc/testsuite/gcc.dg/vect/vect-cond-arith-2.c       (working copy)
> @@ -1,7 +1,7 @@
>  /* { dg-do compile } */
>  /* { dg-additional-options "-fgimple -fdump-tree-optimized -ffast-math" } */
>
> -double __GIMPLE (startwith("loop"))
> +double __GIMPLE (ssa, startwith("loop"))
>  neg_xi (double *x)
>  {
>    int i;
> @@ -13,13 +13,13 @@ neg_xi (double *x)
>    double res;
>    unsigned int ivtmp;
>
> - bb_1:
> -  goto bb_2;
> + __BB(5):
> +  goto __BB2;
>
> - bb_2:
> -  res_1 = __PHI (bb_1: 0.0, bb_3: res_2);
> -  i_4 = __PHI (bb_1: 0, bb_3: i_5);
> -  ivtmp_6 = __PHI (bb_1: 100U, bb_3: ivtmp_7);
> + __BB(2):
> +  res_1 = __PHI (__BB5: 0.0, __BB3: res_2);
> +  i_4 = __PHI (__BB5: 0, __BB3: i_5);
> +  ivtmp_6 = __PHI (__BB5: 100U, __BB3: ivtmp_7);
>    index = (long unsigned int) i_4;
>    offset = index * 8UL;
>    xi_ptr = x_8(D) + offset;
> @@ -29,15 +29,15 @@ neg_xi (double *x)
>    i_5 = i_4 + 1;
>    ivtmp_7 = ivtmp_6 - 1U;
>    if (ivtmp_7 != 0U)
> -    goto bb_3;
> +    goto __BB3;
>    else
> -    goto bb_4;
> +    goto __BB4;
>
> - bb_3:
> -  goto bb_2;
> + __BB(3):
> +  goto __BB2;
>
> - bb_4:
> -  res_3 = __PHI (bb_2: res_2);
> + __BB(4):
> +  res_3 = __PHI (__BB2: res_2);
>    return res_3;
>  }
>
> Index: gcc/testsuite/gcc.target/aarch64/sve/loop_add_6.c
> ===================================================================
> --- gcc/testsuite/gcc.target/aarch64/sve/loop_add_6.c   (revision 269604)
> +++ gcc/testsuite/gcc.target/aarch64/sve/loop_add_6.c   (working copy)
> @@ -1,7 +1,7 @@
>  /* { dg-do compile } */
>  /* { dg-options "-O2 -ftree-vectorize -fgimple -ffast-math" } */
>
> -double __GIMPLE (startwith("loop"))
> +double __GIMPLE (ssa, startwith("loop"))
>  neg_xi (double *x)
>  {
>    int i;
> @@ -13,13 +13,13 @@ neg_xi (double *x)
>    double res;
>    unsigned int ivtmp;
>
> - bb_1:
> -  goto bb_2;
> + __BB(5):
> +  goto __BB2;
>
> - bb_2:
> -  res_1 = __PHI (bb_1: 0.0, bb_3: res_2);
> -  i_4 = __PHI (bb_1: 0, bb_3: i_5);
> -  ivtmp_6 = __PHI (bb_1: 100U, bb_3: ivtmp_7);
> + __BB(2):
> +  res_1 = __PHI (__BB5: 0.0, __BB3: res_2);
> +  i_4 = __PHI (__BB5: 0, __BB3: i_5);
> +  ivtmp_6 = __PHI (__BB5: 100U, __BB3: ivtmp_7);
>    index = (long unsigned int) i_4;
>    offset = index * 8UL;
>    xi_ptr = x_8(D) + offset;
> @@ -29,15 +29,15 @@ neg_xi (double *x)
>    i_5 = i_4 + 1;
>    ivtmp_7 = ivtmp_6 - 1U;
>    if (ivtmp_7 != 0U)
> -    goto bb_3;
> +    goto __BB3;
>    else
> -    goto bb_4;
> +    goto __BB4;
>
> - bb_3:
> -  goto bb_2;
> + __BB(3):
> +  goto __BB2;
>
> - bb_4:
> -  res_3 = __PHI (bb_2: res_2);
> + __BB(4):
> +  res_3 = __PHI (__BB2: res_2);
>    return res_3;
>  }
>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH][RFC] Teach GIMPLE FE to build proper CFG + SSA (+ loops)
  2019-03-13  7:23 ` Bin.Cheng
@ 2019-03-13  8:43   ` Richard Biener
  2019-03-14 10:54     ` Richard Biener
  0 siblings, 1 reply; 5+ messages in thread
From: Richard Biener @ 2019-03-13  8:43 UTC (permalink / raw)
  To: Bin.Cheng; +Cc: gcc-patches List

On Wed, 13 Mar 2019, Bin.Cheng wrote:

> On Wed, Mar 13, 2019 at 3:58 AM Richard Biener <rguenther@suse.de> wrote:
> >
> >
> > This makes an attempt at fixing the most annoying parts of the GIMPLE
> > FE unit testing - the lack of proper CFG preservation and hoops you
> > need to jump through to make the CFG and SSA builders happy.
> >
> > Due to this the __GIMPLE specifiers takes two new flags, "cfg"
> > for GIMPLE-with-a-CFG and "ssa" for GIMPLE-with-a-CFG-and-SSA.
> > When there is a CFG you need to start basic-block boundaries with
> >
> > __BB(index):
> >
> > where 'index' is the basic-block index.  That implicitely defines
> > a label __BBindex for use in goto stmts and friends (but doesn't
> > actually add a GIMPLE_LABEL).
> >
> > The parsing code isn't defensive right now so you need to watch
> > out to not use index 0 or 1 (entry and exit block) which are
> > only implicitely present.
> >
> > As a proof of concept I added one BB annotation - loop_header(num)
> > where "num" is the loop number.  This means you can now also
> > have loop structures preserved (to some extent - the loop tree is
> > not explicitely represented nor are loop fathers, both are re-built
> > via fixup).
> >
> > I've not yet adjusted -gimple dumping.
> >
> > I've adjusted all testcases I could find.
> >
> > The CFG build inside the frontend is a bit awkward (spread out...),
> > likewise some functionality is asking for split-out.
> >
> > This is mainly a RFC for whether you think this is forward looking
> > enough.  Future enhancements would include EH and abnormal edges
> > via stmt annotations:
> Thanks very much for doing this.  Do we have a centralized
> wiki/document on the formal definition?  It would be very helpful even
> it's still evolving, otherwise we would need to dig into messages for
> fragmented clues.

Earlier this week I transformed the old 
https://gcc.gnu.org/wiki/GimpleFrontEnd page into one documenting
the current state but this doesn't yet include any kind of documentation.

I suppose special syntax documentation should go into our texinfo
docs, I guess into a new section in the internals manual.  Currently
we only have documentation for the -fgimple switch.

Note that I view -gimple dumping as the thing that should give you
a clue about expected syntax.  I hope to spend a little more time
on the patch to make it ready for GCC9.

Richard.


> Thanks,
> bin
> >
> > __BB(2):
> >   foo () goto __BB3 __EDGE_EH; // EH edge to BB3
> >
> > __BB(3):
> >   setjmp () goto __BB4 __EDGE_AB; // abnormal edge to BB4
> >
> > __BB(4):
> >   _1 = _5 / 0. __NOTHROW; // gimple_nothrow_p is true
> >   _3 = _2 / _4 goto __BB5 __EDGE_EH; // EH edge to BB5
> >
> > etc.  extra edge flags:
> >
> >   goto __BB5 __EDGE_EXECUTABLE;
> >
> > I guess now is the time for bike-shedding.
> >
> > Richard.
> >
> > 2019-03-12  Richard Biener  <rguenther@suse.de>
> >
> >         c/
> >         * c-tree.h (enum c_declspec_il): New.
> >         (struct c_declspecs): Merge gimple_p and rtl_p into declspec_il
> >         enum bitfield.
> >         * c-parser.c (c_parser_declaration_or_fndef): Adjust accordingly.
> >         Pass start pass and declspec_il to c_parser_parse_gimple_body.
> >         (c_parser_declspecs): Adjust.
> >         * gimple-parser.c: Include cfg.h, cfghooks.h, cfganal.h, tree-cfg.h,
> >         gimple-iterator.h, cfgloop.h, tree-phinodes.h, tree-into-ssa.h
> >         and bitmap.h.
> >         (struct gimple_parser_edge): New.
> >         (edges, current_bb): New globals.
> >         (c_parser_gimple_parse_bb_spec): New helper.
> >         (c_parser_parse_gimple_body): Get start pass and IL specification.
> >         Initialize SSA and CFG.
> >         (c_parser_gimple_compound_statement): Handle CFG build.
> >         (c_parser_gimple_statement): Change intermittend __PHI internal
> >         function arg.
> >         (c_parser_gimple_or_rtl_pass_list): Handle ssa, cfg flags.
> >         (c_parser_gimple_goto_stmt): Record edges to build.
> >         (c_parser_gimple_if_stmt): Likewise.
> >         * gimple-parser.h (c_parser_parse_gimple_body): Adjust.
> >         (c_parser_gimple_or_rtl_pass_list): Likewise.
> >
> >         * gcc.dg/gimplefe-13.c: Adjust.
> >         ...
> >
> > Index: gcc/c/c-parser.c
> > ===================================================================
> > --- gcc/c/c-parser.c    (revision 269604)
> > +++ gcc/c/c-parser.c    (working copy)
> > @@ -2324,19 +2324,9 @@ c_parser_declaration_or_fndef (c_parser
> >        DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
> >         = c_parser_peek_token (parser)->location;
> >
> > -      /* If the definition was marked with __GIMPLE then parse the
> > -         function body as GIMPLE.  */
> > -      if (specs->gimple_p)
> > -       {
> > -         cfun->pass_startwith = specs->gimple_or_rtl_pass;
> > -         bool saved = in_late_binary_op;
> > -         in_late_binary_op = true;
> > -         c_parser_parse_gimple_body (parser);
> > -         in_late_binary_op = saved;
> > -       }
> > -      /* Similarly, if it was marked with __RTL, use the RTL parser now,
> > +      /* If the definition was marked with __RTL, use the RTL parser now,
> >          consuming the function body.  */
> > -      else if (specs->rtl_p)
> > +      if (specs->declspec_il == cdil_rtl)
> >         {
> >           c_parser_parse_rtl_body (parser, specs->gimple_or_rtl_pass);
> >
> > @@ -2350,6 +2340,16 @@ c_parser_declaration_or_fndef (c_parser
> >           finish_function ();
> >           return;
> >         }
> > +      /* If the definition was marked with __GIMPLE then parse the
> > +         function body as GIMPLE.  */
> > +      else if (specs->declspec_il != cdil_none)
> > +       {
> > +         bool saved = in_late_binary_op;
> > +         in_late_binary_op = true;
> > +         c_parser_parse_gimple_body (parser, specs->gimple_or_rtl_pass,
> > +                                     specs->declspec_il);
> > +         in_late_binary_op = saved;
> > +       }
> >        else
> >         fnbody = c_parser_compound_statement (parser);
> >        tree fndecl = current_function_decl;
> > @@ -2372,8 +2372,8 @@ c_parser_declaration_or_fndef (c_parser
> >             add_stmt (fnbody);
> >           finish_function ();
> >         }
> > -      /* Get rid of the empty stmt list for GIMPLE.  */
> > -      if (specs->gimple_p)
> > +      /* Get rid of the empty stmt list for GIMPLE/RTL.  */
> > +      if (specs->declspec_il != cdil_none)
> >         DECL_SAVED_TREE (fndecl) = NULL_TREE;
> >
> >        break;
> > @@ -2882,15 +2882,15 @@ c_parser_declspecs (c_parser *parser, st
> >           if (! flag_gimple)
> >             error_at (loc, "%<__GIMPLE%> only valid with %<-fgimple%>");
> >           c_parser_consume_token (parser);
> > -         specs->gimple_p = true;
> > +         specs->declspec_il = cdil_gimple;
> >           specs->locations[cdw_gimple] = loc;
> > -         specs->gimple_or_rtl_pass = c_parser_gimple_or_rtl_pass_list (parser);
> > +         c_parser_gimple_or_rtl_pass_list (parser, specs);
> >           break;
> >         case RID_RTL:
> >           c_parser_consume_token (parser);
> > -         specs->rtl_p = true;
> > +         specs->declspec_il = cdil_rtl;
> >           specs->locations[cdw_rtl] = loc;
> > -         specs->gimple_or_rtl_pass = c_parser_gimple_or_rtl_pass_list (parser);
> > +         c_parser_gimple_or_rtl_pass_list (parser, specs);
> >           break;
> >         default:
> >           goto out;
> > Index: gcc/c/c-tree.h
> > ===================================================================
> > --- gcc/c/c-tree.h      (revision 269604)
> > +++ gcc/c/c-tree.h      (working copy)
> > @@ -288,6 +288,14 @@ enum c_declspec_word {
> >                             enumerator.  */
> >  };
> >
> > +enum c_declspec_il {
> > +  cdil_none,
> > +  cdil_gimple,         /* __GIMPLE  */
> > +  cdil_gimple_cfg,     /* __GIMPLE(cfg)  */
> > +  cdil_gimple_ssa,     /* __GIMPLE(ssa)  */
> > +  cdil_rtl             /* __RTL  */
> > +};
> > +
> >  /* A sequence of declaration specifiers in C.  When a new declaration
> >     specifier is added, please update the enum c_declspec_word above
> >     accordingly.  */
> > @@ -326,6 +334,7 @@ struct c_declspecs {
> >    /* The kind of type specifier if one has been seen, ctsk_none
> >       otherwise.  */
> >    ENUM_BITFIELD (c_typespec_kind) typespec_kind : 3;
> > +  ENUM_BITFIELD (c_declspec_il) declspec_il : 3;
> >    /* Whether any expressions in typeof specifiers may appear in
> >       constant expressions.  */
> >    BOOL_BITFIELD expr_const_operands : 1;
> > @@ -381,10 +390,6 @@ struct c_declspecs {
> >    /* Whether any alignment specifier (even with zero alignment) was
> >       specified.  */
> >    BOOL_BITFIELD alignas_p : 1;
> > -  /* Whether any __GIMPLE specifier was specified.  */
> > -  BOOL_BITFIELD gimple_p : 1;
> > -  /* Whether any __RTL specifier was specified.  */
> > -  BOOL_BITFIELD rtl_p : 1;
> >    /* The address space that the declaration belongs to.  */
> >    addr_space_t address_space;
> >  };
> > Index: gcc/c/gimple-parser.c
> > ===================================================================
> > --- gcc/c/gimple-parser.c       (revision 269604)
> > +++ gcc/c/gimple-parser.c       (working copy)
> > @@ -54,6 +54,15 @@ along with GCC; see the file COPYING3.
> >  #include "gimple-ssa.h"
> >  #include "tree-dfa.h"
> >  #include "internal-fn.h"
> > +#include "cfg.h"
> > +#include "cfghooks.h"
> > +#include "cfganal.h"
> > +#include "tree-cfg.h"
> > +#include "gimple-iterator.h"
> > +#include "cfgloop.h"
> > +#include "tree-phinodes.h"
> > +#include "tree-into-ssa.h"
> > +#include "bitmap.h"
> >
> >
> >  /* Gimple parsing functions.  */
> > @@ -75,11 +84,34 @@ static void c_finish_gimple_return (loca
> >  static tree c_parser_gimple_paren_condition (c_parser *);
> >  static void c_parser_gimple_expr_list (c_parser *, vec<tree> *);
> >
> > +struct gimple_parser_edge
> > +{
> > +  gimple_parser_edge (int s, int d, int f) : src(s), dest(d), flags(f) {}
> > +  int src;
> > +  int dest;
> > +  int flags;
> > +};
> > +
> > +static vec<gimple_parser_edge> edges = vNULL;
> > +static basic_block current_bb;
> > +
> > +static bool
> > +c_parser_gimple_parse_bb_spec (tree val, int *index)
> > +{
> > +  if (strncmp (IDENTIFIER_POINTER (val), "__BB", 4) != 0)
> > +    return false;
> > +  for (const char *p = IDENTIFIER_POINTER (val) + 4; *p; ++p)
> > +    if (!ISDIGIT (*p))
> > +      return false;
> > +  *index = atoi (IDENTIFIER_POINTER (val) + 4);
> > +  return *index > 0;
> > +}
> >
> >  /* Parse the body of a function declaration marked with "__GIMPLE".  */
> >
> >  void
> > -c_parser_parse_gimple_body (c_parser *parser)
> > +c_parser_parse_gimple_body (c_parser *parser, char *gimple_pass,
> > +                           enum c_declspec_il cdil)
> >  {
> >    gimple_seq seq = NULL;
> >    gimple_seq body = NULL;
> > @@ -87,9 +119,34 @@ c_parser_parse_gimple_body (c_parser *pa
> >    push_scope ();
> >    location_t loc1 = c_parser_peek_token (parser)->location;
> >
> > +  cfun->pass_startwith = gimple_pass;
> >    init_tree_ssa (cfun);
> >
> > -  if (! c_parser_gimple_compound_statement (parser, &seq))
> > +  if (cdil == cdil_gimple)
> > +    /* While we have SSA names in the IL we do not have a CFG built yet
> > +       and PHIs are represented using a PHI internal function.  We do
> > +       have lowered control flow and exception handling (well, we do not
> > +       have parser support for EH yet).  But as we still have BINDs
> > +       we have to go through lowering again.  */
> > +    cfun->curr_properties = PROP_gimple_any;
> > +  else
> > +    {
> > +      /* We have at least cdil_gimple_cfg.  */
> > +      gimple_register_cfg_hooks ();
> > +      init_empty_tree_cfg ();
> > +      /* Initialize the bare loop structure - we are going to only
> > +         mark headers and leave the rest to fixup.  */
> > +      set_loops_for_fn (cfun, ggc_cleared_alloc<struct loops> ());
> > +      init_loops_structure (cfun, loops_for_fn (cfun), 1);
> > +      loops_state_set (cfun, LOOPS_NEED_FIXUP|LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
> > +      cfun->curr_properties
> > +       |= PROP_gimple_lcf | PROP_gimple_leh | PROP_cfg | PROP_loops;
> > +      if (cdil == cdil_gimple_ssa)
> > +       cfun->curr_properties |= PROP_ssa;
> > +    }
> > +
> > +  if (! c_parser_gimple_compound_statement (parser, &seq)
> > +      && cdil == cdil_gimple)
> >      {
> >        gimple *ret = gimple_build_return (NULL);
> >        gimple_seq_add_stmt (&seq, ret);
> > @@ -104,18 +161,90 @@ c_parser_parse_gimple_body (c_parser *pa
> >    BLOCK_CHAIN (block) = NULL_TREE;
> >    TREE_ASM_WRITTEN (block) = 1;
> >
> > -  gbind *bind_stmt = gimple_build_bind (BIND_EXPR_VARS (stmt), NULL,
> > -                                       BIND_EXPR_BLOCK (stmt));
> > -  gimple_bind_set_body (bind_stmt, seq);
> > -  gimple_seq_add_stmt (&body, bind_stmt);
> > -  gimple_set_body (current_function_decl, body);
> > -
> > -  /* While we have SSA names in the IL we do not have a CFG built yet
> > -     and PHIs are represented using a PHI internal function.  We do
> > -     have lowered control flow and exception handling (well, we do not
> > -     have parser support for EH yet).  But as we still have BINDs
> > -     we have to go through lowering again.  */
> > -  cfun->curr_properties = PROP_gimple_any;
> > +  if (cdil == cdil_gimple)
> > +    {
> > +      gbind *bind_stmt = gimple_build_bind (BIND_EXPR_VARS (stmt), NULL,
> > +                                           BIND_EXPR_BLOCK (stmt));
> > +      gimple_bind_set_body (bind_stmt, seq);
> > +      gimple_seq_add_stmt (&body, bind_stmt);
> > +      gimple_set_body (current_function_decl, body);
> > +    }
> > +  else
> > +    {
> > +      /* Control-flow and binds are lowered, record local decls.  */
> > +      for (tree var = BIND_EXPR_VARS (stmt); var; var = DECL_CHAIN (var))
> > +       if (VAR_P (var)
> > +           && !DECL_EXTERNAL (var))
> > +         add_local_decl (cfun, var);
> > +      /* We have a CFG.  Build the edges.  */
> > +      for (unsigned i = 0; i < edges.length (); ++i)
> > +       make_edge (BASIC_BLOCK_FOR_FN (cfun, edges[i].src),
> > +                  BASIC_BLOCK_FOR_FN (cfun, edges[i].dest), edges[i].flags);
> > +      /* Add fallthru edges and edges for case labels.
> > +        Entry and exit block are already treated specially.  */
> > +      basic_block bb;
> > +      FOR_EACH_BB_FN (bb, cfun)
> > +       if (EDGE_COUNT (bb->succs) == 0)
> > +         {
> > +           gimple *last = last_stmt (bb);
> > +           if (gswitch *sw = safe_dyn_cast <gswitch *> (last))
> > +             for (unsigned i = 0; i < gimple_switch_num_labels (sw); ++i)
> > +               {
> > +                 basic_block label_bb = gimple_switch_label_bb (cfun, sw, i);
> > +                 make_edge (bb, label_bb, 0);
> > +               }
> > +           else if (!last
> > +                    || !is_gimple_call (last)
> > +                    || !gimple_call_noreturn_p (last))
> > +             make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
> > +         }
> > +      /* With SSA lower PHIs parsed as internal function calls and
> > +        update stmts.  */
> > +      if (cdil == cdil_gimple_ssa)
> > +       {
> > +         init_ssa_operands (cfun);
> > +         FOR_EACH_BB_FN (bb, cfun)
> > +           {
> > +             bool phis = true;
> > +             for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
> > +                  !gsi_end_p (gsi);)
> > +               {
> > +                 gimple *stmt = gsi_stmt (gsi);
> > +                 if (phis && gimple_call_internal_p (stmt, IFN_PHI))
> > +                   {
> > +                     gphi *phi = create_phi_node (gimple_call_lhs (stmt), bb);
> > +                     for (unsigned i = 0; i < gimple_call_num_args (stmt); i += 2)
> > +                       {
> > +                         int src_index;
> > +                         if (c_parser_gimple_parse_bb_spec (gimple_call_arg (stmt, i),
> > +                                                            &src_index))
> > +                           {
> > +                             edge e = find_edge (BASIC_BLOCK_FOR_FN (cfun, src_index),
> > +                                                 bb);
> > +                             if (e)
> > +                               add_phi_arg (phi, gimple_call_arg (stmt, i + 1), e,
> > +                                            UNKNOWN_LOCATION);
> > +                           }
> > +                       }
> > +                     gsi_remove (&gsi, false);
> > +                   }
> > +                 else
> > +                   {
> > +                     phis = false;
> > +                     update_stmt (stmt);
> > +                     gsi_next (&gsi);
> > +                   }
> > +               }
> > +           }
> > +         /* No explicit virtual operands (yet).  */
> > +         bitmap_obstack_initialize (NULL);
> > +         update_ssa (TODO_update_ssa_only_virtuals);
> > +         bitmap_obstack_release (NULL);
> > +       }
> > +      fix_loop_structure (NULL);
> > +    }
> > +  edges.release ();
> > +  current_bb = NULL;
> >
> >    dump_function (TDI_gimple, current_function_decl);
> >  }
> > @@ -197,6 +326,8 @@ c_parser_gimple_compound_statement (c_pa
> >               if (! c_parser_require (parser, CPP_SEMICOLON,
> >                                       "expected %<;%>"))
> >                 return return_p;
> > +             if (cfun->curr_properties & PROP_cfg)
> > +               make_edge (current_bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
> >               break;
> >             default:
> >               goto expr_stmt;
> > @@ -208,6 +339,134 @@ c_parser_gimple_compound_statement (c_pa
> >               c_parser_gimple_label (parser, seq);
> >               break;
> >             }
> > +         /* Basic block specification.
> > +            __BB (index, ...)  */
> > +         if ((cfun->curr_properties & PROP_cfg)
> > +             && !strcmp (IDENTIFIER_POINTER
> > +                           (c_parser_peek_token (parser)->value), "__BB"))
> > +           {
> > +             c_parser_consume_token (parser);
> > +             if (! c_parser_require (parser, CPP_OPEN_PAREN,
> > +                                     "expected %<(%>"))
> > +               return return_p;
> > +             if (c_parser_next_token_is_not (parser, CPP_NUMBER))
> > +               {
> > +                 c_parser_error (parser, "expected block index");
> > +                 return return_p;
> > +               }
> > +             tree tnum = c_parser_peek_token (parser)->value;
> > +             if (TREE_CODE (tnum) != INTEGER_CST)
> > +               {
> > +                 c_parser_error (parser, "expected block index");
> > +                 return return_p;
> > +               }
> > +             int index = TREE_INT_CST_LOW (tnum);
> > +             int is_loop_header_of = -1;
> > +             c_parser_consume_token (parser);
> > +             while (c_parser_next_token_is (parser, CPP_COMMA))
> > +               {
> > +                 c_parser_consume_token (parser);
> > +                 if (! c_parser_next_token_is (parser, CPP_NAME))
> > +                   {
> > +                     c_parser_error (parser, "expected block specifier");
> > +                     return return_p;
> > +                   }
> > +                 /* loop_header (NUM)  */
> > +                 if (!strcmp (IDENTIFIER_POINTER
> > +                                (c_parser_peek_token (parser)->value),
> > +                              "loop_header"))
> > +                   {
> > +                     c_parser_consume_token (parser);
> > +                     if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
> > +                       return return_p;
> > +                     tree loop_num;
> > +                     if (! c_parser_next_token_is (parser, CPP_NUMBER)
> > +                         || TREE_CODE (loop_num
> > +                                         = c_parser_peek_token (parser)->value)
> > +                              != INTEGER_CST)
> > +                       {
> > +                         c_parser_error (parser, "expected loop number");
> > +                         return return_p;
> > +                       }
> > +                     c_parser_consume_token (parser);
> > +                     is_loop_header_of = TREE_INT_CST_LOW (loop_num);
> > +                     if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
> > +                       return return_p;
> > +                   }
> > +                 else
> > +                   {
> > +                     c_parser_error (parser, "unknown block specifier");
> > +                     return return_p;
> > +                   }
> > +               }
> > +             if (! c_parser_require (parser, CPP_CLOSE_PAREN,
> > +                                     "expected %<)%>"))
> > +               return return_p;
> > +             if (! c_parser_require (parser, CPP_COLON,
> > +                                     "expected %<:%>"))
> > +               return return_p;
> > +
> > +             /* Put stmts parsed in the current block.  */
> > +             if (!gimple_seq_empty_p (*seq))
> > +               {
> > +                 if (!current_bb)
> > +                   c_parser_error (parser, "stmts without block");
> > +                 else
> > +                   {
> > +                     gimple_stmt_iterator gsi = gsi_start_bb (current_bb);
> > +                     gsi_insert_seq_after_without_update (&gsi, *seq,
> > +                                                          GSI_CONTINUE_LINKING);
> > +                   }
> > +                 *seq = NULL;
> > +               }
> > +
> > +             /* Build an empty block with specified index, linking them
> > +                in source order.  */
> > +             basic_block bb = alloc_block ();
> > +             bb->index = index;
> > +             link_block (bb, (current_bb ? current_bb
> > +                              : ENTRY_BLOCK_PTR_FOR_FN (cfun)));
> > +             if (basic_block_info_for_fn (cfun)->length () <= (size_t)index)
> > +               vec_safe_grow_cleared (basic_block_info_for_fn (cfun),
> > +                                      index + 1);
> > +             SET_BASIC_BLOCK_FOR_FN (cfun, index, bb);
> > +             if (last_basic_block_for_fn (cfun) <= index)
> > +               last_basic_block_for_fn (cfun) = index + 1;
> > +             n_basic_blocks_for_fn (cfun)++;
> > +             if (!current_bb)
> > +               make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), bb, EDGE_FALLTHRU);
> > +
> > +             /* We leave the proper setting to fixup.  */
> > +             struct loop *loop_father = loops_for_fn (cfun)->tree_root;
> > +             /* If the new block is a loop header, allocate a loop
> > +                struct.  Fixup will take care of proper placement within
> > +                the loop tree.  */
> > +             if (is_loop_header_of != -1)
> > +               {
> > +                 if (number_of_loops (cfun) > (unsigned)is_loop_header_of
> > +                     && get_loop (cfun, is_loop_header_of) != NULL)
> > +                   {
> > +                     c_parser_error (parser, "duplicate loop header");
> > +                   }
> > +                 else
> > +                   {
> > +                     struct loop *loop = alloc_loop ();
> > +                     loop->num = is_loop_header_of;
> > +                     loop->header = bb;
> > +                     vec_safe_grow_cleared (loops_for_fn (cfun)->larray,
> > +                                            is_loop_header_of + 1);
> > +                     (*loops_for_fn (cfun)->larray)[is_loop_header_of] = loop;
> > +                     flow_loop_tree_node_add (loops_for_fn (cfun)->tree_root,
> > +                                              loop);
> > +                   }
> > +                 loop_father = get_loop (cfun, is_loop_header_of);
> > +               }
> > +             bb->loop_father = loop_father;
> > +
> > +             /* Stmts now go to the new block.  */
> > +             current_bb = bb;
> > +             break;
> > +           }
> >           goto expr_stmt;
> >
> >         case CPP_SEMICOLON:
> > @@ -229,6 +488,22 @@ expr_stmt:
> >         }
> >      }
> >    c_parser_consume_token (parser);
> > +
> > +  /* Put stmts parsed in the current block.  */
> > +  if ((cfun->curr_properties & PROP_cfg)
> > +      && !gimple_seq_empty_p (*seq))
> > +    {
> > +      if (!current_bb)
> > +       c_parser_error (parser, "stmts without block");
> > +      else
> > +       {
> > +         gimple_stmt_iterator gsi = gsi_start_bb (current_bb);
> > +         gsi_insert_seq_after_without_update (&gsi, *seq,
> > +                                              GSI_CONTINUE_LINKING);
> > +       }
> > +      *seq = NULL;
> > +    }
> > +
> >    return return_p;
> >  }
> >
> > @@ -373,8 +648,7 @@ c_parser_gimple_statement (c_parser *par
> >           if (c_parser_next_token_is (parser, CPP_NAME)
> >               && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
> >             {
> > -             arg = lookup_label_for_goto (loc,
> > -                                          c_parser_peek_token (parser)->value);
> > +             arg = c_parser_peek_token (parser)->value;
> >               c_parser_consume_token (parser);
> >
> >               if (c_parser_next_token_is (parser, CPP_COLON))
> > @@ -1288,48 +1562,57 @@ c_parser_gimple_label (c_parser *parser,
> >       startwith("pass-name")
> >   */
> >
> > -char *
> > -c_parser_gimple_or_rtl_pass_list (c_parser *parser)
> > +void
> > +c_parser_gimple_or_rtl_pass_list (c_parser *parser, c_declspecs *specs)
> >  {
> >    char *pass = NULL;
> >
> >    /* Accept __GIMPLE/__RTL.  */
> >    if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
> > -    return NULL;
> > +    return;
> >    c_parser_consume_token (parser);
> >
> > -  if (c_parser_next_token_is (parser, CPP_NAME))
> > +  while (c_parser_next_token_is (parser, CPP_NAME))
> >      {
> >        const char *op = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
> >        c_parser_consume_token (parser);
> >        if (! strcmp (op, "startwith"))
> >         {
> >           if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
> > -           return NULL;
> > +           return;
> >           if (c_parser_next_token_is_not (parser, CPP_STRING))
> >             {
> >               error_at (c_parser_peek_token (parser)->location,
> >                         "expected pass name");
> > -             return NULL;
> > +             return;
> >             }
> >           pass = xstrdup (TREE_STRING_POINTER
> >                                 (c_parser_peek_token (parser)->value));
> >           c_parser_consume_token (parser);
> > -         if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
> > -           return NULL;
> > +         if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<(%>"))
> > +           return;
> >         }
> > +      else if (specs->declspec_il != cdil_gimple)
> > +       /* Allow only one IL specifier and none on RTL.  */
> > +       ;
> > +      else if (! strcmp (op, "cfg"))
> > +       specs->declspec_il = cdil_gimple_cfg;
> > +      else if (! strcmp (op, "ssa"))
> > +       specs->declspec_il = cdil_gimple_ssa;
> >        else
> >         {
> >           error_at (c_parser_peek_token (parser)->location,
> >                     "invalid operation");
> > -         return NULL;
> > +         return;
> >         }
> > +     if (c_parser_next_token_is (parser, CPP_COMMA))
> > +       c_parser_consume_token (parser);
> >      }
> >
> >    if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
> > -    return NULL;
> > +    return;
> >
> > -  return pass;
> > +  specs->gimple_or_rtl_pass = pass;
> >  }
> >
> >  /* Parse gimple local declaration.
> > @@ -1433,9 +1716,18 @@ c_parser_gimple_declaration (c_parser *p
> >  static void
> >  c_parser_gimple_goto_stmt (location_t loc, tree label, gimple_seq *seq)
> >  {
> > +  if (cfun->curr_properties & PROP_cfg)
> > +    {
> > +      int dest_index;
> > +      if (c_parser_gimple_parse_bb_spec (label, &dest_index))
> > +       {
> > +         edges.safe_push (gimple_parser_edge (current_bb->index, dest_index,
> > +                                              EDGE_FALLTHRU));
> > +         return;
> > +       }
> > +    }
> >    tree decl = lookup_label_for_goto (loc, label);
> >    gimple_seq_add_stmt (seq, gimple_build_goto (decl));
> > -  return;
> >  }
> >
> >  /* Parse a parenthesized condition.
> > @@ -1464,7 +1756,7 @@ c_parser_gimple_paren_condition (c_parse
> >  static void
> >  c_parser_gimple_if_stmt (c_parser *parser, gimple_seq *seq)
> >  {
> > -  tree t_label, f_label, label;
> > +  tree t_label = NULL_TREE, f_label = NULL_TREE, label;
> >    location_t loc;
> >    c_parser_consume_token (parser);
> >    tree cond = c_parser_gimple_paren_condition (parser);
> > @@ -1480,7 +1772,13 @@ c_parser_gimple_if_stmt (c_parser *parse
> >         }
> >        label = c_parser_peek_token (parser)->value;
> >        c_parser_consume_token (parser);
> > -      t_label = lookup_label_for_goto (loc, label);
> > +      int dest_index;
> > +      if ((cfun->curr_properties & PROP_cfg)
> > +         && c_parser_gimple_parse_bb_spec (label, &dest_index))
> > +       edges.safe_push (gimple_parser_edge (current_bb->index, dest_index,
> > +                                            EDGE_TRUE_VALUE));
> > +      else
> > +       t_label = lookup_label_for_goto (loc, label);
> >        if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
> >         return;
> >      }
> > @@ -1508,7 +1806,13 @@ c_parser_gimple_if_stmt (c_parser *parse
> >           return;
> >         }
> >        label = c_parser_peek_token (parser)->value;
> > -      f_label = lookup_label_for_goto (loc, label);
> > +      int dest_index;
> > +      if ((cfun->curr_properties & PROP_cfg)
> > +         && c_parser_gimple_parse_bb_spec (label, &dest_index))
> > +       edges.safe_push (gimple_parser_edge (current_bb->index, dest_index,
> > +                                            EDGE_FALSE_VALUE));
> > +      else
> > +       f_label = lookup_label_for_goto (loc, label);
> >        c_parser_consume_token (parser);
> >        if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
> >         return;
> > Index: gcc/c/gimple-parser.h
> > ===================================================================
> > --- gcc/c/gimple-parser.h       (revision 269604)
> > +++ gcc/c/gimple-parser.h       (working copy)
> > @@ -21,7 +21,8 @@ along with GCC; see the file COPYING3.
> >  #define GCC_GIMPLE_PARSER_H
> >
> >  /* Gimple parsing functions.  */
> > -extern void c_parser_parse_gimple_body (c_parser *);
> > -extern char *c_parser_gimple_or_rtl_pass_list (c_parser *);
> > +extern void c_parser_parse_gimple_body (c_parser *, char *,
> > +                                       enum c_declspec_il);
> > +extern void c_parser_gimple_or_rtl_pass_list (c_parser *, c_declspecs *);
> >
> >  #endif
> > Index: gcc/testsuite/gcc.dg/gimplefe-13.c
> > ===================================================================
> > --- gcc/testsuite/gcc.dg/gimplefe-13.c  (revision 269604)
> > +++ gcc/testsuite/gcc.dg/gimplefe-13.c  (working copy)
> > @@ -1,25 +1,25 @@
> >  /* { dg-do compile } */
> >  /* { dg-options "-O -fgimple" } */
> >
> > -void __GIMPLE (startwith ("dse2")) foo ()
> > +void __GIMPLE (ssa,startwith ("dse2")) foo ()
> >  {
> >    int a;
> >
> > -bb_2:
> > -  if (a > 4)
> > -    goto bb_3;
> > +__BB(2):
> > +  if (a_5(D) > 4)
> > +    goto __BB3;
> >    else
> > -    goto bb_4;
> > +    goto __BB4;
> >
> > -bb_3:
> > +__BB(3):
> >    a_2 = 10;
> > -  goto bb_5;
> > +  goto __BB5;
> >
> > -bb_4:
> > +__BB(4):
> >    a_3 = 20;
> >
> > -bb_5:
> > -  a_1 = __PHI (bb_3: a_2, bb_4: a_3);
> > +__BB(5):
> > +  a_1 = __PHI (__BB3: a_2, __BB4: a_3);
> >    a_4 = a_1 + 4;
> >
> >  return;
> > Index: gcc/testsuite/gcc.dg/gimplefe-14.c
> > ===================================================================
> > --- gcc/testsuite/gcc.dg/gimplefe-14.c  (revision 269604)
> > +++ gcc/testsuite/gcc.dg/gimplefe-14.c  (working copy)
> > @@ -1,29 +1,32 @@
> >  /* { dg-do run } */
> >  /* { dg-options "-O -fgimple" } */
> >
> > -int __GIMPLE ()
> > +int __GIMPLE (ssa)
> >  main (int argc, char * * argv)
> >  {
> >    int a;
> >
> > -  bb_2:
> > +  __BB(2):
> >    /* Because of PR82114 we need to handle also 0 as base metal can have
> >       argc == 0.  */
> >    switch (argc_2(D)) {default: L2; case 0: L0; case 1: L0; case 2: L1; }
> >
> > +  __BB(3):
> >  L0:
> >    a_4 = 0;
> > -  goto bb_6;
> > +  goto __BB6;
> >
> > +  __BB(4):
> >  L1:
> >    a_3 = 3;
> > -  goto bb_6;
> > +  goto __BB6;
> >
> > +  __BB(5):
> >  L2:
> >    a_5 = -1;
> >
> > -  bb_6:
> > -  a_1 = __PHI (L0: a_4, L1: a_3, L2: a_5);
> > +  __BB(6):
> > +  a_1 = __PHI (__BB3: a_4, __BB4: a_3, __BB5: a_5);
> >    return a_1;
> >
> >  }
> > Index: gcc/testsuite/gcc.dg/gimplefe-17.c
> > ===================================================================
> > --- gcc/testsuite/gcc.dg/gimplefe-17.c  (revision 269604)
> > +++ gcc/testsuite/gcc.dg/gimplefe-17.c  (working copy)
> > @@ -1,26 +1,29 @@
> >  /* { dg-do compile } */
> > -/* { dg-options "-fgimple -fdump-tree-ssa" } */
> > +/* { dg-options "-fgimple -fdump-tree-fixup_cfg2" } */
> >
> >  int
> > -__GIMPLE () *
> > +__GIMPLE (ssa) *
> >  foo ()
> >  {
> >    int _1;
> >    int j;
> >    int *b;
> > +
> > +__BB(5):
> >    _1 = 1;
> > -bb1:
> > +
> > +__BB(2):
> >    if (_1)
> > -    goto bb3;
> > +    goto __BB4;
> >    else
> > -    goto bb2;
> > +    goto __BB3;
> >
> > -bb2:
> > +__BB(3):
> >    b_2 = (int *)0;
> >
> > -bb3:
> > -  b_4 = __PHI (bb1: b_3(D), bb2: b_2);
> > +__BB(4):
> > +  b_4 = __PHI (__BB2: b_3(D), __BB3: b_2);
> >    return b_4;
> >  }
> >
> > -/* { dg-final { scan-tree-dump-not "_1_" "ssa" } } */
> > +/* { dg-final { scan-tree-dump-not "_1_" "fixup_cfg2" } } */
> > Index: gcc/testsuite/gcc.dg/gimplefe-18.c
> > ===================================================================
> > --- gcc/testsuite/gcc.dg/gimplefe-18.c  (revision 269604)
> > +++ gcc/testsuite/gcc.dg/gimplefe-18.c  (working copy)
> > @@ -2,23 +2,26 @@
> >  /* { dg-options "-fgimple" } */
> >
> >  int
> > -__GIMPLE () *
> > +__GIMPLE (ssa) *
> >  foo ()
> >  {
> >    int _1;
> >    int j;
> >    int *b;
> > +
> > +__BB(2):
> >    _1 = 1;
> > -bb1:
> > +
> > +__BB(3):
> >    if (_1)
> > -    goto bb3;
> > +    goto __BB5;
> >    else
> > -    goto bb2;
> > +    goto __BB4;
> >
> > -bb2:
> > +__BB(4):
> >    b_2 = (int *)0;
> >
> > -bb3:
> > -  b_4 = __PHI (bb1: &j, bb2: b_2);
> > +__BB(5):
> > +  b_4 = __PHI (__BB3: &j, __BB4: b_2);
> >    return b_4;
> >  }
> > Index: gcc/testsuite/gcc.dg/gimplefe-7.c
> > ===================================================================
> > --- gcc/testsuite/gcc.dg/gimplefe-7.c   (revision 269604)
> > +++ gcc/testsuite/gcc.dg/gimplefe-7.c   (working copy)
> > @@ -1,25 +1,25 @@
> >  /* { dg-do compile } */
> >  /* { dg-options "-fgimple" } */
> >
> > -void __GIMPLE () foo ()
> > +void __GIMPLE (ssa) foo ()
> >  {
> >    int a;
> >
> > -bb_2:
> > -  if (a > 4)
> > -    goto bb_3;
> > +__BB(2):
> > +  if (a_5(D) > 4)
> > +    goto __BB3;
> >    else
> > -    goto bb_4;
> > +    goto __BB4;
> >
> > -bb_3:
> > +__BB(3):
> >    a_2 = 10;
> > -  goto bb_5;
> > +  goto __BB5;
> >
> > -bb_4:
> > +__BB(4):
> >    a_3 = 20;
> >
> > -bb_5:
> > -  a_1 = __PHI (bb_3: a_2, bb_4: a_3);
> > +__BB(5):
> > +  a_1 = __PHI (__BB3: a_2, __BB4: a_3);
> >    a_4 = a_1 + 4;
> >
> >  return;
> > Index: gcc/testsuite/gcc.dg/torture/pr89595.c
> > ===================================================================
> > --- gcc/testsuite/gcc.dg/torture/pr89595.c      (revision 269604)
> > +++ gcc/testsuite/gcc.dg/torture/pr89595.c      (working copy)
> > @@ -1,34 +1,38 @@
> >  /* { dg-do run } */
> >  /* { dg-additional-options "-fgimple" } */
> >
> > +/* Go back to fix the testcase -- need SSA name on freelist...
> > +   (allocate all gaps & put them there?)  */
> > +
> >  int __attribute__((noipa))
> >  __GIMPLE(startwith("dom")) bar(int cond, int val)
> >  {
> >    int i;
> >
> > +__BB(3):
> >    if (0 != 0)
> > -    goto bb_6;
> > +    goto __BB6;
> >    else
> > -    goto bb_2;
> > +    goto __BB2;
> >
> > -bb_2:
> > +__BB(2):
> >    if (cond_5(D) != 0)
> > -    goto bb_4;
> > +    goto __BB4;
> >    else
> > -    goto bb_5;
> > +    goto __BB5;
> >
> > -bb_4:
> > +__BB(4):
> >    i_6 = val_2(D);
> >    i_1 = val_2(D) > 0 ? i_6 : 0;
> >
> > -bb_5:
> > -  i_3 = __PHI (bb_4: i_1, bb_2: 0);
> > +__BB(5):
> > +  i_3 = __PHI (__BB4: i_1, __BB2: 0);
> >    return i_3;
> >
> > -bb_6:
> > +__BB(6):
> >    i_4 = 1;
> >    i_9 = 2;
> > -  goto bb_2;
> > +  goto __BB2;
> >  }
> >
> >  int main()
> > Index: gcc/testsuite/gcc.dg/tree-ssa/cunroll-13.c
> > ===================================================================
> > --- gcc/testsuite/gcc.dg/tree-ssa/cunroll-13.c  (revision 269604)
> > +++ gcc/testsuite/gcc.dg/tree-ssa/cunroll-13.c  (working copy)
> > @@ -9,7 +9,7 @@ typedef int i32;
> >
> >  struct a {i32 a[8];i32 b;};
> >
> > -void __GIMPLE (startwith("fix_loops"))
> > +void __GIMPLE (ssa,startwith("fix_loops"))
> >  t (struct a * a)
> >  {
> >    i32 i;
> > @@ -18,37 +18,37 @@ t (struct a * a)
> >    i32 _9;
> >    i32 _11;
> >
> > -bb_2:
> > +__BB(2):
> >    _11 = a_6(D)->a[0];
> >    if (_11 != _Literal (i32) 0)
> > -    goto bb_6;
> > +    goto __BB6;
> >    else
> > -    goto bb_3;
> > +    goto __BB3;
> >
> > -bb_3:
> > +__BB(3):
> >    return;
> >
> > -bb_4:
> > +__BB(4):
> >    _1 = _2 + _Literal (i32) 1;
> >    a_6(D)->a[i_19] = _1;
> >    i_8 = i_19 + _Literal (i32) 1;
> >    if (i_8 <= _Literal (i32) 123455)
> > -    goto bb_5;
> > +    goto __BB5;
> >    else
> > -    goto bb_3;
> > +    goto __BB3;
> >
> > -bb_5:
> > -  i_19 = __PHI (bb_6: _Literal (i32) 1, bb_4: i_8);
> > +__BB(5):
> > +  i_19 = __PHI (__BB6: _Literal (i32) 1, __BB4: i_8);
> >    _2 = a_6(D)->a[i_19];
> >    if (_2 != _Literal (i32) 0)
> > -    goto bb_4;
> > +    goto __BB4;
> >    else
> > -    goto bb_3;
> > +    goto __BB3;
> >
> > -bb_6:
> > +__BB(6):
> >    _9 = _11 + _Literal (i32) 1;
> >    a_6(D)->a[0] = _9;
> > -  goto bb_5;
> > +  goto __BB5;
> >  }
> >
> >  /* This testcase relies on the fact that we do not eliminate the redundant test
> > Index: gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_1g.c
> > ===================================================================
> > --- gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_1g.c       (revision 269604)
> > +++ gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_1g.c       (working copy)
> > @@ -15,7 +15,7 @@ foo (long int * p, long int * p2, int N1
> >    long unsigned int _4;
> >    long int _5;
> >
> > -  bb_2:
> > +  __BB(2):
> >    _1 = (long unsigned int) N1_10(D);
> >    _2 = _1 * 8ul;
> >    p_limit_12 = p_11(D) + _2;
> > @@ -23,59 +23,59 @@ foo (long int * p, long int * p2, int N1
> >    _4 = _3 * 8ul;
> >    p_limit2_15 = p2_14(D) + _4;
> >    if (p_11(D) <= p_limit_12)
> > -    goto bb_3;
> > +    goto __BB3;
> >    else
> > -    goto bb_13;
> > +    goto __BB13;
> >
> > -  bb_13:
> > +  __BB(13):
> >
> > -  bb_9:
> > -  goto bb_6;
> > +  __BB(9):
> > +  goto __BB6;
> >
> > -  bb_3:
> > +  __BB(3):
> >    p_20 = p_11(D) + 8ul;
> >    p2_23 = p2_14(D) + 8ul;
> >    if (p_limit2_15 < p2_23)
> > -    goto bb_14;
> > +    goto __BB14;
> >    else
> > -    goto bb_7;
> > +    goto __BB7;
> >
> > -  bb_14:
> > -  goto bb_9;
> > +  __BB(14):
> > +  goto __BB9;
> >
> > -  bb_7:
> > -  goto bb_5;
> > +  __BB(7):
> > +  goto __BB5;
> >
> > -  bb_4:
> > +  __BB(4):
> >    p_16 = p_26 + 8ul;
> >    p2_17 = p2_27 + 8ul;
> >    if (p_limit2_15 < p2_17)
> > -    goto bb_11;
> > +    goto __BB11;
> >    else
> > -    goto bb_8;
> > +    goto __BB8;
> >
> > -  bb_11:
> > -  goto bb_6;
> > +  __BB(11):
> > +  goto __BB6;
> >
> > -  bb_8:
> > +  __BB(8):
> >    ;
> >
> > -  bb_5:
> > -  s_24 = __PHI (bb_7: 0l, bb_8: s_19);
> > -  p_26 = __PHI (bb_7: p_20, bb_8: p_16);
> > -  p2_27 = __PHI (bb_7: p2_23, bb_8: p2_17);
> > +  __BB(5):
> > +  s_24 = __PHI (__BB7: 0l, __BB8: s_19);
> > +  p_26 = __PHI (__BB7: p_20, __BB8: p_16);
> > +  p2_27 = __PHI (__BB7: p2_23, __BB8: p2_17);
> >    _5 = __MEM <long int> (p_26);
> >    s_19 = _5 + s_24;
> >    if (p_limit_12 >= p_26)
> > -    goto bb_4;
> > +    goto __BB4;
> >    else
> > -    goto bb_12;
> > +    goto __BB12;
> >
> > -  bb_12:
> > +  __BB(12):
> >    ;
> >
> > -  bb_6:
> > -  s_25 = __PHI (bb_12: s_19, bb_11: s_19, bb_9: 0l);
> > +  __BB(6):
> > +  s_25 = __PHI (__BB12: s_19, __BB11: s_19, __BB9: 0l);
> >    return s_25;
> >  }
> >
> > Index: gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_2g.c
> > ===================================================================
> > --- gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_2g.c       (revision 269604)
> > +++ gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_2g.c       (working copy)
> > @@ -3,7 +3,7 @@
> >
> >  /* Exit tests 'i < N1' and 'p2 > p_limit2' can be replaced, so
> >   * two ivs i and p2 can be eliminate.  */
> > -long int __GIMPLE (startwith("fix_loops"))
> > +long int __GIMPLE (ssa,startwith("fix_loops"))
> >  foo (long int * p, long int * p2, int N1, int N2)
> >  {
> >    long int s;
> > @@ -13,66 +13,66 @@ foo (long int * p, long int * p2, int N1
> >    long unsigned int _2;
> >    long int _3;
> >
> > -  bb_2:
> > +  __BB(2):
> >    _1 = (long unsigned int) N2_9(D);
> >    _2 = _1 * 8ul;
> >    p_limit2_11 = p2_10(D) + _2;
> >    if (N1_13(D) > 0)
> > -    goto bb_3;
> > +    goto __BB3;
> >    else
> > -    goto bb_13;
> > +    goto __BB13;
> >
> > -  bb_13:
> > +  __BB(13):
> >
> > -  bb_9:
> > -  goto bb_6;
> > +  __BB(9):
> > +  goto __BB6;
> >
> > -  bb_3:
> > +  __BB(3):
> >    p_22 = p_12(D) + 8ul;
> >    p2_23 = p2_10(D) + 8ul;
> >    if (p_limit2_11 < p2_23)
> > -    goto bb_14;
> > +    goto __BB14;
> >    else
> > -    goto bb_7;
> > +    goto __BB7;
> >
> > -  bb_14:
> > -  goto bb_9;
> > +  __BB(14):
> > +  goto __BB9;
> >
> > -  bb_7:
> > -  goto bb_5;
> > +  __BB(7):
> > +  goto __BB5;
> >
> > -  bb_4:
> > +  __BB(4):
> >    p_14 = p_27 + 8ul;
> >    p2_15 = p2_28 + 8ul;
> >    i_16 = i_29 + 1;
> >    if (p_limit2_11 < p2_15)
> > -    goto bb_11;
> > +    goto __BB11;
> >    else
> > -    goto bb_8;
> > +    goto __BB8;
> >
> > -  bb_11:
> > -  goto bb_6;
> > +  __BB(11):
> > +  goto __BB6;
> >
> > -  bb_8:
> > +  __BB(8):
> >    ;
> >
> > -  bb_5:
> > -  s_25 = __PHI (bb_7: 0l, bb_8: s_18);
> > -  p_27 = __PHI (bb_7: p_22, bb_8: p_14);
> > -  p2_28 = __PHI (bb_7: p2_23, bb_8: p2_15);
> > -  i_29 = __PHI (bb_7: 1, bb_8: i_16);
> > +  __BB(5):
> > +  s_25 = __PHI (__BB7: 0l, __BB8: s_18);
> > +  p_27 = __PHI (__BB7: p_22, __BB8: p_14);
> > +  p2_28 = __PHI (__BB7: p2_23, __BB8: p2_15);
> > +  i_29 = __PHI (__BB7: 1, __BB8: i_16);
> >    _3 = __MEM <long int> (p_27);
> >    s_18 = _3 + s_25;
> >    if (N1_13(D) > i_29)
> > -    goto bb_4;
> > +    goto __BB4;
> >    else
> > -    goto bb_12;
> > +    goto __BB12;
> >
> > -  bb_12:
> > +  __BB(12):
> >    ;
> >
> > -  bb_6:
> > -  s_26 = __PHI (bb_12: s_18, bb_11: s_18, bb_9: 0l);
> > +  __BB(6):
> > +  s_26 = __PHI (__BB12: s_18, __BB11: s_18, __BB9: 0l);
> >    return s_26;
> >  }
> >
> > Index: gcc/testsuite/gcc.dg/tree-ssa/scev-3.c
> > ===================================================================
> > --- gcc/testsuite/gcc.dg/tree-ssa/scev-3.c      (revision 269604)
> > +++ gcc/testsuite/gcc.dg/tree-ssa/scev-3.c      (working copy)
> > @@ -4,39 +4,39 @@
> >  int *a_p;
> >  int a[1000];
> >
> > -void __GIMPLE (startwith ("loop"))
> > +void __GIMPLE (ssa,startwith ("loop"))
> >  f (int k)
> >  {
> >    int i;
> >    int * _1;
> >
> > -bb_2:
> > +__BB(2):
> >    i_5 = k_4(D);
> >    if (i_5 <= 999)
> > -    goto bb_4;
> > +    goto __BB4;
> >    else
> > -    goto bb_3;
> > +    goto __BB3;
> >
> > -bb_3:
> > +__BB(3):
> >    return;
> >
> > -bb_4:
> > +__BB(4):
> >    ;
> >
> > -bb_5:
> > -  i_12 = __PHI (bb_6: i_9, bb_4: i_5);
> > +__BB(5):
> > +  i_12 = __PHI (__BB6: i_9, __BB4: i_5);
> >    _1 = &a[i_12];
> >    a_p = _1;
> >    __MEM <int[1000]> ((int *)&a)[i_12] = 100;
> >    i_9 = i_5 + i_12;
> >    if (i_9 <= 999)
> > -    goto bb_6;
> > +    goto __BB6;
> >    else
> > -    goto bb_3;
> > +    goto __BB3;
> >
> > -bb_6:
> > +__BB(6):
> >    ;
> > -  goto bb_5;
> > +  goto __BB5;
> >
> >  }
> >
> > Index: gcc/testsuite/gcc.dg/tree-ssa/scev-4.c
> > ===================================================================
> > --- gcc/testsuite/gcc.dg/tree-ssa/scev-4.c      (revision 269604)
> > +++ gcc/testsuite/gcc.dg/tree-ssa/scev-4.c      (working copy)
> > @@ -9,39 +9,39 @@ typedef struct {
> >  int *a_p;
> >  S a[1000];
> >
> > -void __GIMPLE (startwith ("loop"))
> > +void __GIMPLE (ssa, startwith ("loop"))
> >  f (int k)
> >  {
> >    int i;
> >    int * _1;
> >
> > -bb_2:
> > +__BB(2):
> >    i_5 = k_4(D);
> >    if (i_5 <= 999)
> > -    goto bb_4;
> > +    goto __BB4;
> >    else
> > -    goto bb_3;
> > +    goto __BB3;
> >
> > -bb_3:
> > +__BB(3):
> >    return;
> >
> > -bb_4:
> > +__BB(4):
> >    ;
> >
> > -bb_5:
> > -  i_12 = __PHI (bb_6: i_9, bb_4: i_5);
> > +__BB(5):
> > +  i_12 = __PHI (__BB6: i_9, __BB4: i_5);
> >    _1 = &a[i_12].y;
> >    a_p = _1;
> >    __MEM <S[1000]> ((int *)&a)[i_12].y = 100;
> >    i_9 = i_5 + i_12;
> >    if (i_9 <= 999)
> > -    goto bb_6;
> > +    goto __BB6;
> >    else
> > -    goto bb_3;
> > +    goto __BB3;
> >
> > -bb_6:
> > +__BB(6):
> >    ;
> > -  goto bb_5;
> > +  goto __BB5;
> >
> >  }
> >
> > Index: gcc/testsuite/gcc.dg/tree-ssa/scev-5.c
> > ===================================================================
> > --- gcc/testsuite/gcc.dg/tree-ssa/scev-5.c      (revision 269604)
> > +++ gcc/testsuite/gcc.dg/tree-ssa/scev-5.c      (working copy)
> > @@ -4,39 +4,39 @@
> >  int *a_p;
> >  int a[1000];
> >
> > -void __GIMPLE (startwith ("loop"))
> > +void __GIMPLE (ssa,startwith ("loop"))
> >  f (int k)
> >  {
> >    long long int i;
> >    int * _1;
> >
> > -bb_2:
> > +__BB(2):
> >    i_5 = (long long int) k_4(D);
> >    if (i_5 <= 999ll)
> > -    goto bb_4;
> > +    goto __BB4;
> >    else
> > -    goto bb_3;
> > +    goto __BB3;
> >
> > -bb_3:
> > +__BB(3):
> >    return;
> >
> > -bb_4:
> > +__BB(4):
> >    ;
> >
> > -bb_5:
> > -  i_12 = __PHI (bb_6: i_9, bb_4: i_5);
> > +__BB(5):
> > +  i_12 = __PHI (__BB6: i_9, __BB4: i_5);
> >    _1 = &a[i_12];
> >    a_p = _1;
> >    __MEM <int[1000]> ((int *)&a)[i_12] = 100;
> >    i_9 = i_5 + i_12;
> >    if (i_9 <= 999ll)
> > -    goto bb_6;
> > +    goto __BB6;
> >    else
> > -    goto bb_3;
> > +    goto __BB3;
> >
> > -bb_6:
> > +__BB(6):
> >    ;
> > -  goto bb_5;
> > +  goto __BB5;
> >
> >  }
> >
> > Index: gcc/testsuite/gcc.dg/vect/vect-cond-arith-2.c
> > ===================================================================
> > --- gcc/testsuite/gcc.dg/vect/vect-cond-arith-2.c       (revision 269604)
> > +++ gcc/testsuite/gcc.dg/vect/vect-cond-arith-2.c       (working copy)
> > @@ -1,7 +1,7 @@
> >  /* { dg-do compile } */
> >  /* { dg-additional-options "-fgimple -fdump-tree-optimized -ffast-math" } */
> >
> > -double __GIMPLE (startwith("loop"))
> > +double __GIMPLE (ssa, startwith("loop"))
> >  neg_xi (double *x)
> >  {
> >    int i;
> > @@ -13,13 +13,13 @@ neg_xi (double *x)
> >    double res;
> >    unsigned int ivtmp;
> >
> > - bb_1:
> > -  goto bb_2;
> > + __BB(5):
> > +  goto __BB2;
> >
> > - bb_2:
> > -  res_1 = __PHI (bb_1: 0.0, bb_3: res_2);
> > -  i_4 = __PHI (bb_1: 0, bb_3: i_5);
> > -  ivtmp_6 = __PHI (bb_1: 100U, bb_3: ivtmp_7);
> > + __BB(2):
> > +  res_1 = __PHI (__BB5: 0.0, __BB3: res_2);
> > +  i_4 = __PHI (__BB5: 0, __BB3: i_5);
> > +  ivtmp_6 = __PHI (__BB5: 100U, __BB3: ivtmp_7);
> >    index = (long unsigned int) i_4;
> >    offset = index * 8UL;
> >    xi_ptr = x_8(D) + offset;
> > @@ -29,15 +29,15 @@ neg_xi (double *x)
> >    i_5 = i_4 + 1;
> >    ivtmp_7 = ivtmp_6 - 1U;
> >    if (ivtmp_7 != 0U)
> > -    goto bb_3;
> > +    goto __BB3;
> >    else
> > -    goto bb_4;
> > +    goto __BB4;
> >
> > - bb_3:
> > -  goto bb_2;
> > + __BB(3):
> > +  goto __BB2;
> >
> > - bb_4:
> > -  res_3 = __PHI (bb_2: res_2);
> > + __BB(4):
> > +  res_3 = __PHI (__BB2: res_2);
> >    return res_3;
> >  }
> >
> > Index: gcc/testsuite/gcc.target/aarch64/sve/loop_add_6.c
> > ===================================================================
> > --- gcc/testsuite/gcc.target/aarch64/sve/loop_add_6.c   (revision 269604)
> > +++ gcc/testsuite/gcc.target/aarch64/sve/loop_add_6.c   (working copy)
> > @@ -1,7 +1,7 @@
> >  /* { dg-do compile } */
> >  /* { dg-options "-O2 -ftree-vectorize -fgimple -ffast-math" } */
> >
> > -double __GIMPLE (startwith("loop"))
> > +double __GIMPLE (ssa, startwith("loop"))
> >  neg_xi (double *x)
> >  {
> >    int i;
> > @@ -13,13 +13,13 @@ neg_xi (double *x)
> >    double res;
> >    unsigned int ivtmp;
> >
> > - bb_1:
> > -  goto bb_2;
> > + __BB(5):
> > +  goto __BB2;
> >
> > - bb_2:
> > -  res_1 = __PHI (bb_1: 0.0, bb_3: res_2);
> > -  i_4 = __PHI (bb_1: 0, bb_3: i_5);
> > -  ivtmp_6 = __PHI (bb_1: 100U, bb_3: ivtmp_7);
> > + __BB(2):
> > +  res_1 = __PHI (__BB5: 0.0, __BB3: res_2);
> > +  i_4 = __PHI (__BB5: 0, __BB3: i_5);
> > +  ivtmp_6 = __PHI (__BB5: 100U, __BB3: ivtmp_7);
> >    index = (long unsigned int) i_4;
> >    offset = index * 8UL;
> >    xi_ptr = x_8(D) + offset;
> > @@ -29,15 +29,15 @@ neg_xi (double *x)
> >    i_5 = i_4 + 1;
> >    ivtmp_7 = ivtmp_6 - 1U;
> >    if (ivtmp_7 != 0U)
> > -    goto bb_3;
> > +    goto __BB3;
> >    else
> > -    goto bb_4;
> > +    goto __BB4;
> >
> > - bb_3:
> > -  goto bb_2;
> > + __BB(3):
> > +  goto __BB2;
> >
> > - bb_4:
> > -  res_3 = __PHI (bb_2: res_2);
> > + __BB(4):
> > +  res_3 = __PHI (__BB2: res_2);
> >    return res_3;
> >  }
> >
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH][RFC] Teach GIMPLE FE to build proper CFG + SSA (+ loops)
  2019-03-13  8:43   ` Richard Biener
@ 2019-03-14 10:54     ` Richard Biener
  2019-03-19 14:49       ` Jeff Law
  0 siblings, 1 reply; 5+ messages in thread
From: Richard Biener @ 2019-03-14 10:54 UTC (permalink / raw)
  To: Bin.Cheng; +Cc: gcc-patches List

On Wed, 13 Mar 2019, Richard Biener wrote:

> On Wed, 13 Mar 2019, Bin.Cheng wrote:
> 
> > On Wed, Mar 13, 2019 at 3:58 AM Richard Biener <rguenther@suse.de> wrote:
> > >
> > >
> > > This makes an attempt at fixing the most annoying parts of the GIMPLE
> > > FE unit testing - the lack of proper CFG preservation and hoops you
> > > need to jump through to make the CFG and SSA builders happy.
> > >
> > > Due to this the __GIMPLE specifiers takes two new flags, "cfg"
> > > for GIMPLE-with-a-CFG and "ssa" for GIMPLE-with-a-CFG-and-SSA.
> > > When there is a CFG you need to start basic-block boundaries with
> > >
> > > __BB(index):
> > >
> > > where 'index' is the basic-block index.  That implicitely defines
> > > a label __BBindex for use in goto stmts and friends (but doesn't
> > > actually add a GIMPLE_LABEL).
> > >
> > > The parsing code isn't defensive right now so you need to watch
> > > out to not use index 0 or 1 (entry and exit block) which are
> > > only implicitely present.
> > >
> > > As a proof of concept I added one BB annotation - loop_header(num)
> > > where "num" is the loop number.  This means you can now also
> > > have loop structures preserved (to some extent - the loop tree is
> > > not explicitely represented nor are loop fathers, both are re-built
> > > via fixup).
> > >
> > > I've not yet adjusted -gimple dumping.
> > >
> > > I've adjusted all testcases I could find.
> > >
> > > The CFG build inside the frontend is a bit awkward (spread out...),
> > > likewise some functionality is asking for split-out.
> > >
> > > This is mainly a RFC for whether you think this is forward looking
> > > enough.  Future enhancements would include EH and abnormal edges
> > > via stmt annotations:
> > Thanks very much for doing this.  Do we have a centralized
> > wiki/document on the formal definition?  It would be very helpful even
> > it's still evolving, otherwise we would need to dig into messages for
> > fragmented clues.
> 
> Earlier this week I transformed the old 
> https://gcc.gnu.org/wiki/GimpleFrontEnd page into one documenting
> the current state but this doesn't yet include any kind of documentation.
> 
> I suppose special syntax documentation should go into our texinfo
> docs, I guess into a new section in the internals manual.  Currently
> we only have documentation for the -fgimple switch.
> 
> Note that I view -gimple dumping as the thing that should give you
> a clue about expected syntax.  I hope to spend a little more time
> on the patch to make it ready for GCC9.

I've settled on another change, forcing explicit gotos for fallthru
edges to the next block.

Otherwise I've cleaned up the patch and removed no longer necessary
support for IFN_PHI from the middle-end.  During cleanup I introduced
a gimple_parser class to hold the extra parsing state and I added
some extra error handling.

Bootstrapped on x86_64-unknown-linux-gnu, testing is still in progress.

I will commit this to make testcase extraction to GIMPLE more feasible
for GCC 9+ (we could even backport the GIMPLE FE changes to GCC 8 if 
needed I guess).  At least it will give me motivation to do further
required changes when I run into the next big LTO testcase running
into a loop optimizer issue... (non-loop passes should work fine
already).

Richard.

From 5cbec540caa8e86f2167ac980159dbe6933717c4 Mon Sep 17 00:00:00 2001
From: Richard Guenther <rguenther@suse.de>
Date: Wed, 13 Mar 2019 13:58:10 +0100
Subject: [PATCH] gimplefe-cfg-ssa

2019-03-12  Richard Biener  <rguenther@suse.de>

	c/
	* c-tree.h (enum c_declspec_il): New.
	(struct c_declspecs): Merge gimple_p and rtl_p into declspec_il
	enum bitfield.
	* c-parser.c (c_parser_declaration_or_fndef): Adjust accordingly.
	Pass start pass and declspec_il to c_parser_parse_gimple_body.
	(c_parser_declspecs): Adjust.
	* gimple-parser.c: Include cfg.h, cfghooks.h, cfganal.h, tree-cfg.h,
	gimple-iterator.h, cfgloop.h, tree-phinodes.h, tree-into-ssa.h
	and bitmap.h.
	(struct gimple_parser): New.
	(gimple_parser::push_edge): New method.
	(c_parser_gimple_parse_bb_spec): New helper.
	(c_parser_parse_gimple_body): Get start pass and IL specification.
	Initialize SSA and CFG.
	(c_parser_gimple_compound_statement): Handle CFG and SSA build.
	Build a gimple_parser parsing state and pass it along.
	(c_parser_gimple_statement): Change intermittend __PHI internal
	function argument for the edge.
	(c_parser_gimple_or_rtl_pass_list): Handle ssa, cfg flags.
	(c_parser_gimple_goto_stmt): Record edges to build.
	(c_parser_gimple_if_stmt): Likewise.
	* gimple-parser.h (c_parser_parse_gimple_body): Adjust.
	(c_parser_gimple_or_rtl_pass_list): Likewise.
	* gimple-pretty-print.c: Include cfgloop.h.
	(dump_gimple_phi): Adjust.
	(dump_gimple_bb_header): Dump loop header for GIMPLE.
	(pp_cfg_jump): Adjust.
	(dump_implicit_edges): Dump fallthru to next block for GIMPLE as well.
	* tree-cfg.c (build_gimple_cfg): Remove lower_phi_internal_fn call.
	(lower_phi_internal_fn): Remove.
	(verify_gimple_call): Remove IFN_PHI special-casing.
	(dump_function_to_file): Dump IL state.
	* tree-into-ssa.c (rewrite_add_phi_arguments): Revert changes
	done to deal with PHI nodes being present in non-SSA state.

	* gcc.dg/gimplefe-13.c: Adjust.
	* gcc.dg/gimplefe-14.c: Likewise.
	* gcc.dg/gimplefe-17.c: Likewise.
	* gcc.dg/gimplefe-18.c: Likewise.
	* gcc.dg/gimplefe-7.c: Likewise.
	* gcc.dg/torture/pr89595.c: Likewise.
	* gcc.dg/tree-ssa/cunroll-13.c: Likewise.
	* gcc.dg/tree-ssa/ivopt_mult_1g.c: Likewise.
	* gcc.dg/tree-ssa/ivopt_mult_2g.c: Likewise.
	* gcc.dg/tree-ssa/scev-3.c: Likewise.
	* gcc.dg/tree-ssa/scev-4.c: Likewise.
	* gcc.dg/tree-ssa/scev-5.c: Likewise.
	* gcc.dg/vect/vect-cond-arith-2.c: Likewise.
	* gcc.target/aarch64/sve/loop_add_6.c: Likewise.

diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 5134e95a921..741d172ff30 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -2324,19 +2324,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
 	= c_parser_peek_token (parser)->location;
 
-      /* If the definition was marked with __GIMPLE then parse the
-         function body as GIMPLE.  */
-      if (specs->gimple_p)
-	{
-	  cfun->pass_startwith = specs->gimple_or_rtl_pass;
-	  bool saved = in_late_binary_op;
-	  in_late_binary_op = true;
-	  c_parser_parse_gimple_body (parser);
-	  in_late_binary_op = saved;
-	}
-      /* Similarly, if it was marked with __RTL, use the RTL parser now,
+      /* If the definition was marked with __RTL, use the RTL parser now,
 	 consuming the function body.  */
-      else if (specs->rtl_p)
+      if (specs->declspec_il == cdil_rtl)
 	{
 	  c_parser_parse_rtl_body (parser, specs->gimple_or_rtl_pass);
 
@@ -2350,6 +2340,16 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 	  finish_function ();
 	  return;
 	}
+      /* If the definition was marked with __GIMPLE then parse the
+         function body as GIMPLE.  */
+      else if (specs->declspec_il != cdil_none)
+	{
+	  bool saved = in_late_binary_op;
+	  in_late_binary_op = true;
+	  c_parser_parse_gimple_body (parser, specs->gimple_or_rtl_pass,
+				      specs->declspec_il);
+	  in_late_binary_op = saved;
+	}
       else
 	fnbody = c_parser_compound_statement (parser);
       tree fndecl = current_function_decl;
@@ -2372,8 +2372,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 	    add_stmt (fnbody);
 	  finish_function ();
 	}
-      /* Get rid of the empty stmt list for GIMPLE.  */
-      if (specs->gimple_p)
+      /* Get rid of the empty stmt list for GIMPLE/RTL.  */
+      if (specs->declspec_il != cdil_none)
 	DECL_SAVED_TREE (fndecl) = NULL_TREE;
 
       break;
@@ -2882,15 +2882,15 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 	  if (! flag_gimple)
 	    error_at (loc, "%<__GIMPLE%> only valid with %<-fgimple%>");
 	  c_parser_consume_token (parser);
-	  specs->gimple_p = true;
+	  specs->declspec_il = cdil_gimple;
 	  specs->locations[cdw_gimple] = loc;
-	  specs->gimple_or_rtl_pass = c_parser_gimple_or_rtl_pass_list (parser);
+	  c_parser_gimple_or_rtl_pass_list (parser, specs);
 	  break;
 	case RID_RTL:
 	  c_parser_consume_token (parser);
-	  specs->rtl_p = true;
+	  specs->declspec_il = cdil_rtl;
 	  specs->locations[cdw_rtl] = loc;
-	  specs->gimple_or_rtl_pass = c_parser_gimple_or_rtl_pass_list (parser);
+	  c_parser_gimple_or_rtl_pass_list (parser, specs);
 	  break;
 	default:
 	  goto out;
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index b69ef3377fd..d6e345afb37 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -288,6 +288,14 @@ enum c_declspec_word {
 			    enumerator.  */
 };
 
+enum c_declspec_il {
+  cdil_none,
+  cdil_gimple,		/* __GIMPLE  */
+  cdil_gimple_cfg,	/* __GIMPLE(cfg)  */
+  cdil_gimple_ssa,	/* __GIMPLE(ssa)  */
+  cdil_rtl		/* __RTL  */
+};
+
 /* A sequence of declaration specifiers in C.  When a new declaration
    specifier is added, please update the enum c_declspec_word above
    accordingly.  */
@@ -326,6 +334,7 @@ struct c_declspecs {
   /* The kind of type specifier if one has been seen, ctsk_none
      otherwise.  */
   ENUM_BITFIELD (c_typespec_kind) typespec_kind : 3;
+  ENUM_BITFIELD (c_declspec_il) declspec_il : 3;
   /* Whether any expressions in typeof specifiers may appear in
      constant expressions.  */
   BOOL_BITFIELD expr_const_operands : 1;
@@ -381,10 +390,6 @@ struct c_declspecs {
   /* Whether any alignment specifier (even with zero alignment) was
      specified.  */
   BOOL_BITFIELD alignas_p : 1;
-  /* Whether any __GIMPLE specifier was specified.  */
-  BOOL_BITFIELD gimple_p : 1;
-  /* Whether any __RTL specifier was specified.  */
-  BOOL_BITFIELD rtl_p : 1;
   /* The address space that the declaration belongs to.  */
   addr_space_t address_space;
 };
diff --git a/gcc/c/gimple-parser.c b/gcc/c/gimple-parser.c
index c67b96641eb..5aa906c0b7e 100644
--- a/gcc/c/gimple-parser.c
+++ b/gcc/c/gimple-parser.c
@@ -54,45 +54,133 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-ssa.h"
 #include "tree-dfa.h"
 #include "internal-fn.h"
+#include "cfg.h"
+#include "cfghooks.h"
+#include "cfganal.h"
+#include "tree-cfg.h"
+#include "gimple-iterator.h"
+#include "cfgloop.h"
+#include "tree-phinodes.h"
+#include "tree-into-ssa.h"
+#include "bitmap.h"
+
+
+/* GIMPLE parser state.  */
+
+struct gimple_parser
+{
+  gimple_parser (c_parser *p) : parser (p), edges(), current_bb(NULL) {}
+  /* c_parser is not visible here, use composition and fake inheritance
+     via a conversion operator.  */
+  operator c_parser *() { return parser; }
+  c_parser *parser;
+
+  /* CFG build state.  */
+  struct gimple_parser_edge
+  {
+    int src;
+    int dest;
+    int flags;
+  };
+  auto_vec<gimple_parser_edge> edges;
+  basic_block current_bb;
+
+  void push_edge (int, int, int);
+};
+
+void
+gimple_parser::push_edge (int src, int dest, int flags)
+{
+  gimple_parser_edge e;
+  e.src = src;
+  e.dest = dest;
+  e.flags = flags;
+  edges.safe_push (e);
+}
 
 
 /* Gimple parsing functions.  */
-static bool c_parser_gimple_compound_statement (c_parser *, gimple_seq *);
-static void c_parser_gimple_label (c_parser *, gimple_seq *);
-static void c_parser_gimple_statement (c_parser *, gimple_seq *);
-static struct c_expr c_parser_gimple_binary_expression (c_parser *);
-static struct c_expr c_parser_gimple_unary_expression (c_parser *);
-static struct c_expr c_parser_gimple_postfix_expression (c_parser *);
-static struct c_expr c_parser_gimple_postfix_expression_after_primary (c_parser *,
-								       location_t,
-								       struct c_expr);
-static void c_parser_gimple_declaration (c_parser *);
-static void c_parser_gimple_goto_stmt (location_t, tree, gimple_seq *);
-static void c_parser_gimple_if_stmt (c_parser *, gimple_seq *);
-static void c_parser_gimple_switch_stmt (c_parser *, gimple_seq *);
-static void c_parser_gimple_return_stmt (c_parser *, gimple_seq *);
+static bool c_parser_gimple_compound_statement (gimple_parser &, gimple_seq *);
+static void c_parser_gimple_label (gimple_parser &, gimple_seq *);
+static void c_parser_gimple_statement (gimple_parser &, gimple_seq *);
+static struct c_expr c_parser_gimple_binary_expression (gimple_parser &);
+static struct c_expr c_parser_gimple_unary_expression (gimple_parser &);
+static struct c_expr c_parser_gimple_postfix_expression (gimple_parser &);
+static struct c_expr c_parser_gimple_postfix_expression_after_primary
+			(gimple_parser &, location_t, struct c_expr);
+static void c_parser_gimple_declaration (gimple_parser &);
+static void c_parser_gimple_goto_stmt (gimple_parser &, location_t,
+				       tree, gimple_seq *);
+static void c_parser_gimple_if_stmt (gimple_parser &, gimple_seq *);
+static void c_parser_gimple_switch_stmt (gimple_parser &, gimple_seq *);
+static void c_parser_gimple_return_stmt (gimple_parser &, gimple_seq *);
 static void c_finish_gimple_return (location_t, tree);
-static tree c_parser_gimple_paren_condition (c_parser *);
-static void c_parser_gimple_expr_list (c_parser *, vec<tree> *);
+static tree c_parser_gimple_paren_condition (gimple_parser &);
+static void c_parser_gimple_expr_list (gimple_parser &, vec<tree> *);
 
 
+/* See if VAL is an identifier matching __BB<num> and return <num>
+   in *INDEX.  Return true if so.  */
+
+static bool
+c_parser_gimple_parse_bb_spec (tree val, int *index)
+{
+  if (strncmp (IDENTIFIER_POINTER (val), "__BB", 4) != 0)
+    return false;
+  for (const char *p = IDENTIFIER_POINTER (val) + 4; *p; ++p)
+    if (!ISDIGIT (*p))
+      return false;
+  *index = atoi (IDENTIFIER_POINTER (val) + 4);
+  return *index > 0;
+}
+
 /* Parse the body of a function declaration marked with "__GIMPLE".  */
 
 void
-c_parser_parse_gimple_body (c_parser *parser)
+c_parser_parse_gimple_body (c_parser *cparser, char *gimple_pass,
+			    enum c_declspec_il cdil)
 {
+  gimple_parser parser (cparser);
   gimple_seq seq = NULL;
   gimple_seq body = NULL;
   tree stmt = push_stmt_list ();
   push_scope ();
   location_t loc1 = c_parser_peek_token (parser)->location;
 
+  cfun->pass_startwith = gimple_pass;
   init_tree_ssa (cfun);
 
-  if (! c_parser_gimple_compound_statement (parser, &seq))
+  if (cdil == cdil_gimple)
+    /* While we have SSA names in the IL we do not have a CFG built yet
+       and PHIs are represented using a PHI internal function.  We do
+       have lowered control flow and exception handling (well, we do not
+       have parser support for EH yet).  But as we still have BINDs
+       we have to go through lowering again.  */
+    cfun->curr_properties = PROP_gimple_any;
+  else
+    {
+      /* We have at least cdil_gimple_cfg.  */
+      gimple_register_cfg_hooks ();
+      init_empty_tree_cfg ();
+      /* Initialize the bare loop structure - we are going to only
+         mark headers and leave the rest to fixup.  */
+      set_loops_for_fn (cfun, ggc_cleared_alloc<struct loops> ());
+      init_loops_structure (cfun, loops_for_fn (cfun), 1);
+      loops_state_set (cfun, LOOPS_NEED_FIXUP|LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
+      cfun->curr_properties
+	|= PROP_gimple_lcf | PROP_gimple_leh | PROP_cfg | PROP_loops;
+      if (cdil == cdil_gimple_ssa)
+	{
+	  init_ssa_operands (cfun);
+	  cfun->curr_properties |= PROP_ssa;
+	}
+    }
+
+  if (! c_parser_gimple_compound_statement (parser, &seq)
+      && cdil == cdil_gimple)
     {
       gimple *ret = gimple_build_return (NULL);
-      gimple_seq_add_stmt (&seq, ret);
+      gimple_seq_add_stmt_without_update (&seq, ret);
     }
 
   tree block = pop_scope ();
@@ -104,18 +192,87 @@ c_parser_parse_gimple_body (c_parser *parser)
   BLOCK_CHAIN (block) = NULL_TREE;
   TREE_ASM_WRITTEN (block) = 1;
 
-  gbind *bind_stmt = gimple_build_bind (BIND_EXPR_VARS (stmt), NULL,
-					BIND_EXPR_BLOCK (stmt));
-  gimple_bind_set_body (bind_stmt, seq);
-  gimple_seq_add_stmt (&body, bind_stmt);
-  gimple_set_body (current_function_decl, body);
+  if (cdil == cdil_gimple)
+    {
+      gbind *bind_stmt = gimple_build_bind (BIND_EXPR_VARS (stmt), NULL,
+					    BIND_EXPR_BLOCK (stmt));
+      gimple_bind_set_body (bind_stmt, seq);
+      gimple_seq_add_stmt_without_update (&body, bind_stmt);
+      gimple_set_body (current_function_decl, body);
+    }
+  else
+    {
+      /* Control-flow and binds are lowered, record local decls.  */
+      for (tree var = BIND_EXPR_VARS (stmt); var; var = DECL_CHAIN (var))
+	if (VAR_P (var)
+	    && !DECL_EXTERNAL (var))
+	  add_local_decl (cfun, var);
+      /* We have a CFG.  Build the edges.  */
+      for (unsigned i = 0; i < parser.edges.length (); ++i)
+	make_edge (BASIC_BLOCK_FOR_FN (cfun, parser.edges[i].src),
+		   BASIC_BLOCK_FOR_FN (cfun, parser.edges[i].dest),
+		   parser.edges[i].flags);
+      /* Add edges for case labels.  */
+      basic_block bb;
+      FOR_EACH_BB_FN (bb, cfun)
+	if (EDGE_COUNT (bb->succs) == 0)
+	  {
+	    gimple *last = last_stmt (bb);
+	    if (gswitch *sw = safe_dyn_cast <gswitch *> (last))
+	      for (unsigned i = 0; i < gimple_switch_num_labels (sw); ++i)
+		{
+		  basic_block label_bb = gimple_switch_label_bb (cfun, sw, i);
+		  make_edge (bb, label_bb, 0);
+		}
+	  }
+      /* Need those for loop fixup.  */
+      calculate_dominance_info (CDI_DOMINATORS);
+      /* With SSA lower PHIs parsed as internal function calls and
+	 update stmts.  */
+      if (cdil == cdil_gimple_ssa)
+	{
+	  /* Create PHI nodes, they are parsed into __PHI internal calls.  */
+	  FOR_EACH_BB_FN (bb, cfun)
+	    for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+		 !gsi_end_p (gsi);)
+	      {
+		gimple *stmt = gsi_stmt (gsi);
+		if (!gimple_call_internal_p (stmt, IFN_PHI))
+		  break;
 
-  /* While we have SSA names in the IL we do not have a CFG built yet
-     and PHIs are represented using a PHI internal function.  We do
-     have lowered control flow and exception handling (well, we do not
-     have parser support for EH yet).  But as we still have BINDs
-     we have to go through lowering again.  */
-  cfun->curr_properties = PROP_gimple_any;
+		gphi *phi = create_phi_node (gimple_call_lhs (stmt), bb);
+		for (unsigned i = 0; i < gimple_call_num_args (stmt); i += 2)
+		  {
+		    int srcidx = TREE_INT_CST_LOW (gimple_call_arg (stmt, i));
+		    edge e = find_edge (BASIC_BLOCK_FOR_FN (cfun, srcidx), bb);
+		    if (!e)
+		      c_parser_error (parser, "edge not found");
+		    else
+		      add_phi_arg (phi, gimple_call_arg (stmt, i + 1), e,
+				   UNKNOWN_LOCATION);
+		  }
+		gsi_remove (&gsi, false);
+	      }
+	  /* Fill SSA name gaps, putting them on the freelist.  */
+	  for (unsigned i = 0; i < num_ssa_names; ++i)
+	    if (!ssa_name (i))
+	      {
+		tree name = make_ssa_name_fn (cfun, integer_type_node, NULL, i);
+		release_ssa_name_fn (cfun, name);
+	      }
+	  /* No explicit virtual operands (yet).  */
+	  bitmap_obstack_initialize (NULL);
+	  update_ssa (TODO_update_ssa_only_virtuals);
+	  bitmap_obstack_release (NULL);
+	  /* ???  By flushing the freelist after virtual operand SSA rewrite
+	     we keep the gaps available for re-use like needed for the
+	     PR89595 testcase but then usually virtual operands would have
+	     taken most of them.  The fix is obviously to make virtual
+	     operands explicit in the SSA IL.  */
+	  flush_ssaname_freelist ();
+	}
+      fix_loop_structure (NULL);
+    }
 
   dump_function (TDI_gimple, current_function_decl);
 }
@@ -135,7 +292,7 @@ c_parser_parse_gimple_body (c_parser *parser)
 */
 
 static bool
-c_parser_gimple_compound_statement (c_parser *parser, gimple_seq *seq)
+c_parser_gimple_compound_statement (gimple_parser &parser, gimple_seq *seq)
 {
   bool return_p = false;
 
@@ -180,7 +337,7 @@ c_parser_gimple_compound_statement (c_parser *parser, gimple_seq *seq)
 		c_parser_consume_token (parser);
 		if (c_parser_next_token_is (parser, CPP_NAME))
 		  {
-		    c_parser_gimple_goto_stmt (loc,
+		    c_parser_gimple_goto_stmt (parser, loc,
 					       c_parser_peek_token
 					       (parser)->value,
 					       seq);
@@ -197,6 +354,8 @@ c_parser_gimple_compound_statement (c_parser *parser, gimple_seq *seq)
 	      if (! c_parser_require (parser, CPP_SEMICOLON,
 				      "expected %<;%>"))
 		return return_p;
+	      if (cfun->curr_properties & PROP_cfg)
+		parser.push_edge (parser.current_bb->index, EXIT_BLOCK, 0);
 	      break;
 	    default:
 	      goto expr_stmt;
@@ -208,6 +367,142 @@ c_parser_gimple_compound_statement (c_parser *parser, gimple_seq *seq)
 	      c_parser_gimple_label (parser, seq);
 	      break;
 	    }
+	  /* Basic block specification.
+	     __BB (index, ...)  */
+	  if ((cfun->curr_properties & PROP_cfg)
+	      && !strcmp (IDENTIFIER_POINTER
+			    (c_parser_peek_token (parser)->value), "__BB"))
+	    {
+	      c_parser_consume_token (parser);
+	      if (! c_parser_require (parser, CPP_OPEN_PAREN,
+				      "expected %<(%>"))
+		return return_p;
+	      if (c_parser_next_token_is_not (parser, CPP_NUMBER))
+		{
+		  c_parser_error (parser, "expected block index");
+		  return return_p;
+		}
+	      tree tnum = c_parser_peek_token (parser)->value;
+	      if (TREE_CODE (tnum) != INTEGER_CST)
+		{
+		  c_parser_error (parser, "expected block index");
+		  return return_p;
+		}
+	      int index = TREE_INT_CST_LOW (tnum);
+	      if (index < NUM_FIXED_BLOCKS
+		  || (index < last_basic_block_for_fn (cfun)
+		      && BASIC_BLOCK_FOR_FN (cfun, index) != NULL))
+		{
+		  c_parser_error (parser, "invalid block index");
+		  return return_p;
+		}
+	      int is_loop_header_of = -1;
+	      c_parser_consume_token (parser);
+	      while (c_parser_next_token_is (parser, CPP_COMMA))
+		{
+		  c_parser_consume_token (parser);
+		  if (! c_parser_next_token_is (parser, CPP_NAME))
+		    {
+		      c_parser_error (parser, "expected block specifier");
+		      return return_p;
+		    }
+		  /* loop_header (NUM)  */
+		  if (!strcmp (IDENTIFIER_POINTER
+			         (c_parser_peek_token (parser)->value),
+			       "loop_header"))
+		    {
+		      c_parser_consume_token (parser);
+		      if (! c_parser_require (parser, CPP_OPEN_PAREN,
+					      "expected %<(%>"))
+			return return_p;
+		      tree loop_num;
+		      if (! c_parser_next_token_is (parser, CPP_NUMBER)
+			  || TREE_CODE (loop_num
+					  = c_parser_peek_token (parser)->value)
+			       != INTEGER_CST)
+			{
+			  c_parser_error (parser, "expected loop number");
+			  return return_p;
+			}
+		      c_parser_consume_token (parser);
+		      is_loop_header_of = TREE_INT_CST_LOW (loop_num);
+		      if (! c_parser_require (parser, CPP_CLOSE_PAREN,
+					      "expected %<)%>"))
+			return return_p;
+		    }
+		  else
+		    {
+		      c_parser_error (parser, "unknown block specifier");
+		      return return_p;
+		    }
+		}
+	      if (! c_parser_require (parser, CPP_CLOSE_PAREN,
+				      "expected %<)%>")
+		  || ! c_parser_require (parser, CPP_COLON,
+					 "expected %<:%>"))
+		return return_p;
+
+	      /* Put stmts parsed in the current block.  */
+	      if (!gimple_seq_empty_p (*seq))
+		{
+		  if (!parser.current_bb)
+		    c_parser_error (parser, "stmts without block");
+		  else
+		    {
+		      gimple_stmt_iterator gsi
+			= gsi_start_bb (parser.current_bb);
+		      gsi_insert_seq_after (&gsi, *seq, GSI_CONTINUE_LINKING);
+		    }
+		  *seq = NULL;
+		}
+
+	      /* Build an empty block with specified index, linking them
+		 in source order.  */
+	      basic_block bb = alloc_block ();
+	      bb->index = index;
+	      link_block (bb, (parser.current_bb ? parser.current_bb
+			       : ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+	      if (basic_block_info_for_fn (cfun)->length () <= (size_t)index)
+		vec_safe_grow_cleared (basic_block_info_for_fn (cfun),
+				       index + 1);
+	      SET_BASIC_BLOCK_FOR_FN (cfun, index, bb);
+	      if (last_basic_block_for_fn (cfun) <= index)
+		last_basic_block_for_fn (cfun) = index + 1;
+	      n_basic_blocks_for_fn (cfun)++;
+	      if (!parser.current_bb)
+		parser.push_edge (ENTRY_BLOCK, bb->index, EDGE_FALLTHRU);
+
+	      /* We leave the proper setting to fixup.  */
+	      struct loop *loop_father = loops_for_fn (cfun)->tree_root;
+	      /* If the new block is a loop header, allocate a loop
+		 struct.  Fixup will take care of proper placement within
+		 the loop tree.  */
+	      if (is_loop_header_of != -1)
+		{
+		  if (number_of_loops (cfun) > (unsigned)is_loop_header_of
+		      && get_loop (cfun, is_loop_header_of) != NULL)
+		    {
+		      c_parser_error (parser, "duplicate loop header");
+		    }
+		  else
+		    {
+		      struct loop *loop = alloc_loop ();
+		      loop->num = is_loop_header_of;
+		      loop->header = bb;
+		      vec_safe_grow_cleared (loops_for_fn (cfun)->larray,
+					     is_loop_header_of + 1);
+		      (*loops_for_fn (cfun)->larray)[is_loop_header_of] = loop;
+		      flow_loop_tree_node_add (loops_for_fn (cfun)->tree_root,
+					       loop);
+		    }
+		  loop_father = get_loop (cfun, is_loop_header_of);
+		}
+	      bb->loop_father = loop_father;
+
+	      /* Stmts now go to the new block.  */
+	      parser.current_bb = bb;
+	      break;
+	    }
 	  goto expr_stmt;
 
 	case CPP_SEMICOLON:
@@ -217,7 +512,7 @@ c_parser_gimple_compound_statement (c_parser *parser, gimple_seq *seq)
 	    c_parser_consume_token (parser);
 	    gimple *nop = gimple_build_nop ();
 	    gimple_set_location (nop, loc);
-	    gimple_seq_add_stmt (seq, nop);
+	    gimple_seq_add_stmt_without_update (seq, nop);
 	    break;
 	  }
 
@@ -229,6 +524,21 @@ expr_stmt:
 	}
     }
   c_parser_consume_token (parser);
+
+  /* Put stmts parsed in the current block.  */
+  if ((cfun->curr_properties & PROP_cfg)
+      && !gimple_seq_empty_p (*seq))
+    {
+      if (!parser.current_bb)
+	c_parser_error (parser, "stmts without block");
+      else
+	{
+	  gimple_stmt_iterator gsi = gsi_start_bb (parser.current_bb);
+	  gsi_insert_seq_after (&gsi, *seq, GSI_CONTINUE_LINKING);
+	}
+      *seq = NULL;
+    }
+
   return return_p;
 }
 
@@ -260,7 +570,7 @@ expr_stmt:
 */
 
 static void
-c_parser_gimple_statement (c_parser *parser, gimple_seq *seq)
+c_parser_gimple_statement (gimple_parser &parser, gimple_seq *seq)
 {
   struct c_expr lhs, rhs;
   gimple *assign = NULL;
@@ -278,7 +588,7 @@ c_parser_gimple_statement (c_parser *parser, gimple_seq *seq)
     {
       gimple *call;
       call = gimple_build_call_from_tree (lhs.value, NULL);
-      gimple_seq_add_stmt (seq, call);
+      gimple_seq_add_stmt_without_update (seq, call);
       gimple_set_location (call, loc);
       return;
     }
@@ -316,7 +626,7 @@ c_parser_gimple_statement (c_parser *parser, gimple_seq *seq)
 		   && FLOAT_TYPE_P (TREE_TYPE (rhs.value)))
 	    code = FIX_TRUNC_EXPR;
 	  assign = gimple_build_assign (lhs.value, code, rhs.value);
-	  gimple_seq_add_stmt (seq, assign);
+	  gimple_seq_add_stmt_without_update (seq, assign);
 	  gimple_set_location (assign, loc);
 	  return;
 	}
@@ -350,7 +660,7 @@ c_parser_gimple_statement (c_parser *parser, gimple_seq *seq)
 	{
 	  assign = gimple_build_assign (lhs.value, rhs.value);
 	  gimple_set_location (assign, loc);
-	  gimple_seq_add_stmt (seq, assign);
+	  gimple_seq_add_stmt_without_update (seq, assign);
 	}
       return;
 
@@ -373,13 +683,14 @@ c_parser_gimple_statement (c_parser *parser, gimple_seq *seq)
 	  if (c_parser_next_token_is (parser, CPP_NAME)
 	      && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
 	    {
-	      arg = lookup_label_for_goto (loc,
-					   c_parser_peek_token (parser)->value);
+	      arg = 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);
+	      int src_index = -1;
+	      if (!c_parser_gimple_parse_bb_spec (arg, &src_index))
+		c_parser_error (parser, "invalid source block specification");
+	      vargs.safe_push (size_int (src_index));
 	    }
 	  else if (c_parser_next_token_is (parser, CPP_COMMA))
 	    c_parser_consume_token (parser);
@@ -397,7 +708,7 @@ c_parser_gimple_statement (c_parser *parser, gimple_seq *seq)
       gcall *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);
+      gimple_seq_add_stmt_without_update (seq, call_stmt);
       return;
     }
 
@@ -412,7 +723,7 @@ c_parser_gimple_statement (c_parser *parser, gimple_seq *seq)
 	{
 	  gimple *call = gimple_build_call_from_tree (rhs.value, NULL);
 	  gimple_call_set_lhs (call, lhs.value);
-	  gimple_seq_add_stmt (seq, call);
+	  gimple_seq_add_stmt_without_update (seq, call);
 	  gimple_set_location (call, loc);
 	}
       return;
@@ -440,7 +751,7 @@ c_parser_gimple_statement (c_parser *parser, gimple_seq *seq)
 				  rhs.value, trueval.value, falseval.value);
 	}
       assign = gimple_build_assign (lhs.value, rhs.value);
-      gimple_seq_add_stmt (seq, assign);
+      gimple_seq_add_stmt_without_update (seq, assign);
       gimple_set_location (assign, loc);
     }
   return;
@@ -470,7 +781,7 @@ c_parser_gimple_statement (c_parser *parser, gimple_seq *seq)
 */
 
 static c_expr
-c_parser_gimple_binary_expression (c_parser *parser)
+c_parser_gimple_binary_expression (gimple_parser &parser)
 {
   /* Location of the binary operator.  */
   struct c_expr ret, lhs, rhs;
@@ -578,7 +889,7 @@ c_parser_gimple_binary_expression (c_parser *parser)
 */
 
 static c_expr
-c_parser_gimple_unary_expression (c_parser *parser)
+c_parser_gimple_unary_expression (gimple_parser &parser)
 {
   struct c_expr ret, op;
   location_t op_loc = c_parser_peek_token (parser)->location;
@@ -687,7 +998,7 @@ c_parser_parse_ssa_name_id (tree id, unsigned *version, unsigned *ver_offset)
    TYPE is the type if the SSA name is being declared.  */
 
 static tree 
-c_parser_parse_ssa_name (c_parser *parser,
+c_parser_parse_ssa_name (gimple_parser &parser,
 			 tree id, tree type, unsigned version,
 			 unsigned ver_offset)
 {
@@ -752,7 +1063,7 @@ c_parser_parse_ssa_name (c_parser *parser,
      . identifier ( gimple-argument-expression-list[opt] )  */
 
 static struct c_expr
-c_parser_gimple_call_internal (c_parser *parser)
+c_parser_gimple_call_internal (gimple_parser &parser)
 {
   struct c_expr expr;
   expr.set_error ();
@@ -812,7 +1123,7 @@ c_parser_gimple_call_internal (c_parser *parser)
 */
 
 static struct c_expr
-c_parser_gimple_postfix_expression (c_parser *parser)
+c_parser_gimple_postfix_expression (gimple_parser &parser)
 {
   location_t loc = c_parser_peek_token (parser)->location;
   source_range tok_range = c_parser_peek_token (parser)->get_range ();
@@ -1102,7 +1413,7 @@ c_parser_gimple_postfix_expression (c_parser *parser)
    literal.  */
 
 static struct c_expr
-c_parser_gimple_postfix_expression_after_primary (c_parser *parser,
+c_parser_gimple_postfix_expression_after_primary (gimple_parser &parser,
 						  location_t expr_loc,
 						  struct c_expr expr)
 {
@@ -1245,7 +1556,7 @@ c_parser_gimple_postfix_expression_after_primary (c_parser *parser,
  */
 
 static void
-c_parser_gimple_expr_list (c_parser *parser, vec<tree> *ret)
+c_parser_gimple_expr_list (gimple_parser &parser, vec<tree> *ret)
 {
   struct c_expr expr;
 
@@ -1269,7 +1580,7 @@ c_parser_gimple_expr_list (c_parser *parser, vec<tree> *ret)
 */
 
 static void
-c_parser_gimple_label (c_parser *parser, gimple_seq *seq)
+c_parser_gimple_label (gimple_parser &parser, gimple_seq *seq)
 {
   tree name = c_parser_peek_token (parser)->value;
   location_t loc1 = c_parser_peek_token (parser)->location;
@@ -1278,58 +1589,67 @@ c_parser_gimple_label (c_parser *parser, gimple_seq *seq)
   gcc_assert (c_parser_next_token_is (parser, CPP_COLON));
   c_parser_consume_token (parser);
   tree label = define_label (loc1, name);
-  gimple_seq_add_stmt (seq, gimple_build_label (label));
+  gimple_seq_add_stmt_without_update (seq, gimple_build_label (label));
   return;
 }
 
 /* Parse gimple/RTL pass list.
 
    gimple-or-rtl-pass-list:
-     startwith("pass-name")
+     startwith("pass-name")[,{cfg,ssa}]
  */
 
-char *
-c_parser_gimple_or_rtl_pass_list (c_parser *parser)
+void
+c_parser_gimple_or_rtl_pass_list (c_parser *parser, c_declspecs *specs)
 {
   char *pass = NULL;
 
   /* Accept __GIMPLE/__RTL.  */
   if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
-    return NULL;
+    return;
   c_parser_consume_token (parser);
 
-  if (c_parser_next_token_is (parser, CPP_NAME))
+  while (c_parser_next_token_is (parser, CPP_NAME))
     {
       const char *op = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
       c_parser_consume_token (parser);
       if (! strcmp (op, "startwith"))
 	{
 	  if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
-	    return NULL;
+	    return;
 	  if (c_parser_next_token_is_not (parser, CPP_STRING))
 	    {
 	      error_at (c_parser_peek_token (parser)->location,
 			"expected pass name");
-	      return NULL;
+	      return;
 	    }
 	  pass = xstrdup (TREE_STRING_POINTER
 				(c_parser_peek_token (parser)->value));
 	  c_parser_consume_token (parser);
-	  if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
-	    return NULL;
+	  if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<(%>"))
+	    return;
 	}
+      else if (specs->declspec_il != cdil_gimple)
+	/* Allow only one IL specifier and none on RTL.  */
+	;
+      else if (! strcmp (op, "cfg"))
+	specs->declspec_il = cdil_gimple_cfg;
+      else if (! strcmp (op, "ssa"))
+	specs->declspec_il = cdil_gimple_ssa;
       else
 	{
 	  error_at (c_parser_peek_token (parser)->location,
 		    "invalid operation");
-	  return NULL;
+	  return;
 	}
+     if (c_parser_next_token_is (parser, CPP_COMMA))
+       c_parser_consume_token (parser);
     }
 
   if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
-    return NULL;
+    return;
 
-  return pass;
+  specs->gimple_or_rtl_pass = pass;
 }
 
 /* Parse gimple local declaration.
@@ -1371,7 +1691,7 @@ c_parser_gimple_or_rtl_pass_list (c_parser *parser)
  */
 
 static void
-c_parser_gimple_declaration (c_parser *parser)
+c_parser_gimple_declaration (gimple_parser &parser)
 {
   struct c_declarator *declarator;
   struct c_declspecs *specs = build_null_declspecs ();
@@ -1431,11 +1751,21 @@ c_parser_gimple_declaration (c_parser *parser)
 /* Parse gimple goto statement.  */
 
 static void
-c_parser_gimple_goto_stmt (location_t loc, tree label, gimple_seq *seq)
+c_parser_gimple_goto_stmt (gimple_parser &parser,
+			   location_t loc, tree label, gimple_seq *seq)
 {
+  if (cfun->curr_properties & PROP_cfg)
+    {
+      int dest_index;
+      if (c_parser_gimple_parse_bb_spec (label, &dest_index))
+	{
+	  parser.push_edge (parser.current_bb->index, dest_index,
+			    EDGE_FALLTHRU);
+	  return;
+	}
+    }
   tree decl = lookup_label_for_goto (loc, label);
-  gimple_seq_add_stmt (seq, gimple_build_goto (decl));
-  return;
+  gimple_seq_add_stmt_without_update (seq, gimple_build_goto (decl));
 }
 
 /* Parse a parenthesized condition.
@@ -1443,7 +1773,7 @@ c_parser_gimple_goto_stmt (location_t loc, tree label, gimple_seq *seq)
      ( gimple-binary-expression )    */
 
 static tree
-c_parser_gimple_paren_condition (c_parser *parser)
+c_parser_gimple_paren_condition (gimple_parser &parser)
 {
   if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     return error_mark_node;
@@ -1462,9 +1792,9 @@ c_parser_gimple_paren_condition (c_parser *parser)
  */
 
 static void
-c_parser_gimple_if_stmt (c_parser *parser, gimple_seq *seq)
+c_parser_gimple_if_stmt (gimple_parser &parser, gimple_seq *seq)
 {
-  tree t_label, f_label, label;
+  tree t_label = NULL_TREE, f_label = NULL_TREE, label;
   location_t loc;
   c_parser_consume_token (parser);
   tree cond = c_parser_gimple_paren_condition (parser);
@@ -1480,7 +1810,13 @@ c_parser_gimple_if_stmt (c_parser *parser, gimple_seq *seq)
 	}
       label = c_parser_peek_token (parser)->value;
       c_parser_consume_token (parser);
-      t_label = lookup_label_for_goto (loc, label);
+      int dest_index;
+      if ((cfun->curr_properties & PROP_cfg)
+	  && c_parser_gimple_parse_bb_spec (label, &dest_index))
+	parser.push_edge (parser.current_bb->index, dest_index,
+			  EDGE_TRUE_VALUE);
+      else
+	t_label = lookup_label_for_goto (loc, label);
       if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
 	return;
     }
@@ -1508,7 +1844,13 @@ c_parser_gimple_if_stmt (c_parser *parser, gimple_seq *seq)
 	  return;
 	}
       label = c_parser_peek_token (parser)->value;
-      f_label = lookup_label_for_goto (loc, label);
+      int dest_index;
+      if ((cfun->curr_properties & PROP_cfg)
+	  && c_parser_gimple_parse_bb_spec (label, &dest_index))
+	parser.push_edge (parser.current_bb->index, dest_index,
+			  EDGE_FALSE_VALUE);
+      else
+	f_label = lookup_label_for_goto (loc, label);
       c_parser_consume_token (parser);
       if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
 	return;
@@ -1520,7 +1862,7 @@ c_parser_gimple_if_stmt (c_parser *parser, gimple_seq *seq)
     }
 
   if (cond != error_mark_node)
-    gimple_seq_add_stmt (seq, gimple_build_cond_from_tree (cond, t_label,
+    gimple_seq_add_stmt_without_update (seq, gimple_build_cond_from_tree (cond, t_label,
 							   f_label));
 }
 
@@ -1535,13 +1877,12 @@ c_parser_gimple_if_stmt (c_parser *parser, gimple_seq *seq)
 */
 
 static void
-c_parser_gimple_switch_stmt (c_parser *parser, gimple_seq *seq)
+c_parser_gimple_switch_stmt (gimple_parser &parser, gimple_seq *seq)
 {
   c_expr cond_expr;
   tree case_label, label;
   auto_vec<tree> labels;
   tree default_label = NULL_TREE;
-  gimple_seq switch_body = NULL;
   c_parser_consume_token (parser);
 
   if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
@@ -1629,32 +1970,8 @@ c_parser_gimple_switch_stmt (c_parser *parser, gimple_seq *seq)
 	      return;
 	    break;
 	  }
-	case RID_GOTO:
-	  {
-	    location_t loc = c_parser_peek_token (parser)->location;
-	    c_parser_consume_token (parser);
-	    if (c_parser_next_token_is (parser, CPP_NAME))
-	      {
-		c_parser_gimple_goto_stmt (loc,
-					   c_parser_peek_token
-					   (parser)->value,
-					   &switch_body);
-		c_parser_consume_token (parser);
-		if (c_parser_next_token_is (parser, CPP_SEMICOLON))
-		  c_parser_consume_token (parser);
-		else
-		  {
-		    c_parser_error (parser, "expected semicolon");
-		    return;
-		  }
-	      }
-	    else if (! c_parser_require (parser, CPP_NAME,
-					 "expected label"))
-	      return;
-	    break;
-	  }
 	default:
-	  c_parser_error (parser, "expected case label or goto statement");
+	  c_parser_error (parser, "expected case label");
 	  return;
 	}
 
@@ -1664,16 +1981,15 @@ c_parser_gimple_switch_stmt (c_parser *parser, gimple_seq *seq)
 
   if (cond_expr.value != error_mark_node)
     {
-      gimple_seq_add_stmt (seq, gimple_build_switch (cond_expr.value,
-						     default_label, labels));
-      gimple_seq_add_seq (seq, switch_body);
+      gswitch *s = gimple_build_switch (cond_expr.value, default_label, labels);
+      gimple_seq_add_stmt_without_update (seq, s);
     }
 }
 
 /* Parse gimple return statement.  */
 
 static void
-c_parser_gimple_return_stmt (c_parser *parser, gimple_seq *seq)
+c_parser_gimple_return_stmt (gimple_parser &parser, gimple_seq *seq)
 {
   location_t loc = c_parser_peek_token (parser)->location;
   gimple *ret = NULL;
@@ -1682,7 +1998,7 @@ c_parser_gimple_return_stmt (c_parser *parser, gimple_seq *seq)
     {
       c_finish_gimple_return (loc, NULL_TREE);
       ret = gimple_build_return (NULL);
-      gimple_seq_add_stmt (seq, ret);
+      gimple_seq_add_stmt_without_update (seq, ret);
     }
   else
     {
@@ -1692,7 +2008,7 @@ c_parser_gimple_return_stmt (c_parser *parser, gimple_seq *seq)
 	{
 	  c_finish_gimple_return (xloc, expr.value);
 	  ret = gimple_build_return (expr.value);
-	  gimple_seq_add_stmt (seq, ret);
+	  gimple_seq_add_stmt_without_update (seq, ret);
 	}
     }
 }
diff --git a/gcc/c/gimple-parser.h b/gcc/c/gimple-parser.h
index ae912ee4777..383ad768759 100644
--- a/gcc/c/gimple-parser.h
+++ b/gcc/c/gimple-parser.h
@@ -21,7 +21,8 @@ along with GCC; see the file COPYING3.  If not see
 #define GCC_GIMPLE_PARSER_H
 
 /* Gimple parsing functions.  */
-extern void c_parser_parse_gimple_body (c_parser *);
-extern char *c_parser_gimple_or_rtl_pass_list (c_parser *);
+extern void c_parser_parse_gimple_body (c_parser *, char *,
+					enum c_declspec_il);
+extern void c_parser_gimple_or_rtl_pass_list (c_parser *, c_declspecs *);
 
 #endif
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 45ef09e8241..69bae0d10d0 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "attribs.h"
 #include "asan.h"
+#include "cfgloop.h"
 
 #define INDENT(SPACE)							\
   do { int i; for (i = 0; i < SPACE; i++) pp_space (buffer); } while (0)
@@ -2221,18 +2222,11 @@ dump_gimple_phi (pretty_printer *buffer, gphi *phi, int spc, bool comment,
     {
       if ((flags & TDF_LINENO) && gimple_phi_arg_has_location (phi, i))
 	dump_location (buffer, gimple_phi_arg_location (phi, i));
+      basic_block src = gimple_phi_arg_edge (phi, i)->src;
       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, "__BB");
+	  pp_decimal_int (buffer, src->index);
 	  pp_string (buffer, ": ");
 	}
       dump_generic_node (buffer, gimple_phi_arg_def (phi, i), spc, flags,
@@ -2240,7 +2234,7 @@ dump_gimple_phi (pretty_printer *buffer, gphi *phi, int spc, bool comment,
       if (! (flags & TDF_GIMPLE))
 	{
 	  pp_left_paren (buffer);
-	  pp_decimal_int (buffer, gimple_phi_arg_edge (phi, i)->src->index);
+	  pp_decimal_int (buffer, src->index);
 	  pp_right_paren (buffer);
 	}
       if (i < gimple_phi_num_args (phi) - 1)
@@ -2706,7 +2700,12 @@ dump_gimple_bb_header (FILE *outf, basic_block bb, int indent,
   else
     {
       if (flags & TDF_GIMPLE)
-	fprintf (outf, "%*sbb_%d:\n", indent, "", bb->index);
+	{
+	  fprintf (outf, "%*s__BB(%d", indent, "", bb->index);
+	  if (bb->loop_father->header == bb)
+	    fprintf (outf, ",loop_header(%d)", bb->loop_father->num);
+	  fprintf (outf, "):\n");
+	}
       else
 	fprintf (outf, "%*s<bb %d> %s:\n",
 		 indent, "", bb->index, dump_profile (bb->count));
@@ -2759,7 +2758,7 @@ pp_cfg_jump (pretty_printer *buffer, edge e, dump_flags_t flags)
 {
   if (flags & TDF_GIMPLE)
     {
-      pp_string (buffer, "goto bb_");
+      pp_string (buffer, "goto __BB");
       pp_decimal_int (buffer, e->dest->index);
       pp_semicolon (buffer);
     }
@@ -2812,7 +2811,7 @@ dump_implicit_edges (pretty_printer *buffer, basic_block bb, int indent,
      goto to the dump.  */
   e = find_fallthru_edge (bb->succs);
 
-  if (e && e->dest != bb->next_bb)
+  if (e && (e->dest != bb->next_bb || (flags & TDF_GIMPLE)))
     {
       INDENT (indent);
 
diff --git a/gcc/testsuite/gcc.dg/gimplefe-13.c b/gcc/testsuite/gcc.dg/gimplefe-13.c
index f0af7611fb9..dc326861c0f 100644
--- a/gcc/testsuite/gcc.dg/gimplefe-13.c
+++ b/gcc/testsuite/gcc.dg/gimplefe-13.c
@@ -1,25 +1,26 @@
 /* { dg-do compile } */
 /* { dg-options "-O -fgimple" } */
 
-void __GIMPLE (startwith ("dse2")) foo ()
+void __GIMPLE (ssa,startwith ("dse2")) foo ()
 {
   int a;
 
-bb_2:
-  if (a > 4)
-    goto bb_3;
+__BB(2):
+  if (a_5(D) > 4)
+    goto __BB3;
   else
-    goto bb_4;
+    goto __BB4;
 
-bb_3:
+__BB(3):
   a_2 = 10;
-  goto bb_5;
+  goto __BB5;
 
-bb_4:
+__BB(4):
   a_3 = 20;
+  goto __BB5;
 
-bb_5:
-  a_1 = __PHI (bb_3: a_2, bb_4: a_3);
+__BB(5):
+  a_1 = __PHI (__BB3: a_2, __BB4: 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
index 15022297703..a9e9d8141f0 100644
--- a/gcc/testsuite/gcc.dg/gimplefe-14.c
+++ b/gcc/testsuite/gcc.dg/gimplefe-14.c
@@ -1,29 +1,33 @@
 /* { dg-do run } */
 /* { dg-options "-O -fgimple" } */
 
-int __GIMPLE ()
+int __GIMPLE (ssa)
 main (int argc, char * * argv)
 {
   int a;
 
-  bb_2:
+  __BB(2):
   /* Because of PR82114 we need to handle also 0 as base metal can have
      argc == 0.  */
   switch (argc_2(D)) {default: L2; case 0: L0; case 1: L0; case 2: L1; }
 
+  __BB(3):
 L0:
   a_4 = 0;
-  goto bb_6;
+  goto __BB6;
 
+  __BB(4):
 L1:
   a_3 = 3;
-  goto bb_6;
+  goto __BB6;
 
+  __BB(5):
 L2:
   a_5 = -1;
+  goto __BB6;
 
-  bb_6:
-  a_1 = __PHI (L0: a_4, L1: a_3, L2: a_5);
+  __BB(6):
+  a_1 = __PHI (__BB3: a_4, __BB4: a_3, __BB5: a_5);
   return a_1;
 
 }
diff --git a/gcc/testsuite/gcc.dg/gimplefe-17.c b/gcc/testsuite/gcc.dg/gimplefe-17.c
index c5633eee34f..eceefd153ef 100644
--- a/gcc/testsuite/gcc.dg/gimplefe-17.c
+++ b/gcc/testsuite/gcc.dg/gimplefe-17.c
@@ -1,26 +1,31 @@
 /* { dg-do compile } */
-/* { dg-options "-fgimple -fdump-tree-ssa" } */
+/* { dg-options "-fgimple -fdump-tree-fixup_cfg2" } */
 
 int 
-__GIMPLE () *
+__GIMPLE (ssa) *
 foo ()
 {
   int _1;
   int j;
   int *b;
+
+__BB(5):
   _1 = 1;
-bb1:
+  goto __BB2;
+
+__BB(2):
   if (_1)
-    goto bb3;
+    goto __BB4;
   else
-    goto bb2;
+    goto __BB3;
 
-bb2:
+__BB(3):
   b_2 = (int *)0;
+  goto __BB4;
 
-bb3:
-  b_4 = __PHI (bb1: b_3(D), bb2: b_2);
+__BB(4):
+  b_4 = __PHI (__BB2: b_3(D), __BB3: b_2);
   return b_4;
 }
 
-/* { dg-final { scan-tree-dump-not "_1_" "ssa" } } */
+/* { dg-final { scan-tree-dump-not "_1_" "fixup_cfg2" } } */
diff --git a/gcc/testsuite/gcc.dg/gimplefe-18.c b/gcc/testsuite/gcc.dg/gimplefe-18.c
index ba918b2bc04..18fabbe1e66 100644
--- a/gcc/testsuite/gcc.dg/gimplefe-18.c
+++ b/gcc/testsuite/gcc.dg/gimplefe-18.c
@@ -2,23 +2,28 @@
 /* { dg-options "-fgimple" } */
 
 int
-__GIMPLE () *
+__GIMPLE (ssa) *
 foo ()
 {
   int _1;
   int j;
   int *b;
+
+__BB(2):
   _1 = 1;
-bb1:
+  goto __BB3;
+
+__BB(3):
   if (_1)
-    goto bb3;
+    goto __BB5;
   else
-    goto bb2;
+    goto __BB4;
 
-bb2:
+__BB(4):
   b_2 = (int *)0;
+  goto __BB5;
 
-bb3:
-  b_4 = __PHI (bb1: &j, bb2: b_2);
+__BB(5):
+  b_4 = __PHI (__BB3: &j, __BB4: b_2);
   return b_4;
 }
diff --git a/gcc/testsuite/gcc.dg/gimplefe-7.c b/gcc/testsuite/gcc.dg/gimplefe-7.c
index 61255412ab5..ad34e85b502 100644
--- a/gcc/testsuite/gcc.dg/gimplefe-7.c
+++ b/gcc/testsuite/gcc.dg/gimplefe-7.c
@@ -1,25 +1,26 @@
 /* { dg-do compile } */
 /* { dg-options "-fgimple" } */
 
-void __GIMPLE () foo ()
+void __GIMPLE (ssa) foo ()
 {
   int a;
 
-bb_2:
-  if (a > 4)
-    goto bb_3;
+__BB(2):
+  if (a_5(D) > 4)
+    goto __BB3;
   else
-    goto bb_4;
+    goto __BB4;
 
-bb_3:
+__BB(3):
   a_2 = 10;
-  goto bb_5;
+  goto __BB5;
 
-bb_4:
+__BB(4):
   a_3 = 20;
+  goto __BB5;
 
-bb_5:
-  a_1 = __PHI (bb_3: a_2, bb_4: a_3);
+__BB(5):
+  a_1 = __PHI (__BB3: a_2, __BB4: a_3);
   a_4 = a_1 + 4;
 
 return;
diff --git a/gcc/testsuite/gcc.dg/torture/pr89595.c b/gcc/testsuite/gcc.dg/torture/pr89595.c
index ebd834f32a4..f45dc98c3f0 100644
--- a/gcc/testsuite/gcc.dg/torture/pr89595.c
+++ b/gcc/testsuite/gcc.dg/torture/pr89595.c
@@ -2,33 +2,35 @@
 /* { dg-additional-options "-fgimple" } */
 
 int __attribute__((noipa))
-__GIMPLE(startwith("dom")) bar(int cond, int val)
+__GIMPLE(ssa,startwith("dom")) bar(int cond, int val)
 {
   int i;
 
+__BB(3):
   if (0 != 0)
-    goto bb_6;
+    goto __BB6;
   else
-    goto bb_2;
+    goto __BB2;
 
-bb_2:
+__BB(2):
   if (cond_5(D) != 0)
-    goto bb_4;
+    goto __BB4;
   else
-    goto bb_5;
+    goto __BB5;
 
-bb_4:
+__BB(4):
   i_6 = val_2(D);
   i_1 = val_2(D) > 0 ? i_6 : 0;
+  goto __BB5;
 
-bb_5:
-  i_3 = __PHI (bb_4: i_1, bb_2: 0);
+__BB(5):
+  i_3 = __PHI (__BB4: i_1, __BB2: 0);
   return i_3;
 
-bb_6:
+__BB(6):
   i_4 = 1;
   i_9 = 2;
-  goto bb_2;
+  goto __BB2;
 }
 
 int main()
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cunroll-13.c b/gcc/testsuite/gcc.dg/tree-ssa/cunroll-13.c
index 096380ab5aa..98cb56a8564 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/cunroll-13.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/cunroll-13.c
@@ -9,7 +9,7 @@ typedef int i32;
 
 struct a {i32 a[8];i32 b;};
 
-void __GIMPLE (startwith("fix_loops"))
+void __GIMPLE (ssa,startwith("fix_loops"))
 t (struct a * a)
 {
   i32 i;
@@ -18,37 +18,37 @@ t (struct a * a)
   i32 _9;
   i32 _11;
 
-bb_2:
+__BB(2):
   _11 = a_6(D)->a[0];
   if (_11 != _Literal (i32) 0)
-    goto bb_6;
+    goto __BB6;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_3:
+__BB(3):
   return;
 
-bb_4:
+__BB(4):
   _1 = _2 + _Literal (i32) 1;
   a_6(D)->a[i_19] = _1;
   i_8 = i_19 + _Literal (i32) 1;
   if (i_8 <= _Literal (i32) 123455)
-    goto bb_5;
+    goto __BB5;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_5:
-  i_19 = __PHI (bb_6: _Literal (i32) 1, bb_4: i_8);
+__BB(5):
+  i_19 = __PHI (__BB6: _Literal (i32) 1, __BB4: i_8);
   _2 = a_6(D)->a[i_19];
   if (_2 != _Literal (i32) 0)
-    goto bb_4;
+    goto __BB4;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_6:
+__BB(6):
   _9 = _11 + _Literal (i32) 1;
   a_6(D)->a[0] = _9;
-  goto bb_5;
+  goto __BB5;
 }
 
 /* This testcase relies on the fact that we do not eliminate the redundant test
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_1g.c b/gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_1g.c
index ac1346c7663..3f2132b1161 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_1g.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_1g.c
@@ -15,7 +15,7 @@ foo (long int * p, long int * p2, int N1, int N2)
   long unsigned int _4;
   long int _5;
 
-  bb_2:
+  __BB(2):
   _1 = (long unsigned int) N1_10(D);
   _2 = _1 * 8ul;
   p_limit_12 = p_11(D) + _2;
@@ -23,59 +23,60 @@ foo (long int * p, long int * p2, int N1, int N2)
   _4 = _3 * 8ul;
   p_limit2_15 = p2_14(D) + _4;
   if (p_11(D) <= p_limit_12)
-    goto bb_3;
+    goto __BB3;
   else
-    goto bb_13;
+    goto __BB13;
 
-  bb_13:
+  __BB(13):
+  goto __BB9;
 
-  bb_9:
-  goto bb_6;
+  __BB(9):
+  goto __BB6;
 
-  bb_3:
+  __BB(3):
   p_20 = p_11(D) + 8ul;
   p2_23 = p2_14(D) + 8ul;
   if (p_limit2_15 < p2_23)
-    goto bb_14;
+    goto __BB14;
   else
-    goto bb_7;
+    goto __BB7;
 
-  bb_14:
-  goto bb_9;
+  __BB(14):
+  goto __BB9;
 
-  bb_7:
-  goto bb_5;
+  __BB(7):
+  goto __BB5;
 
-  bb_4:
+  __BB(4):
   p_16 = p_26 + 8ul;
   p2_17 = p2_27 + 8ul;
   if (p_limit2_15 < p2_17)
-    goto bb_11;
+    goto __BB11;
   else
-    goto bb_8;
+    goto __BB8;
 
-  bb_11:
-  goto bb_6;
+  __BB(11):
+  goto __BB6;
 
-  bb_8:
-  ;
+  __BB(8):
+  goto __BB5;
 
-  bb_5:
-  s_24 = __PHI (bb_7: 0l, bb_8: s_19);
-  p_26 = __PHI (bb_7: p_20, bb_8: p_16);
-  p2_27 = __PHI (bb_7: p2_23, bb_8: p2_17);
+  __BB(5):
+  s_24 = __PHI (__BB7: 0l, __BB8: s_19);
+  p_26 = __PHI (__BB7: p_20, __BB8: p_16);
+  p2_27 = __PHI (__BB7: p2_23, __BB8: p2_17);
   _5 = __MEM <long int> (p_26);
   s_19 = _5 + s_24;
   if (p_limit_12 >= p_26)
-    goto bb_4;
+    goto __BB4;
   else
-    goto bb_12;
+    goto __BB12;
 
-  bb_12:
-  ;
+  __BB(12):
+  goto __BB6;
 
-  bb_6:
-  s_25 = __PHI (bb_12: s_19, bb_11: s_19, bb_9: 0l);
+  __BB(6):
+  s_25 = __PHI (__BB12: s_19, __BB11: s_19, __BB9: 0l);
   return s_25;
 }
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_2g.c b/gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_2g.c
index 38f547657d1..e0c90bdd914 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_2g.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ivopt_mult_2g.c
@@ -3,7 +3,7 @@
 
 /* Exit tests 'i < N1' and 'p2 > p_limit2' can be replaced, so
  * two ivs i and p2 can be eliminate.  */
-long int __GIMPLE (startwith("fix_loops"))
+long int __GIMPLE (ssa,startwith("fix_loops"))
 foo (long int * p, long int * p2, int N1, int N2)
 {
   long int s;
@@ -13,66 +13,67 @@ foo (long int * p, long int * p2, int N1, int N2)
   long unsigned int _2;
   long int _3;
 
-  bb_2:
+  __BB(2):
   _1 = (long unsigned int) N2_9(D);
   _2 = _1 * 8ul;
   p_limit2_11 = p2_10(D) + _2;
   if (N1_13(D) > 0)
-    goto bb_3;
+    goto __BB3;
   else
-    goto bb_13;
+    goto __BB13;
 
-  bb_13:
+  __BB(13):
+  goto __BB9;
 
-  bb_9:
-  goto bb_6;
+  __BB(9):
+  goto __BB6;
 
-  bb_3:
+  __BB(3):
   p_22 = p_12(D) + 8ul;
   p2_23 = p2_10(D) + 8ul;
   if (p_limit2_11 < p2_23)
-    goto bb_14;
+    goto __BB14;
   else
-    goto bb_7;
+    goto __BB7;
 
-  bb_14:
-  goto bb_9;
+  __BB(14):
+  goto __BB9;
 
-  bb_7:
-  goto bb_5;
+  __BB(7):
+  goto __BB5;
 
-  bb_4:
+  __BB(4):
   p_14 = p_27 + 8ul;
   p2_15 = p2_28 + 8ul;
   i_16 = i_29 + 1;
   if (p_limit2_11 < p2_15)
-    goto bb_11;
+    goto __BB11;
   else
-    goto bb_8;
+    goto __BB8;
 
-  bb_11:
-  goto bb_6;
+  __BB(11):
+  goto __BB6;
 
-  bb_8:
-  ;
+  __BB(8):
+  goto __BB8;
 
-  bb_5:
-  s_25 = __PHI (bb_7: 0l, bb_8: s_18);
-  p_27 = __PHI (bb_7: p_22, bb_8: p_14);
-  p2_28 = __PHI (bb_7: p2_23, bb_8: p2_15);
-  i_29 = __PHI (bb_7: 1, bb_8: i_16);
+  __BB(5):
+  s_25 = __PHI (__BB7: 0l, __BB8: s_18);
+  p_27 = __PHI (__BB7: p_22, __BB8: p_14);
+  p2_28 = __PHI (__BB7: p2_23, __BB8: p2_15);
+  i_29 = __PHI (__BB7: 1, __BB8: i_16);
   _3 = __MEM <long int> (p_27);
   s_18 = _3 + s_25;
   if (N1_13(D) > i_29)
-    goto bb_4;
+    goto __BB4;
   else
-    goto bb_12;
+    goto __BB12;
 
-  bb_12:
-  ;
+  __BB(12):
+  goto __BB6;
 
-  bb_6:
-  s_26 = __PHI (bb_12: s_18, bb_11: s_18, bb_9: 0l);
+  __BB(6):
+  s_26 = __PHI (__BB12: s_18, __BB11: s_18, __BB9: 0l);
   return s_26;
 }
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scev-3.c b/gcc/testsuite/gcc.dg/tree-ssa/scev-3.c
index fed1011968d..4babd33f5c0 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/scev-3.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/scev-3.c
@@ -4,39 +4,39 @@
 int *a_p;
 int a[1000];
 
-void __GIMPLE (startwith ("loop"))
+void __GIMPLE (ssa,startwith ("loop"))
 f (int k)
 {
   int i;
   int * _1;
 
-bb_2:
+__BB(2):
   i_5 = k_4(D);
   if (i_5 <= 999)
-    goto bb_4;
+    goto __BB4;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_3:
+__BB(3):
   return;
 
-bb_4:
-  ;
+__BB(4):
+  goto __BB5;
 
-bb_5:
-  i_12 = __PHI (bb_6: i_9, bb_4: i_5);
+__BB(5):
+  i_12 = __PHI (__BB6: i_9, __BB4: i_5);
   _1 = &a[i_12];
   a_p = _1;
   __MEM <int[1000]> ((int *)&a)[i_12] = 100;
   i_9 = i_5 + i_12;
   if (i_9 <= 999)
-    goto bb_6;
+    goto __BB6;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_6:
+__BB(6):
   ;
-  goto bb_5;
+  goto __BB5;
 
 }
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scev-4.c b/gcc/testsuite/gcc.dg/tree-ssa/scev-4.c
index 94ebfae7b93..57cb0213402 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/scev-4.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/scev-4.c
@@ -9,39 +9,39 @@ typedef struct {
 int *a_p;
 S a[1000];
 
-void __GIMPLE (startwith ("loop"))
+void __GIMPLE (ssa, startwith ("loop"))
 f (int k)
 {
   int i;
   int * _1;
 
-bb_2:
+__BB(2):
   i_5 = k_4(D);
   if (i_5 <= 999)
-    goto bb_4;
+    goto __BB4;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_3:
+__BB(3):
   return;
 
-bb_4:
-  ;
+__BB(4):
+  goto __BB5;
 
-bb_5:
-  i_12 = __PHI (bb_6: i_9, bb_4: i_5);
+__BB(5):
+  i_12 = __PHI (__BB6: i_9, __BB4: i_5);
   _1 = &a[i_12].y;
   a_p = _1;
   __MEM <S[1000]> ((int *)&a)[i_12].y = 100;
   i_9 = i_5 + i_12;
   if (i_9 <= 999)
-    goto bb_6;
+    goto __BB6;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_6:
+__BB(6):
   ;
-  goto bb_5;
+  goto __BB5;
 
 }
 
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scev-5.c b/gcc/testsuite/gcc.dg/tree-ssa/scev-5.c
index 8cced512e8d..c2feebdfc24 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/scev-5.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/scev-5.c
@@ -4,39 +4,39 @@
 int *a_p;
 int a[1000];
 
-void __GIMPLE (startwith ("loop"))
+void __GIMPLE (ssa,startwith ("loop"))
 f (int k)
 {
   long long int i;
   int * _1;
 
-bb_2:
+__BB(2):
   i_5 = (long long int) k_4(D);
   if (i_5 <= 999ll)
-    goto bb_4;
+    goto __BB4;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_3:
+__BB(3):
   return;
 
-bb_4:
-  ;
+__BB(4):
+  goto __BB5;
 
-bb_5:
-  i_12 = __PHI (bb_6: i_9, bb_4: i_5);
+__BB(5):
+  i_12 = __PHI (__BB6: i_9, __BB4: i_5);
   _1 = &a[i_12];
   a_p = _1;
   __MEM <int[1000]> ((int *)&a)[i_12] = 100;
   i_9 = i_5 + i_12;
   if (i_9 <= 999ll)
-    goto bb_6;
+    goto __BB6;
   else
-    goto bb_3;
+    goto __BB3;
 
-bb_6:
+__BB(6):
   ;
-  goto bb_5;
+  goto __BB5;
 
 }
 
diff --git a/gcc/testsuite/gcc.dg/vect/vect-cond-arith-2.c b/gcc/testsuite/gcc.dg/vect/vect-cond-arith-2.c
index 15ec005df26..38994ea82a5 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-cond-arith-2.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-cond-arith-2.c
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-additional-options "-fgimple -fdump-tree-optimized -ffast-math" } */
 
-double __GIMPLE (startwith("loop"))
+double __GIMPLE (ssa, startwith("loop"))
 neg_xi (double *x)
 {
   int i;
@@ -13,13 +13,13 @@ neg_xi (double *x)
   double res;
   unsigned int ivtmp;
 
- bb_1:
-  goto bb_2;
+ __BB(5):
+  goto __BB2;
 
- bb_2:
-  res_1 = __PHI (bb_1: 0.0, bb_3: res_2);
-  i_4 = __PHI (bb_1: 0, bb_3: i_5);
-  ivtmp_6 = __PHI (bb_1: 100U, bb_3: ivtmp_7);
+ __BB(2):
+  res_1 = __PHI (__BB5: 0.0, __BB3: res_2);
+  i_4 = __PHI (__BB5: 0, __BB3: i_5);
+  ivtmp_6 = __PHI (__BB5: 100U, __BB3: ivtmp_7);
   index = (long unsigned int) i_4;
   offset = index * 8UL;
   xi_ptr = x_8(D) + offset;
@@ -29,15 +29,15 @@ neg_xi (double *x)
   i_5 = i_4 + 1;
   ivtmp_7 = ivtmp_6 - 1U;
   if (ivtmp_7 != 0U)
-    goto bb_3;
+    goto __BB3;
   else
-    goto bb_4;
+    goto __BB4;
 
- bb_3:
-  goto bb_2;
+ __BB(3):
+  goto __BB2;
 
- bb_4:
-  res_3 = __PHI (bb_2: res_2);
+ __BB(4):
+  res_3 = __PHI (__BB2: res_2);
   return res_3;
 }
 
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/loop_add_6.c b/gcc/testsuite/gcc.target/aarch64/sve/loop_add_6.c
index aab5eddddb0..e7416ebcded 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/loop_add_6.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/loop_add_6.c
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -ftree-vectorize -fgimple -ffast-math" } */
 
-double __GIMPLE (startwith("loop"))
+double __GIMPLE (ssa, startwith("loop"))
 neg_xi (double *x)
 {
   int i;
@@ -13,13 +13,13 @@ neg_xi (double *x)
   double res;
   unsigned int ivtmp;
 
- bb_1:
-  goto bb_2;
+ __BB(5):
+  goto __BB2;
 
- bb_2:
-  res_1 = __PHI (bb_1: 0.0, bb_3: res_2);
-  i_4 = __PHI (bb_1: 0, bb_3: i_5);
-  ivtmp_6 = __PHI (bb_1: 100U, bb_3: ivtmp_7);
+ __BB(2):
+  res_1 = __PHI (__BB5: 0.0, __BB3: res_2);
+  i_4 = __PHI (__BB5: 0, __BB3: i_5);
+  ivtmp_6 = __PHI (__BB5: 100U, __BB3: ivtmp_7);
   index = (long unsigned int) i_4;
   offset = index * 8UL;
   xi_ptr = x_8(D) + offset;
@@ -29,15 +29,15 @@ neg_xi (double *x)
   i_5 = i_4 + 1;
   ivtmp_7 = ivtmp_6 - 1U;
   if (ivtmp_7 != 0U)
-    goto bb_3;
+    goto __BB3;
   else
-    goto bb_4;
+    goto __BB4;
 
- bb_3:
-  goto bb_2;
+ __BB(3):
+  goto __BB2;
 
- bb_4:
-  res_3 = __PHI (bb_2: res_2);
+ __BB(4):
+  res_3 = __PHI (__BB2: res_2);
   return res_3;
 }
 
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 805e8727ce0..0dc94ea41d4 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -171,7 +171,6 @@ static bool gimple_can_merge_blocks_p (basic_block, basic_block);
 static void remove_bb (basic_block);
 static edge find_taken_edge_computed_goto (basic_block, tree);
 static edge find_taken_edge_cond_expr (const gcond *, tree);
-static void lower_phi_internal_fn ();
 
 void
 init_empty_tree_cfg_for_function (struct function *fn)
@@ -246,7 +245,6 @@ 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;
@@ -359,47 +357,6 @@ 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_after_labels (bb); !gsi_end_p (gsi);)
-	{
-	  stmt = gsi_stmt (gsi);
-	  if (! gimple_call_internal_p (stmt, IFN_PHI))
-	    break;
-
-	  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 (cfun, 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,11 +3294,6 @@ 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
     {
@@ -7922,7 +7874,11 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags)
     {
       print_generic_expr (file, TREE_TYPE (TREE_TYPE (fndecl)),
 			  dump_flags | TDF_SLIM);
-      fprintf (file, " __GIMPLE ()\n%s (", function_name (fun));
+      fprintf (file, " __GIMPLE (%s)\n%s (",
+	       (fun->curr_properties & PROP_ssa) ? "ssa"
+	       : (fun->curr_properties & PROP_cfg) ? "cfg"
+	       : "",
+	       function_name (fun));
     }
   else
     fprintf (file, "%s %s(", function_name (fun), tmclone ? "[tm-clone] " : "");
diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c
index dad071df6ee..061521d20d5 100644
--- a/gcc/tree-into-ssa.c
+++ b/gcc/tree-into-ssa.c
@@ -1436,20 +1436,12 @@ rewrite_add_phi_arguments (basic_block bb)
       for (gsi = gsi_start_phis (e->dest); !gsi_end_p (gsi);
 	   gsi_next (&gsi))
 	{
-	  tree currdef, res, argvar;
+	  tree currdef, res;
 	  location_t loc;
 
 	  phi = gsi.phi ();
 	  res = gimple_phi_result (phi);
-	  /* 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);
+	  currdef = get_reaching_def (SSA_NAME_VAR (res));
 	  /* Virtual operand PHI args do not need a location.  */
 	  if (virtual_operand_p (res))
 	    loc = UNKNOWN_LOCATION;

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH][RFC] Teach GIMPLE FE to build proper CFG + SSA (+ loops)
  2019-03-14 10:54     ` Richard Biener
@ 2019-03-19 14:49       ` Jeff Law
  0 siblings, 0 replies; 5+ messages in thread
From: Jeff Law @ 2019-03-19 14:49 UTC (permalink / raw)
  To: Richard Biener, Bin.Cheng; +Cc: gcc-patches List

On 3/14/19 4:43 AM, Richard Biener wrote:
> On Wed, 13 Mar 2019, Richard Biener wrote:
> 
>> On Wed, 13 Mar 2019, Bin.Cheng wrote:
>>
>>> On Wed, Mar 13, 2019 at 3:58 AM Richard Biener <rguenther@suse.de> wrote:
>>>>
>>>>
>>>> This makes an attempt at fixing the most annoying parts of the GIMPLE
>>>> FE unit testing - the lack of proper CFG preservation and hoops you
>>>> need to jump through to make the CFG and SSA builders happy.
>>>>
>>>> Due to this the __GIMPLE specifiers takes two new flags, "cfg"
>>>> for GIMPLE-with-a-CFG and "ssa" for GIMPLE-with-a-CFG-and-SSA.
>>>> When there is a CFG you need to start basic-block boundaries with
>>>>
>>>> __BB(index):
>>>>
>>>> where 'index' is the basic-block index.  That implicitely defines
>>>> a label __BBindex for use in goto stmts and friends (but doesn't
>>>> actually add a GIMPLE_LABEL).
>>>>
>>>> The parsing code isn't defensive right now so you need to watch
>>>> out to not use index 0 or 1 (entry and exit block) which are
>>>> only implicitely present.
>>>>
>>>> As a proof of concept I added one BB annotation - loop_header(num)
>>>> where "num" is the loop number.  This means you can now also
>>>> have loop structures preserved (to some extent - the loop tree is
>>>> not explicitely represented nor are loop fathers, both are re-built
>>>> via fixup).
>>>>
>>>> I've not yet adjusted -gimple dumping.
>>>>
>>>> I've adjusted all testcases I could find.
>>>>
>>>> The CFG build inside the frontend is a bit awkward (spread out...),
>>>> likewise some functionality is asking for split-out.
>>>>
>>>> This is mainly a RFC for whether you think this is forward looking
>>>> enough.  Future enhancements would include EH and abnormal edges
>>>> via stmt annotations:
>>> Thanks very much for doing this.  Do we have a centralized
>>> wiki/document on the formal definition?  It would be very helpful even
>>> it's still evolving, otherwise we would need to dig into messages for
>>> fragmented clues.
>>
>> Earlier this week I transformed the old 
>> https://gcc.gnu.org/wiki/GimpleFrontEnd page into one documenting
>> the current state but this doesn't yet include any kind of documentation.
>>
>> I suppose special syntax documentation should go into our texinfo
>> docs, I guess into a new section in the internals manual.  Currently
>> we only have documentation for the -fgimple switch.
>>
>> Note that I view -gimple dumping as the thing that should give you
>> a clue about expected syntax.  I hope to spend a little more time
>> on the patch to make it ready for GCC9.
> 
> I've settled on another change, forcing explicit gotos for fallthru
> edges to the next block.
> 
> Otherwise I've cleaned up the patch and removed no longer necessary
> support for IFN_PHI from the middle-end.  During cleanup I introduced
> a gimple_parser class to hold the extra parsing state and I added
> some extra error handling.
> 
> Bootstrapped on x86_64-unknown-linux-gnu, testing is still in progress.
> 
> I will commit this to make testcase extraction to GIMPLE more feasible
> for GCC 9+ (we could even backport the GIMPLE FE changes to GCC 8 if 
> needed I guess).  At least it will give me motivation to do further
> required changes when I run into the next big LTO testcase running
> into a loop optimizer issue... (non-loop passes should work fine
> already).
If it makes building testcases easier, then I'm all for it ;-)

jeff

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2019-03-19 14:44 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-12 19:59 [PATCH][RFC] Teach GIMPLE FE to build proper CFG + SSA (+ loops) Richard Biener
2019-03-13  7:23 ` Bin.Cheng
2019-03-13  8:43   ` Richard Biener
2019-03-14 10:54     ` Richard Biener
2019-03-19 14:49       ` Jeff Law

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).