diff gcc/c/gimple-parser.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/c/gimple-parser.c	Fri Oct 27 22:46:09 2017 +0900
@@ -0,0 +1,1610 @@
+/* Parser for GIMPLE.
+   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "function.h"
+#include "c-tree.h"
+#include "timevar.h"
+#include "stringpool.h"
+#include "cgraph.h"
+#include "attribs.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "trans-mem.h"
+#include "c-family/c-pragma.h"
+#include "c-lang.h"
+#include "c-family/c-objc.h"
+#include "plugin.h"
+#include "builtins.h"
+#include "gomp-constants.h"
+#include "c-family/c-indentation.h"
+#include "gimple-expr.h"
+#include "context.h"
+#include "gcc-rich-location.h"
+#include "c-parser.h"
+#include "tree-vrp.h"
+#include "tree-pass.h"
+#include "tree-pretty-print.h"
+#include "tree.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "gimple-pretty-print.h"
+#include "tree-ssa.h"
+#include "pass_manager.h"
+#include "tree-ssanames.h"
+#include "gimple-ssa.h"
+#include "tree-dfa.h"
+
+
+/* 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 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> *);
+
+
+/* Parse the body of a function declaration marked with "__GIMPLE".  */
+
+void
+c_parser_parse_gimple_body (c_parser *parser)
+{
+  gimple_seq seq = NULL;
+  gimple_seq body = NULL;
+  tree stmt = push_stmt_list ();
+  push_scope ();
+  location_t loc1 = c_parser_peek_token (parser)->location;
+
+  init_tree_ssa (cfun);
+
+  if (! c_parser_gimple_compound_statement (parser, &seq))
+    {
+      gimple *ret = gimple_build_return (NULL);
+      gimple_seq_add_stmt (&seq, ret);
+    }
+
+  tree block = pop_scope ();
+  stmt = pop_stmt_list (stmt);
+  stmt = c_build_bind_expr (loc1, block, stmt);
+
+  block = DECL_INITIAL (current_function_decl);
+  BLOCK_SUBBLOCKS (block) = NULL_TREE;
+  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;
+
+  dump_function (TDI_gimple, current_function_decl);
+}
+
+/* Parse a compound statement in gimple function body.
+
+   gimple-statement:
+     gimple-statement
+     gimple-declaration-statement
+     gimple-if-statement
+     gimple-switch-statement
+     gimple-labeled-statement
+     gimple-expression-statement
+     gimple-goto-statement
+     gimple-phi-statement
+     gimple-return-statement
+*/
+
+static bool
+c_parser_gimple_compound_statement (c_parser *parser, gimple_seq *seq)
+{
+  bool return_p = false;
+
+  if (! c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+    return false;
+
+  /* A compund statement starts with optional declarations.  */
+  while (c_parser_next_tokens_start_declaration (parser))
+    {
+      c_parser_gimple_declaration (parser);
+      if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+	return false;
+    }
+
+  while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
+    {
+      if (c_parser_error (parser))
+	{
+	  c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
+	  return return_p;
+	}
+      else if (c_parser_next_token_is (parser, CPP_EOF))
+	{
+	  c_parser_error (parser, "expected declaration or statement");
+	  return return_p;
+	}
+
+      switch (c_parser_peek_token (parser)->type)
+	{
+	case CPP_KEYWORD:
+	  switch (c_parser_peek_token (parser)->keyword)
+	    {
+	    case RID_IF:
+	      c_parser_gimple_if_stmt (parser, seq);
+	      break;
+	    case RID_SWITCH:
+	      c_parser_gimple_switch_stmt (parser, seq);
+	      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,
+					       seq);
+		    c_parser_consume_token (parser);
+		    if (! c_parser_require (parser, CPP_SEMICOLON,
+					    "expected %<;%>"))
+		      return return_p;
+		  }
+		}
+	      break;
+	    case RID_RETURN:
+	      return_p = true;
+	      c_parser_gimple_return_stmt (parser, seq);
+	      if (! c_parser_require (parser, CPP_SEMICOLON,
+				      "expected %<;%>"))
+		return return_p;
+	      break;
+	    default:
+	      goto expr_stmt;
+	    }
+	  break;
+	case CPP_NAME:
+	  if (c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+	    {
+	      c_parser_gimple_label (parser, seq);
+	      break;
+	    }
+	  goto expr_stmt;
+
+	case CPP_SEMICOLON:
+	  {
+	    /* Empty stmt.  */
+	    location_t loc = c_parser_peek_token (parser)->location;
+	    c_parser_consume_token (parser);
+	    gimple *nop = gimple_build_nop ();
+	    gimple_set_location (nop, loc);
+	    gimple_seq_add_stmt (seq, nop);
+	    break;
+	  }
+
+	default:
+expr_stmt:
+	  c_parser_gimple_statement (parser, seq);
+	  if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+	    c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+	}
+    }
+  c_parser_consume_token (parser);
+  return return_p;
+}
+
+/* Parse a gimple statement.
+
+   gimple-statement:
+     gimple-call-expression
+     gimple-assign-statement
+     gimple-phi-statement
+
+   gimple-assign-statement:
+     gimple-unary-expression = gimple-assign-rhs
+ 
+   gimple-assign-rhs:
+     gimple-cast-expression
+     gimple-unary-expression
+     gimple-binary-expression
+     gimple-call-expression
+
+   gimple-phi-statement:
+     identifier = __PHI ( label : gimple_primary-expression, ... )
+
+   gimple-call-expr:
+     gimple-primary-expression ( argument-list )
+
+   gimple-cast-expression:
+     ( type-name ) gimple-primary-expression
+
+*/
+
+static void
+c_parser_gimple_statement (c_parser *parser, gimple_seq *seq)
+{
+  struct c_expr lhs, rhs;
+  gimple *assign = NULL;
+  location_t loc;
+  tree arg = NULL_TREE;
+  auto_vec<tree> vargs;
+
+  lhs = c_parser_gimple_unary_expression (parser);
+  loc = EXPR_LOCATION (lhs.value);
+  rhs.set_error ();
+
+  /* GIMPLE call statement without LHS.  */
+  if (c_parser_next_token_is (parser, CPP_SEMICOLON)
+      && TREE_CODE (lhs.value) == CALL_EXPR)
+    {
+      gimple *call;
+      call = gimple_build_call_from_tree (lhs.value, NULL);
+      gimple_seq_add_stmt (seq, call);
+      gimple_set_location (call, loc);
+      return;
+    }
+
+  /* All following cases are statements with LHS.  */
+  if (! c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+    return;
+
+  /* Cast expression.  */
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+      && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+    {
+      c_parser_consume_token (parser);
+      struct c_type_name *type_name = c_parser_type_name (parser);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+      if (type_name == NULL)
+	return;
+      /* ???  The actual type used in the cast expression is ignored as
+         in GIMPLE it is encoded by the type of the LHS.  */
+      rhs = c_parser_gimple_postfix_expression (parser);
+      if (lhs.value != error_mark_node
+	  && rhs.value != error_mark_node)
+	{
+	  enum tree_code code = NOP_EXPR;
+	  if (VECTOR_TYPE_P (TREE_TYPE (lhs.value)))
+	    {
+	      code = VIEW_CONVERT_EXPR;
+	      rhs.value = build1 (VIEW_CONVERT_EXPR,
+				  TREE_TYPE (lhs.value), rhs.value);
+	    }
+	  else if (FLOAT_TYPE_P (TREE_TYPE (lhs.value))
+		   && ! FLOAT_TYPE_P (TREE_TYPE (rhs.value)))
+	    code = FLOAT_EXPR;
+	  else if (! FLOAT_TYPE_P (TREE_TYPE (lhs.value))
+		   && 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_set_location (assign, loc);
+	  return;
+	}
+    }
+
+  /* Unary expression.  */
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_NAME:
+      {
+	tree id = c_parser_peek_token (parser)->value;
+	if (strcmp (IDENTIFIER_POINTER (id), "__ABS") == 0)
+	  goto build_unary_expr;
+	break;
+      }
+    case CPP_KEYWORD:
+      if (c_parser_peek_token (parser)->keyword != RID_REALPART
+	  && c_parser_peek_token (parser)->keyword != RID_IMAGPART)
+	break;
+      /* Fallthru.  */
+    case CPP_AND:
+    case CPP_PLUS:
+    case CPP_MINUS:
+    case CPP_COMPL:
+    case CPP_NOT:
+    case CPP_MULT: /* pointer deref */
+    build_unary_expr:
+      rhs = c_parser_gimple_unary_expression (parser);
+      if (rhs.value != error_mark_node)
+	{
+	  assign = gimple_build_assign (lhs.value, rhs.value);
+	  gimple_set_location (assign, loc);
+	  gimple_seq_add_stmt (seq, assign);
+	}
+      return;
+
+    default:;
+    }
+
+  /* GIMPLE PHI statement.  */
+  if (c_parser_next_token_is_keyword (parser, RID_PHI))
+    {
+      c_parser_consume_token (parser);
+
+      if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+	return;
+
+      if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+	c_parser_consume_token (parser);
+
+      while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
+	{
+	  if (c_parser_next_token_is (parser, CPP_NAME)
+	      && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+	    {
+	      arg = lookup_label_for_goto (loc,
+					   c_parser_peek_token (parser)->value);
+	      c_parser_consume_token (parser);
+
+	      if (c_parser_next_token_is (parser, CPP_COLON))
+		c_parser_consume_token (parser);
+	      vargs.safe_push (arg);
+	    }
+	  else if (c_parser_next_token_is (parser, CPP_COMMA))
+	    c_parser_consume_token (parser);
+	  else
+	    {
+	      arg = c_parser_gimple_unary_expression (parser).value;
+	      vargs.safe_push (arg);
+	    }
+	}
+
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+				 "expected %<)%>");
+
+      /* Build internal function for PHI.  */
+      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);
+      return;
+    }
+
+  /* GIMPLE call with lhs.  */
+  if (c_parser_next_token_is (parser, CPP_NAME)
+      && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN
+      && lookup_name (c_parser_peek_token (parser)->value))
+    {
+      rhs = c_parser_gimple_unary_expression (parser);
+      if (rhs.value != error_mark_node)
+	{
+	  gimple *call = gimple_build_call_from_tree (rhs.value, NULL);
+	  gimple_call_set_lhs (call, lhs.value);
+	  gimple_seq_add_stmt (seq, call);
+	  gimple_set_location (call, loc);
+	}
+      return;
+    }
+
+  rhs = c_parser_gimple_binary_expression (parser);
+  if (lhs.value != error_mark_node
+      && rhs.value != error_mark_node)
+    {
+      assign = gimple_build_assign (lhs.value, rhs.value);
+      gimple_seq_add_stmt (seq, assign);
+      gimple_set_location (assign, loc);
+    }
+  return;
+}
+
+/* Parse gimple binary expr.
+
+   gimple-binary-expression:
+     gimple-unary-expression * gimple-unary-expression
+     gimple-unary-expression / gimple-unary-expression
+     gimple-unary-expression % gimple-unary-expression
+     gimple-unary-expression + gimple-unary-expression
+     gimple-unary-expression - gimple-unary-expression
+     gimple-unary-expression << gimple-unary-expression
+     gimple-unary-expression >> gimple-unary-expression
+     gimple-unary-expression < gimple-unary-expression
+     gimple-unary-expression > gimple-unary-expression
+     gimple-unary-expression <= gimple-unary-expression
+     gimple-unary-expression >= gimple-unary-expression
+     gimple-unary-expression == gimple-unary-expression
+     gimple-unary-expression != gimple-unary-expression
+     gimple-unary-expression & gimple-unary-expression
+     gimple-unary-expression ^ gimple-unary-expression
+     gimple-unary-expression | gimple-unary-expression
+
+*/
+
+static c_expr
+c_parser_gimple_binary_expression (c_parser *parser)
+{
+  /* Location of the binary operator.  */
+  struct c_expr ret, lhs, rhs;
+  enum tree_code code = ERROR_MARK;
+  ret.set_error ();
+  lhs = c_parser_gimple_postfix_expression (parser);
+  if (c_parser_error (parser))
+    return ret;
+  tree ret_type = TREE_TYPE (lhs.value);
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_MULT:
+      code = MULT_EXPR;
+      break;
+    case CPP_DIV:
+      code = TRUNC_DIV_EXPR;
+      break;
+    case CPP_MOD:
+      code = TRUNC_MOD_EXPR;
+      break;
+    case CPP_PLUS:
+      if (POINTER_TYPE_P (TREE_TYPE (lhs.value)))
+	code = POINTER_PLUS_EXPR;
+      else
+	code = PLUS_EXPR;
+      break;
+    case CPP_MINUS:
+      code = MINUS_EXPR;
+      break;
+    case CPP_LSHIFT:
+      code = LSHIFT_EXPR;
+      break;
+    case CPP_RSHIFT:
+      code = RSHIFT_EXPR;
+      break;
+    case CPP_LESS:
+      code = LT_EXPR;
+      ret_type = boolean_type_node;
+      break;
+    case CPP_GREATER:
+      code = GT_EXPR;
+      ret_type = boolean_type_node;
+      break;
+    case CPP_LESS_EQ:
+      code = LE_EXPR;
+      ret_type = boolean_type_node;
+      break;
+    case CPP_GREATER_EQ:
+      code = GE_EXPR;
+      ret_type = boolean_type_node;
+      break;
+    case CPP_EQ_EQ:
+      code = EQ_EXPR;
+      ret_type = boolean_type_node;
+      break;
+    case CPP_NOT_EQ:
+      code = NE_EXPR;
+      ret_type = boolean_type_node;
+      break;
+    case CPP_AND:
+      code = BIT_AND_EXPR;
+      break;
+    case CPP_XOR:
+      code = BIT_XOR_EXPR;
+      break;
+    case CPP_OR:
+      code = BIT_IOR_EXPR;
+      break;
+    case CPP_AND_AND:
+      c_parser_error (parser, "%<&&%> not valid in GIMPLE");
+      return ret;
+    case CPP_OR_OR:
+      c_parser_error (parser, "%<||%> not valid in GIMPLE");
+      return ret;
+    default:
+      /* Not a binary expression.  */
+      return lhs;
+    }
+  location_t ret_loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_token (parser);
+  rhs = c_parser_gimple_postfix_expression (parser);
+  if (lhs.value != error_mark_node && rhs.value != error_mark_node)
+    ret.value = build2_loc (ret_loc, code, ret_type, lhs.value, rhs.value);
+  return ret;
+}
+
+/* Parse gimple unary expression.
+
+   gimple-unary-expression:
+     gimple-postfix-expression
+     unary-operator gimple-postfix-expression
+
+   unary-operator: one of
+     & * + - ~ abs_expr
+*/
+
+static c_expr
+c_parser_gimple_unary_expression (c_parser *parser)
+{
+  struct c_expr ret, op;
+  location_t op_loc = c_parser_peek_token (parser)->location;
+  location_t finish;
+  ret.set_error ();
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_AND:
+      c_parser_consume_token (parser);
+      op = c_parser_gimple_postfix_expression (parser);
+      mark_exp_read (op.value);
+      return parser_build_unary_op (op_loc, ADDR_EXPR, op);
+    case CPP_MULT:
+      {
+	c_parser_consume_token (parser);
+	op = c_parser_gimple_postfix_expression (parser);
+	if (op.value == error_mark_node)
+	  return ret;
+	if (! POINTER_TYPE_P (TREE_TYPE (op.value)))
+	  {
+	    error_at (op_loc, "expected pointer as argument of unary %<*%>");
+	    return ret;
+	  }
+	finish = op.get_finish ();
+	location_t combined_loc = make_location (op_loc, op_loc, finish);
+	ret.value = build_simple_mem_ref_loc (combined_loc, op.value);
+	TREE_SIDE_EFFECTS (ret.value)
+	  = TREE_THIS_VOLATILE (ret.value)
+	  = TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (op.value)));
+	ret.src_range.m_start = op_loc;
+	ret.src_range.m_finish = finish;
+	return ret;
+      }
+    case CPP_PLUS:
+      c_parser_consume_token (parser);
+      op = c_parser_gimple_postfix_expression (parser);
+      return parser_build_unary_op (op_loc, CONVERT_EXPR, op);
+    case CPP_MINUS:
+      c_parser_consume_token (parser);
+      op = c_parser_gimple_postfix_expression (parser);
+      return parser_build_unary_op (op_loc, NEGATE_EXPR, op);
+    case CPP_COMPL:
+      c_parser_consume_token (parser);
+      op = c_parser_gimple_postfix_expression (parser);
+      return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op);
+    case CPP_NOT:
+      c_parser_error (parser, "%<!%> not valid in GIMPLE");
+      return ret;
+    case CPP_KEYWORD:
+      switch (c_parser_peek_token (parser)->keyword)
+	{
+	case RID_REALPART:
+	  c_parser_consume_token (parser);
+	  op = c_parser_gimple_postfix_expression (parser);
+	  return parser_build_unary_op (op_loc, REALPART_EXPR, op);
+	case RID_IMAGPART:
+	  c_parser_consume_token (parser);
+	  op = c_parser_gimple_postfix_expression (parser);
+	  return parser_build_unary_op (op_loc, IMAGPART_EXPR, op);
+	default:
+	  return c_parser_gimple_postfix_expression (parser);
+	}
+    case CPP_NAME:
+	{
+	  tree id = c_parser_peek_token (parser)->value;
+	  if (strcmp (IDENTIFIER_POINTER (id), "__ABS") == 0)
+	    {
+	      c_parser_consume_token (parser);
+	      op = c_parser_gimple_postfix_expression (parser);
+	      return parser_build_unary_op (op_loc, ABS_EXPR, op);
+	    }
+	  else
+	    return c_parser_gimple_postfix_expression (parser);
+	}
+    default:
+      return c_parser_gimple_postfix_expression (parser);
+    }
+}
+
+/* Decompose ID into base name (ID until ver_offset) and VERSION.  Return
+   true if ID matches a SSA name.  */
+
+static bool
+c_parser_parse_ssa_name_id (tree id, unsigned *version, unsigned *ver_offset)
+{
+  const char *token = IDENTIFIER_POINTER (id);
+  const char *var_version = strrchr (token, '_');
+  if (! var_version)
+    return false;
+
+  *ver_offset = var_version - token;
+  for (const char *p = var_version + 1; *p; ++p)
+    if (! ISDIGIT (*p))
+      return false;
+  *version = atoi (var_version + 1);
+  return *version > 0;
+}
+
+/* Get at the actual SSA name ID with VERSION starting at VER_OFFSET.
+   TYPE is the type if the SSA name is being declared.  */
+
+static tree 
+c_parser_parse_ssa_name (c_parser *parser,
+			 tree id, tree type, unsigned version,
+			 unsigned ver_offset)
+{
+  tree name = NULL_TREE;
+  const char *token = IDENTIFIER_POINTER (id);
+
+  if (ver_offset == 0)
+    {
+      /* Anonymous unnamed SSA name.  */
+      if (version < num_ssa_names)
+	name = ssa_name (version);
+      if (! name)
+	{
+	  if (! type)
+	    {
+	      c_parser_error (parser, "SSA name undeclared"); 
+	      return error_mark_node;
+	    }
+	  name = make_ssa_name_fn (cfun, type, NULL, version);
+	}
+    }
+  else
+    {
+      if (version < num_ssa_names)
+	name = ssa_name (version);
+      if (! name)
+	{
+	  /* Separate var name from version.  */
+	  char *var_name = XNEWVEC (char, ver_offset + 1);
+	  memcpy (var_name, token, ver_offset);
+	  var_name[ver_offset] = '\0';
+	  /* lookup for parent decl.  */
+	  id = get_identifier (var_name);
+	  tree parent = lookup_name (id);
+	  XDELETEVEC (var_name);
+	  if (! parent || parent == error_mark_node)
+	    {
+	      c_parser_error (parser, "base variable or SSA name undeclared"); 
+	      return error_mark_node;
+	    }
+	  if (!(VAR_P (parent)
+		|| TREE_CODE (parent) == PARM_DECL
+		|| TREE_CODE (parent) == RESULT_DECL))
+	    {
+	      error ("invalid base %qE for SSA name", parent);
+	      return error_mark_node;
+	    }
+	  if (VECTOR_TYPE_P (TREE_TYPE (parent))
+	      || TREE_CODE (TREE_TYPE (parent)) == COMPLEX_TYPE)
+	    DECL_GIMPLE_REG_P (parent) = 1;
+	  name = make_ssa_name_fn (cfun, parent,
+				   gimple_build_nop (), version);
+	}
+    }
+
+  return name;
+}
+
+/* Parse gimple postfix expression.
+
+   gimple-postfix-expression:
+     gimple-primary-expression
+     gimple-primary-xpression [ gimple-primary-expression ]
+     gimple-primary-expression ( gimple-argument-expression-list[opt] )
+     postfix-expression . identifier
+     postfix-expression -> identifier
+
+   gimple-argument-expression-list:
+     gimple-unary-expression
+     gimple-argument-expression-list , gimple-unary-expression
+
+   gimple-primary-expression:
+     identifier
+     constant
+     string-literal
+
+*/
+
+static struct c_expr
+c_parser_gimple_postfix_expression (c_parser *parser)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  source_range tok_range = c_parser_peek_token (parser)->get_range ();
+  struct c_expr expr;
+  expr.set_error ();
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_NUMBER:
+      expr.value = c_parser_peek_token (parser)->value;
+      set_c_expr_source_range (&expr, tok_range);
+      loc = c_parser_peek_token (parser)->location;
+      c_parser_consume_token (parser);
+      break;
+    case CPP_CHAR:
+    case CPP_CHAR16:
+    case CPP_CHAR32:
+    case CPP_WCHAR:
+      expr.value = c_parser_peek_token (parser)->value;
+      set_c_expr_source_range (&expr, tok_range);
+      c_parser_consume_token (parser);
+      break;
+    case CPP_STRING:
+    case CPP_STRING16:
+    case CPP_STRING32:
+    case CPP_WSTRING:
+    case CPP_UTF8STRING:
+      expr.value = c_parser_peek_token (parser)->value;
+      set_c_expr_source_range (&expr, tok_range);
+      expr.original_code = STRING_CST;
+      c_parser_consume_token (parser);
+      break;
+    case CPP_NAME:
+      if (c_parser_peek_token (parser)->id_kind == C_ID_ID)
+	{
+	  tree id = c_parser_peek_token (parser)->value;
+	  if (strcmp (IDENTIFIER_POINTER (id), "__MEM") == 0)
+	    {
+	      /* __MEM '<' type-name [ ',' number ] '>'
+	               '(' [ '(' type-name ')' ] unary-expression
+		           [ '+' number ] ')'  */
+	      location_t loc = c_parser_peek_token (parser)->location;
+	      c_parser_consume_token (parser);
+	      struct c_type_name *type_name = NULL;
+	      tree alignment = NULL_TREE;
+	      if (c_parser_require (parser, CPP_LESS, "expected %<<%>"))
+	        {
+		  type_name = c_parser_type_name (parser);
+		  /* Optional alignment.  */
+		  if (c_parser_next_token_is (parser, CPP_COMMA))
+		    {
+		      c_parser_consume_token (parser);
+		      alignment
+			= c_parser_gimple_postfix_expression (parser).value;
+		    }
+		  c_parser_skip_until_found (parser,
+					     CPP_GREATER, "expected %<>%>");
+		}
+	      struct c_expr ptr;
+	      ptr.value = error_mark_node;
+	      tree alias_off = NULL_TREE;
+	      if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+		{
+		  tree alias_type = NULL_TREE;
+		  /* Optional alias-type cast.  */
+		  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+		    {
+		      c_parser_consume_token (parser);
+		      struct c_type_name *alias_type_name
+			= c_parser_type_name (parser);
+		      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+						 "expected %<)%>");
+		      if (alias_type_name)
+			{
+			  tree tem;
+			  alias_type = groktypename (alias_type_name,
+						     &tem, NULL);
+			}
+		    }
+		  ptr = c_parser_gimple_unary_expression (parser);
+		  if (ptr.value == error_mark_node
+		      || ! POINTER_TYPE_P (TREE_TYPE (ptr.value)))
+		    {
+		      if (ptr.value != error_mark_node)
+			error_at (ptr.get_start (),
+				  "invalid type of %<__MEM%> operand");
+		      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+						 "expected %<)%>");
+		      return expr;
+		    }
+		  if (! alias_type)
+		    alias_type = TREE_TYPE (ptr.value);
+		  /* Optional constant offset.  */
+		  if (c_parser_next_token_is (parser, CPP_PLUS))
+		    {
+		      c_parser_consume_token (parser);
+		      alias_off
+			= c_parser_gimple_postfix_expression (parser).value;
+		      alias_off = fold_convert (alias_type, alias_off);
+		    }
+		  if (! alias_off)
+		    alias_off = build_int_cst (alias_type, 0);
+		  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+					     "expected %<)%>");
+		}
+	      if (! type_name || c_parser_error (parser))
+		{
+		  c_parser_set_error (parser, false);
+		  return expr;
+		}
+	      tree tem = NULL_TREE;
+	      tree type = groktypename (type_name, &tem, NULL);
+	      if (alignment)
+		type = build_aligned_type (type, tree_to_uhwi (alignment));
+	      expr.value = build2_loc (loc, MEM_REF,
+				       type, ptr.value, alias_off);
+	      break;
+	    }
+	  else if (strcmp (IDENTIFIER_POINTER (id), "_Literal") == 0)
+	    {
+	      /* _Literal '(' type-name ')' [ '-' ] constant */
+	      c_parser_consume_token (parser);
+	      tree type = NULL_TREE;
+	      if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+		{
+		  struct c_type_name *type_name = c_parser_type_name (parser);
+		  tree tem;
+		  if (type_name)
+		    type = groktypename (type_name, &tem, NULL);
+		  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+					     "expected %<)%>");
+		}
+	      bool neg_p;
+	      if ((neg_p = c_parser_next_token_is (parser, CPP_MINUS)))
+		c_parser_consume_token (parser);
+	      tree val = c_parser_gimple_postfix_expression (parser).value;
+	      if (! type
+		  || ! val
+		  || val == error_mark_node
+		  || ! CONSTANT_CLASS_P (val))
+		{
+		  c_parser_error (parser, "invalid _Literal");
+		  return expr;
+		}
+	      if (neg_p)
+		{
+		  val = const_unop (NEGATE_EXPR, TREE_TYPE (val), val);
+		  if (! val)
+		    {
+		      c_parser_error (parser, "invalid _Literal");
+		      return expr;
+		    }
+		}
+	      expr.value = fold_convert (type, val);
+	      return expr;
+	    }
+	  else if (strcmp (IDENTIFIER_POINTER (id), "__FMA") == 0)
+	    {
+	      c_parser_consume_token (parser);
+	      auto_vec<tree> args;
+
+	      if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+		{
+		  c_parser_gimple_expr_list (parser, &args);
+		  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+					     "expected %<)%>");
+		}
+	      if (args.length () != 3)
+		{
+		  error_at (loc, "invalid number of operands to __FMA");
+		  expr.value = error_mark_node;
+		  return expr;
+		}
+	      expr.value = build3_loc (loc, FMA_EXPR, TREE_TYPE (args[0]),
+				       args[0], args[1], args[2]);
+	      return expr;
+	    }
+
+	  /* SSA name.  */
+	  unsigned version, ver_offset;
+	  if (! lookup_name (id)
+	      && c_parser_parse_ssa_name_id (id, &version, &ver_offset))
+	    {
+	      c_parser_consume_token (parser);
+	      expr.value = c_parser_parse_ssa_name (parser, id, NULL_TREE,
+						    version, ver_offset);
+	      if (expr.value == error_mark_node)
+		return expr;
+	      set_c_expr_source_range (&expr, tok_range);
+	      /* For default definition SSA names.  */
+	      if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+		  && c_parser_peek_2nd_token (parser)->type == CPP_NAME
+		  && strcmp ("D",
+			     IDENTIFIER_POINTER
+			       (c_parser_peek_2nd_token (parser)->value)) == 0
+		  && c_parser_peek_nth_token (parser, 3)->type == CPP_CLOSE_PAREN)
+		{
+		  c_parser_consume_token (parser);
+		  c_parser_consume_token (parser);
+		  c_parser_consume_token (parser);
+		  if (! SSA_NAME_IS_DEFAULT_DEF (expr.value))
+		    {
+		      if (!SSA_NAME_VAR (expr.value))
+			{
+			  error_at (loc, "anonymous SSA name cannot have"
+				    " default definition");
+			  expr.value = error_mark_node;
+			  return expr;
+			}
+		      set_ssa_default_def (cfun, SSA_NAME_VAR (expr.value),
+					   expr.value);
+		      SSA_NAME_DEF_STMT (expr.value) = gimple_build_nop ();
+		    }
+		}
+	    }
+	  else
+	    {
+	      c_parser_consume_token (parser);
+	      expr.value
+		= build_external_ref (loc, id,
+				      (c_parser_peek_token (parser)->type
+				       == CPP_OPEN_PAREN), &expr.original_type);
+	      set_c_expr_source_range (&expr, tok_range);
+	    }
+	  break;
+	}
+      else
+	{
+	  c_parser_error (parser, "expected expression");
+	  expr.set_error ();
+	  break;
+	}
+      break;
+    default:
+      c_parser_error (parser, "expected expression");
+      expr.set_error ();
+      break;
+    }
+  return c_parser_gimple_postfix_expression_after_primary
+    (parser, EXPR_LOC_OR_LOC (expr.value, loc), expr);
+}
+
+/* Parse a gimple postfix expression after the initial primary or compound
+   literal.  */
+
+static struct c_expr
+c_parser_gimple_postfix_expression_after_primary (c_parser *parser,
+						  location_t expr_loc,
+						  struct c_expr expr)
+{
+  location_t start;
+  location_t finish;
+  tree ident;
+  location_t comp_loc;
+
+  while (true)
+    {
+      location_t op_loc = c_parser_peek_token (parser)->location;
+      switch (c_parser_peek_token (parser)->type)
+	{
+	case CPP_OPEN_SQUARE:
+	  {
+	    c_parser_consume_token (parser);
+	    tree idx = c_parser_gimple_unary_expression (parser).value;
+
+	    if (! c_parser_require (parser, CPP_CLOSE_SQUARE, "expected %<]%>"))
+	      {
+		c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL);
+		break;
+	      }
+
+	    start = expr.get_start ();
+	    finish = c_parser_tokens_buf (parser, 0)->location;
+	    expr.value = build_array_ref (op_loc, expr.value, idx);
+	    set_c_expr_source_range (&expr, start, finish);
+
+	    expr.original_code = ERROR_MARK;
+	    expr.original_type = NULL;
+	    break;
+	  }
+	case CPP_OPEN_PAREN:
+	  {
+	    /* Function call.  */
+	    c_parser_consume_token (parser);
+	    auto_vec<tree> exprlist;
+	    if (! c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+	      c_parser_gimple_expr_list (parser, &exprlist);
+	    c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+				       "expected %<)%>");
+	    expr.value = build_call_array_loc
+		(expr_loc, TREE_TYPE (TREE_TYPE (expr.value)),
+		 expr.value, exprlist.length (), exprlist.address ());
+	    expr.original_code = ERROR_MARK;
+	    expr.original_type = NULL;
+	    break;
+	  }
+	case CPP_DOT:
+	  {
+	    /* Structure element reference.  */
+	    c_parser_consume_token (parser);
+	    if (c_parser_next_token_is (parser, CPP_NAME))
+	      {
+		c_token *comp_tok = c_parser_peek_token (parser);
+		ident = comp_tok->value;
+		comp_loc = comp_tok->location;
+	      }
+	    else
+	      {
+		c_parser_error (parser, "expected identifier");
+		expr.set_error ();
+		expr.original_code = ERROR_MARK;
+		expr.original_type = NULL;
+		return expr;
+	      }
+	    start = expr.get_start ();
+	    finish = c_parser_peek_token (parser)->get_finish ();
+	    c_parser_consume_token (parser);
+	    expr.value = build_component_ref (op_loc, expr.value, ident,
+					      comp_loc);
+	    set_c_expr_source_range (&expr, start, finish);
+	    expr.original_code = ERROR_MARK;
+	    if (TREE_CODE (expr.value) != COMPONENT_REF)
+	      expr.original_type = NULL;
+	    else
+	      {
+		/* Remember the original type of a bitfield.  */
+		tree field = TREE_OPERAND (expr.value, 1);
+		if (TREE_CODE (field) != FIELD_DECL)
+		  expr.original_type = NULL;
+		else
+		  expr.original_type = DECL_BIT_FIELD_TYPE (field);
+	      }
+	    break;
+	  }
+	case CPP_DEREF:
+	  {
+	    /* Structure element reference.  */
+	    c_parser_consume_token (parser);
+	    if (c_parser_next_token_is (parser, CPP_NAME))
+	      {
+		c_token *comp_tok = c_parser_peek_token (parser);
+		ident = comp_tok->value;
+		comp_loc = comp_tok->location;
+	      }
+	    else
+	      {
+		c_parser_error (parser, "expected identifier");
+		expr.set_error ();
+		expr.original_code = ERROR_MARK;
+		expr.original_type = NULL;
+		return expr;
+	      }
+	    start = expr.get_start ();
+	    finish = c_parser_peek_token (parser)->get_finish ();
+	    c_parser_consume_token (parser);
+	    expr.value = build_component_ref (op_loc,
+					      build_simple_mem_ref_loc
+					        (op_loc, expr.value),
+					      ident, comp_loc);
+	    set_c_expr_source_range (&expr, start, finish);
+	    expr.original_code = ERROR_MARK;
+	    if (TREE_CODE (expr.value) != COMPONENT_REF)
+	      expr.original_type = NULL;
+	    else
+	      {
+		/* Remember the original type of a bitfield.  */
+		tree field = TREE_OPERAND (expr.value, 1);
+		if (TREE_CODE (field) != FIELD_DECL)
+		  expr.original_type = NULL;
+		else
+		  expr.original_type = DECL_BIT_FIELD_TYPE (field);
+	      }
+	    break;
+	  }
+	default:
+	  return expr;
+	}
+    }
+}
+
+/* Parse expression list.
+
+   gimple-expr-list:
+     gimple-unary-expression
+     gimple-expr-list , gimple-unary-expression
+
+ */
+
+static void
+c_parser_gimple_expr_list (c_parser *parser, vec<tree> *ret)
+{
+  struct c_expr expr;
+
+  expr = c_parser_gimple_unary_expression (parser);
+  ret->safe_push (expr.value);
+  while (c_parser_next_token_is (parser, CPP_COMMA))
+    {
+      c_parser_consume_token (parser);
+      expr = c_parser_gimple_unary_expression (parser);
+      ret->safe_push (expr.value);
+    }
+}
+
+/* Parse gimple label.
+
+   gimple-label:
+     identifier :
+     case constant-expression :
+     default :
+
+*/
+
+static void
+c_parser_gimple_label (c_parser *parser, gimple_seq *seq)
+{
+  tree name = c_parser_peek_token (parser)->value;
+  location_t loc1 = c_parser_peek_token (parser)->location;
+  gcc_assert (c_parser_next_token_is (parser, CPP_NAME));
+  c_parser_consume_token (parser);
+  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));
+  return;
+}
+
+/* Parse gimple/RTL pass list.
+
+   gimple-or-rtl-pass-list:
+     startwith("pass-name")
+ */
+
+char *
+c_parser_gimple_or_rtl_pass_list (c_parser *parser)
+{
+  char *pass = NULL;
+
+  /* Accept __GIMPLE/__RTL.  */
+  if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
+    return NULL;
+  c_parser_consume_token (parser);
+
+  if (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;
+	  if (c_parser_next_token_is_not (parser, CPP_STRING))
+	    {
+	      error_at (c_parser_peek_token (parser)->location,
+			"expected pass name");
+	      return NULL;
+	    }
+	  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;
+	}
+      else
+	{
+	  error_at (c_parser_peek_token (parser)->location,
+		    "invalid operation");
+	  return NULL;
+	}
+    }
+
+  if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+    return NULL;
+
+  return pass;
+}
+
+/* Parse gimple local declaration.
+
+   declaration-specifiers:
+     storage-class-specifier declaration-specifiers[opt]
+     type-specifier declaration-specifiers[opt]
+     type-qualifier declaration-specifiers[opt]
+     function-specifier declaration-specifiers[opt]
+     alignment-specifier declaration-specifiers[opt]
+
+   storage-class-specifier:
+     typedef
+     extern
+     static
+     auto
+     register
+
+   type-specifier:
+     void
+     char
+     short
+     int
+     long
+     float
+     double
+     signed
+     unsigned
+     _Bool
+     _Complex
+
+   type-qualifier:
+     const
+     restrict
+     volatile
+     address-space-qualifier
+     _Atomic
+
+ */
+
+static void
+c_parser_gimple_declaration (c_parser *parser)
+{
+  struct c_declarator *declarator;
+  struct c_declspecs *specs = build_null_declspecs ();
+  c_parser_declspecs (parser, specs, true, true, true,
+		      true, true, cla_nonabstract_decl);
+  finish_declspecs (specs);
+
+  /* Provide better error recovery.  Note that a type name here is usually
+     better diagnosed as a redeclaration.  */
+  if (c_parser_next_token_starts_declspecs (parser)
+      && ! c_parser_next_token_is (parser, CPP_NAME))
+    {
+      c_parser_error (parser, "expected %<;%>");
+      c_parser_set_error (parser, false);
+      return;
+    }
+
+  bool dummy = false;
+  declarator = c_parser_declarator (parser,
+				    specs->typespec_kind != ctsk_none,
+				    C_DTR_NORMAL, &dummy);
+
+  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+    {
+      /* Handle SSA name decls specially, they do not go into the identifier
+         table but we simply build the SSA name for later lookup.  */
+      unsigned version, ver_offset;
+      if (declarator->kind == cdk_id
+	  && is_gimple_reg_type (specs->type)
+	  && c_parser_parse_ssa_name_id (declarator->u.id,
+					 &version, &ver_offset)
+	  /* The following restricts it to unnamed anonymous SSA names
+	     which fails parsing of named ones in dumps (we could
+	     decide to not dump their name for -gimple).  */
+	  && ver_offset == 0)
+	c_parser_parse_ssa_name (parser, declarator->u.id, specs->type,
+				 version, ver_offset);
+      else
+	{
+	  tree postfix_attrs = NULL_TREE;
+	  tree all_prefix_attrs = specs->attrs;
+	  specs->attrs = NULL;
+	  tree decl = start_decl (declarator, specs, false,
+				  chainon (postfix_attrs, all_prefix_attrs));
+	  if (decl)
+	    finish_decl (decl, UNKNOWN_LOCATION, NULL_TREE, NULL_TREE,
+			 NULL_TREE);
+	}
+    }
+  else
+    {
+      c_parser_error (parser, "expected %<;%>");
+      return;
+    }
+}
+
+/* Parse gimple goto statement.  */
+
+static void
+c_parser_gimple_goto_stmt (location_t loc, tree label, gimple_seq *seq)
+{
+  tree decl = lookup_label_for_goto (loc, label);
+  gimple_seq_add_stmt (seq, gimple_build_goto (decl));
+  return;
+}
+
+/* Parse a parenthesized condition.
+   gimple-condition:
+     ( gimple-binary-expression )    */
+
+static tree
+c_parser_gimple_paren_condition (c_parser *parser)
+{
+  if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return error_mark_node;
+  tree cond = c_parser_gimple_binary_expression (parser).value;
+  if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+    return error_mark_node;
+  return cond;
+}
+
+/* Parse gimple if-else statement.
+
+   if-statement:
+     if ( gimple-binary-expression ) gimple-goto-statement
+     if ( gimple-binary-expression ) gimple-goto-statement \
+					else gimple-goto-statement
+ */
+
+static void
+c_parser_gimple_if_stmt (c_parser *parser, gimple_seq *seq)
+{
+  tree t_label, f_label, label;
+  location_t loc;
+  c_parser_consume_token (parser);
+  tree cond = c_parser_gimple_paren_condition (parser);
+
+  if (c_parser_next_token_is_keyword (parser, RID_GOTO))
+    {
+      loc = c_parser_peek_token (parser)->location;
+      c_parser_consume_token (parser);
+      if (! c_parser_next_token_is (parser, CPP_NAME))
+	{
+	  c_parser_error (parser, "expected label");
+	  return;
+	}
+      label = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+      t_label = lookup_label_for_goto (loc, label);
+      if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+	return;
+    }
+  else
+    {
+      c_parser_error (parser, "expected goto expression");
+      return;
+    }
+
+  if (c_parser_next_token_is_keyword (parser, RID_ELSE))
+    c_parser_consume_token (parser);
+  else
+    {
+      c_parser_error (parser, "expected else statement");
+      return;
+    }
+
+  if (c_parser_next_token_is_keyword (parser, RID_GOTO))
+    {
+      loc = c_parser_peek_token (parser)->location;
+      c_parser_consume_token (parser);
+      if (! c_parser_next_token_is (parser, CPP_NAME))
+	{
+	  c_parser_error (parser, "expected label");
+	  return;
+	}
+      label = c_parser_peek_token (parser)->value;
+      f_label = lookup_label_for_goto (loc, label);
+      c_parser_consume_token (parser);
+      if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+	return;
+    }
+  else
+    {
+      c_parser_error (parser, "expected goto expression");
+      return;
+    }
+
+  if (cond != error_mark_node)
+    gimple_seq_add_stmt (seq, gimple_build_cond_from_tree (cond, t_label,
+							   f_label));
+}
+
+/* Parse gimple switch-statement.
+
+   gimple-switch-statement:
+     switch (gimple-postfix-expression) gimple-case-statement
+
+   gimple-case-statement:
+     gimple-case-statement
+     gimple-label-statement : gimple-goto-statment
+*/
+
+static void
+c_parser_gimple_switch_stmt (c_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 %<(%>"))
+    return;
+  cond_expr = c_parser_gimple_postfix_expression (parser);
+  if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+    return;
+
+  if (! c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+    return;
+
+  while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
+    {
+      if (c_parser_next_token_is (parser, CPP_EOF))
+	{
+	  c_parser_error (parser, "expected statement");
+	  return;
+	}
+
+      switch (c_parser_peek_token (parser)->keyword)
+	{
+	case RID_CASE:
+	  {
+	    c_expr exp1;
+	    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_peek_token (parser)->type == CPP_NUMBER)
+	      exp1 = c_parser_gimple_postfix_expression (parser);
+	    else
+	      {
+		c_parser_error (parser, "expected expression");
+		return;
+	      }
+
+	    if (c_parser_next_token_is (parser, CPP_COLON))
+	      {
+		c_parser_consume_token (parser);
+		if (c_parser_next_token_is (parser, CPP_NAME))
+		  {
+		    label = c_parser_peek_token (parser)->value;
+		    c_parser_consume_token (parser);
+		    tree decl = lookup_label_for_goto (loc, label);
+		    case_label = build_case_label (exp1.value, NULL_TREE,
+						   decl);
+		    labels.safe_push (case_label);
+		    if (! c_parser_require (parser, CPP_SEMICOLON,
+					    "expected %<;%>"))
+		      return;
+		  }
+		else if (! c_parser_require (parser, CPP_NAME,
+					     "expected label"))
+		  return;
+	      }
+	    else if (! c_parser_require (parser, CPP_SEMICOLON,
+					 "expected %<:%>"))
+	      return;
+	    break;
+	  }
+	case RID_DEFAULT:
+	  {
+	    location_t loc = c_parser_peek_token (parser)->location;
+	    c_parser_consume_token (parser);
+	    if (c_parser_next_token_is (parser, CPP_COLON))
+	      {
+		c_parser_consume_token (parser);
+		if (c_parser_next_token_is (parser, CPP_NAME))
+		  {
+		    label = c_parser_peek_token (parser)->value;
+		    c_parser_consume_token (parser);
+		    tree decl = lookup_label_for_goto (loc, label);
+		    default_label = build_case_label (NULL_TREE, NULL_TREE,
+						      decl);
+		    if (! c_parser_require (parser, CPP_SEMICOLON,
+					    "expected %<;%>"))
+		      return;
+		  }
+		else if (! c_parser_require (parser, CPP_NAME,
+					     "expected label"))
+		  return;
+	      }
+	    else if (! c_parser_require (parser, CPP_SEMICOLON,
+					 "expected %<:%>"))
+	      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");
+	  return;
+	}
+
+    }
+  if (! c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"))
+    return;
+
+  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);
+    }
+}
+
+/* Parse gimple return statement.  */
+
+static void
+c_parser_gimple_return_stmt (c_parser *parser, gimple_seq *seq)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  gimple *ret = NULL;
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+    {
+      c_finish_gimple_return (loc, NULL_TREE);
+      ret = gimple_build_return (NULL);
+      gimple_seq_add_stmt (seq, ret);
+    }
+  else
+    {
+      location_t xloc = c_parser_peek_token (parser)->location;
+      c_expr expr = c_parser_gimple_unary_expression (parser);
+      if (expr.value != error_mark_node)
+	{
+	  c_finish_gimple_return (xloc, expr.value);
+	  ret = gimple_build_return (expr.value);
+	  gimple_seq_add_stmt (seq, ret);
+	}
+    }
+}
+
+/* Support function for c_parser_gimple_return_stmt.  */
+
+static void
+c_finish_gimple_return (location_t loc, tree retval)
+{
+  tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
+
+  /* Use the expansion point to handle cases such as returning NULL
+     in a function returning void.  */
+  source_location xloc = expansion_point_location_if_in_system_header (loc);
+
+  if (TREE_THIS_VOLATILE (current_function_decl))
+    warning_at (xloc, 0,
+		"function declared %<noreturn%> has a %<return%> statement");
+
+  if (! retval)
+    current_function_returns_null = 1;
+  else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE)
+    {
+      current_function_returns_null = 1;
+      if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
+	{
+	  error_at
+	    (xloc, "%<return%> with a value, in function returning void");
+	  inform (DECL_SOURCE_LOCATION (current_function_decl),
+		  "declared here");
+	}
+    }
+  else if (TREE_CODE (valtype) != TREE_CODE (TREE_TYPE (retval)))
+    {
+      error_at
+	(xloc, "invalid conversion in return statement");
+      inform (DECL_SOURCE_LOCATION (current_function_decl),
+	      "declared here");
+    }
+  return;
+}