diff mbox

[1/2] GIMPLE Frontend, C FE parts (and GIMPLE parser)

Message ID alpine.LSU.2.11.1610281336330.5294@t29.fhfr.qr
State New
Headers show

Commit Message

Richard Biener Oct. 28, 2016, 11:46 a.m. UTC
These are the C (and ObjC) Frontend changes required by the GIMPLE
Frontend which is now itself contained in c/gimple-parser.[ch].

Most changes are due to a new c-parser.h header where we export
stuff from the C parser that the GIMPLE frontend requires.  Other
changes include new __GIMPLE and __PHI keywords, handling
__GIMPLE as new declspec and dispatching to the GIMPLE parser
for __GIMPLE marked function definitions.

We'd like to include the GIMPLE parser for GCC 7, as the parser
is pretty self-contained (and now works to a good extent) it can
be improved during stage3 or when testcases show that it needs
improvement.

Bootstrapped and tested on x86_64-unknown-linux-gnu (together with [2/2])
for C, ObjC.

Ok for trunk?

Thanks,
Richard.

2016-10-28  Prasad Ghangal  <prasad.ghangal@gmail.com>
	Richard Biener  <rguenther@suse.de>
    
    	c/
    	* Make-lang.in (C_AND_OBJC_OBJS): Add gimple-parser.o.
    	* config-lang.in (gtfiles): Add c/c-parser.h.
    	* c-tree.h (enum c_declspec_word): Add cdw_gimple.
    	(struct c_declspecs): Add gimple_pass member and gimple_p flag.
    	* c-parser.c (enum c_id_kind, struct c_token,
    	c_parser_next_token_is, c_parser_next_token_is_not,
    	c_parser_next_token_is_keyword,
    	enum c_lookahead_kind, enum c_dtr_syn, enum c_parser_prec):
    	Split out to ...
    	* c-parser.h: ... new header.
    	* c-parser.c: Include c-parser.h and gimple-parser.h.
	(c_parser_peek_token, c_parser_peek_2nd_token,
    	c_token_starts_typename, c_parser_next_token_starts_declspecs,
    	c_parser_next_tokens_start_declaration, c_parser_consume_token,
    	c_parser_error, c_parser_require, c_parser_skip_until_found,
    	c_parser_declspecs, c_parser_declarator, c_parser_peek_nth_token,
    	c_parser_cast_expression): Export.
    	(c_parser_tokens_buf): New function.
    	(c_parser_error): Likewise.
    	(c_parser_set_error): Likewise.
    	(c_parser_declspecs): Handle RID_GIMPLE.
	(c_parser_declaration_or_fndef): Parse __GIMPLE marked body
	via c_parser_parse_gimple_body.
    	* c-parser.h (c_parser_peek_token, c_parser_peek_2nd_token,
    	c_token_starts_typename, c_parser_next_token_starts_declspecs,
    	c_parser_next_tokens_start_declaration, c_parser_consume_token,
    	c_parser_error, c_parser_require, c_parser_skip_until_found,
    	c_parser_declspecs, c_parser_declarator, c_parser_peek_nth_token,
    	c_parser_cast_expression): Declare.
	(struct c_parser): Declare forward.
	(c_parser_tokens_buf): Declare.
        (c_parser_error): Likewise.
        (c_parser_set_error): Likewise.
    	* gimple-parser.c: New file.
    	* gimple-parser.h: Likewise.
    
    	obj-c/
    	* config-lang.in (gtfiles): Add c/c-parser.h.

    	c-family/
    	* c-common.h (c_common_resword): Add RID_GIMPLE, RID_PHI types.
    	* c-common.h (enum rid): Add RID_GIMPLE, RID_PHI.
    	* c.opt (fgimple): New option.

	* doc/invoke.texi (fgimple): Document.

Comments

Richard Biener Nov. 4, 2016, 1:58 p.m. UTC | #1
On Fri, 28 Oct 2016, Richard Biener wrote:

> 
> These are the C (and ObjC) Frontend changes required by the GIMPLE
> Frontend which is now itself contained in c/gimple-parser.[ch].
> 
> Most changes are due to a new c-parser.h header where we export
> stuff from the C parser that the GIMPLE frontend requires.  Other
> changes include new __GIMPLE and __PHI keywords, handling
> __GIMPLE as new declspec and dispatching to the GIMPLE parser
> for __GIMPLE marked function definitions.
> 
> We'd like to include the GIMPLE parser for GCC 7, as the parser
> is pretty self-contained (and now works to a good extent) it can
> be improved during stage3 or when testcases show that it needs
> improvement.
> 
> Bootstrapped and tested on x86_64-unknown-linux-gnu (together with [2/2])
> for C, ObjC.
> 
> Ok for trunk?

Ping.

Thanks,
Richard.

> Thanks,
> Richard.
> 
> 2016-10-28  Prasad Ghangal  <prasad.ghangal@gmail.com>
> 	Richard Biener  <rguenther@suse.de>
>     
>     	c/
>     	* Make-lang.in (C_AND_OBJC_OBJS): Add gimple-parser.o.
>     	* config-lang.in (gtfiles): Add c/c-parser.h.
>     	* c-tree.h (enum c_declspec_word): Add cdw_gimple.
>     	(struct c_declspecs): Add gimple_pass member and gimple_p flag.
>     	* c-parser.c (enum c_id_kind, struct c_token,
>     	c_parser_next_token_is, c_parser_next_token_is_not,
>     	c_parser_next_token_is_keyword,
>     	enum c_lookahead_kind, enum c_dtr_syn, enum c_parser_prec):
>     	Split out to ...
>     	* c-parser.h: ... new header.
>     	* c-parser.c: Include c-parser.h and gimple-parser.h.
> 	(c_parser_peek_token, c_parser_peek_2nd_token,
>     	c_token_starts_typename, c_parser_next_token_starts_declspecs,
>     	c_parser_next_tokens_start_declaration, c_parser_consume_token,
>     	c_parser_error, c_parser_require, c_parser_skip_until_found,
>     	c_parser_declspecs, c_parser_declarator, c_parser_peek_nth_token,
>     	c_parser_cast_expression): Export.
>     	(c_parser_tokens_buf): New function.
>     	(c_parser_error): Likewise.
>     	(c_parser_set_error): Likewise.
>     	(c_parser_declspecs): Handle RID_GIMPLE.
> 	(c_parser_declaration_or_fndef): Parse __GIMPLE marked body
> 	via c_parser_parse_gimple_body.
>     	* c-parser.h (c_parser_peek_token, c_parser_peek_2nd_token,
>     	c_token_starts_typename, c_parser_next_token_starts_declspecs,
>     	c_parser_next_tokens_start_declaration, c_parser_consume_token,
>     	c_parser_error, c_parser_require, c_parser_skip_until_found,
>     	c_parser_declspecs, c_parser_declarator, c_parser_peek_nth_token,
>     	c_parser_cast_expression): Declare.
> 	(struct c_parser): Declare forward.
> 	(c_parser_tokens_buf): Declare.
>         (c_parser_error): Likewise.
>         (c_parser_set_error): Likewise.
>     	* gimple-parser.c: New file.
>     	* gimple-parser.h: Likewise.
>     
>     	obj-c/
>     	* config-lang.in (gtfiles): Add c/c-parser.h.
> 
>     	c-family/
>     	* c-common.h (c_common_resword): Add RID_GIMPLE, RID_PHI types.
>     	* c-common.h (enum rid): Add RID_GIMPLE, RID_PHI.
>     	* c.opt (fgimple): New option.
> 
> 	* doc/invoke.texi (fgimple): Document.
>  
> diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
> index 307862b..2997c83 100644
> --- a/gcc/c-family/c-common.c
> +++ b/gcc/c-family/c-common.c
> @@ -435,6 +435,8 @@ const struct c_common_resword c_common_reswords[] =
>    { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
>    { "__volatile",	RID_VOLATILE,	0 },
>    { "__volatile__",	RID_VOLATILE,	0 },
> +  { "__GIMPLE",		RID_GIMPLE,	D_CONLY },
> +  { "__PHI",		RID_PHI,	D_CONLY },
>    { "alignas",		RID_ALIGNAS,	D_CXXONLY | D_CXX11 | D_CXXWARN },
>    { "alignof",		RID_ALIGNOF,	D_CXXONLY | D_CXX11 | D_CXXWARN },
>    { "asm",		RID_ASM,	D_ASM },
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 547bab2..1fbe060 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -118,6 +118,12 @@ enum rid
>  
>    RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, RID_BUILTIN_CALL_WITH_STATIC_CHAIN,
>  
> +  /* "__GIMPLE", for the GIMPLE-parsing extension to the C frontend. */
> +  RID_GIMPLE,
> +
> +  /* "__PHI", for parsing PHI function in GIMPLE FE.  */
> +  RID_PHI,
> +
>    /* C11 */
>    RID_ALIGNAS, RID_GENERIC,
>  
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index 458d453..24d3b8e 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -200,6 +200,10 @@ F
>  Driver C ObjC C++ ObjC++ Joined Separate MissingArgError(missing path after %qs)
>  -F <dir>	Add <dir> to the end of the main framework include path.
>  
> +fgimple
> +C Var(flag_gimple) Init(0)
> +Enable parsing GIMPLE.
> +
>  H
>  C ObjC C++ ObjC++
>  Print the name of header files as they are used.
> diff --git a/gcc/c/Make-lang.in b/gcc/c/Make-lang.in
> index 72c9ae7..cd7108b 100644
> --- a/gcc/c/Make-lang.in
> +++ b/gcc/c/Make-lang.in
> @@ -51,7 +51,8 @@ CFLAGS-c/gccspec.o += $(DRIVER_DEFINES)
>  # Language-specific object files for C and Objective C.
>  C_AND_OBJC_OBJS = attribs.o c/c-errors.o c/c-decl.o c/c-typeck.o \
>    c/c-convert.o c/c-aux-info.o c/c-objc-common.o c/c-parser.o \
> -  c/c-array-notation.o c/c-fold.o $(C_COMMON_OBJS) $(C_TARGET_OBJS)
> +  c/c-array-notation.o c/c-fold.o c/gimple-parser.o \
> +  $(C_COMMON_OBJS) $(C_TARGET_OBJS)
>  
>  # Language-specific object files for C.
>  C_OBJS = c/c-lang.o c-family/stub-objc.o $(C_AND_OBJC_OBJS)
> diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
> index 6bc42da..d21b8e9 100644
> --- a/gcc/c/c-parser.c
> +++ b/gcc/c/c-parser.c
> @@ -59,6 +59,8 @@ along with GCC; see the file COPYING3.  If not see
>  #include "gimple-expr.h"
>  #include "context.h"
>  #include "gcc-rich-location.h"
> +#include "c-parser.h"
> +#include "gimple-parser.h"
>  
>  /* We need to walk over decls with incomplete struct/union/enum types
>     after parsing the whole translation unit.
> @@ -150,63 +152,6 @@ c_parse_init (void)
>      }
>  }
>  
> -/* The C lexer intermediates between the lexer in cpplib and c-lex.c
> -   and the C parser.  Unlike the C++ lexer, the parser structure
> -   stores the lexer information instead of using a separate structure.
> -   Identifiers are separated into ordinary identifiers, type names,
> -   keywords and some other Objective-C types of identifiers, and some
> -   look-ahead is maintained.
> -
> -   ??? It might be a good idea to lex the whole file up front (as for
> -   C++).  It would then be possible to share more of the C and C++
> -   lexer code, if desired.  */
> -
> -/* More information about the type of a CPP_NAME token.  */
> -enum c_id_kind {
> -  /* An ordinary identifier.  */
> -  C_ID_ID,
> -  /* An identifier declared as a typedef name.  */
> -  C_ID_TYPENAME,
> -  /* An identifier declared as an Objective-C class name.  */
> -  C_ID_CLASSNAME,
> -  /* An address space identifier.  */
> -  C_ID_ADDRSPACE,
> -  /* Not an identifier.  */
> -  C_ID_NONE
> -};
> -
> -/* A single C token after string literal concatenation and conversion
> -   of preprocessing tokens to tokens.  */
> -struct GTY (()) c_token {
> -  /* The kind of token.  */
> -  ENUM_BITFIELD (cpp_ttype) type : 8;
> -  /* If this token is a CPP_NAME, this value indicates whether also
> -     declared as some kind of type.  Otherwise, it is C_ID_NONE.  */
> -  ENUM_BITFIELD (c_id_kind) id_kind : 8;
> -  /* If this token is a keyword, this value indicates which keyword.
> -     Otherwise, this value is RID_MAX.  */
> -  ENUM_BITFIELD (rid) keyword : 8;
> -  /* If this token is a CPP_PRAGMA, this indicates the pragma that
> -     was seen.  Otherwise it is PRAGMA_NONE.  */
> -  ENUM_BITFIELD (pragma_kind) pragma_kind : 8;
> -  /* The location at which this token was found.  */
> -  location_t location;
> -  /* The value associated with this token, if any.  */
> -  tree value;
> -  /* Token flags.  */
> -  unsigned char flags;
> -
> -  source_range get_range () const
> -  {
> -    return get_range_from_loc (line_table, location);
> -  }
> -
> -  location_t get_finish () const
> -  {
> -    return get_range ().m_finish;
> -  }
> -};
> -
>  /* A parser structure recording information about the state and
>     context of parsing.  Includes lexer information with up to two
>     tokens of look-ahead; more are not needed for C.  */
> @@ -259,6 +204,30 @@ struct GTY(()) c_parser {
>    vec <c_token, va_gc> *cilk_simd_fn_tokens;
>  };
>  
> +/* Return a pointer to the Nth token in PARERs tokens_buf.  */
> +
> +c_token *
> +c_parser_tokens_buf (c_parser *parser, unsigned n)
> +{
> +  return &parser->tokens_buf[n];
> +}
> +
> +/* Return the error state of PARSER.  */
> +
> +bool
> +c_parser_error (c_parser *parser)
> +{
> +  return parser->error;
> +}
> +
> +/* Set the error state of PARSER to ERR.  */
> +
> +void
> +c_parser_set_error (c_parser *parser, bool err)
> +{
> +  parser->error = err;
> +}
> +
>  
>  /* The actual parser and external interface.  ??? Does this need to be
>     garbage-collected?  */
> @@ -454,7 +423,7 @@ c_lex_one_token (c_parser *parser, c_token *token)
>  /* Return a pointer to the next token from PARSER, reading it in if
>     necessary.  */
>  
> -static inline c_token *
> +c_token *
>  c_parser_peek_token (c_parser *parser)
>  {
>    if (parser->tokens_avail == 0)
> @@ -465,37 +434,10 @@ c_parser_peek_token (c_parser *parser)
>    return &parser->tokens[0];
>  }
>  
> -/* Return true if the next token from PARSER has the indicated
> -   TYPE.  */
> -
> -static inline bool
> -c_parser_next_token_is (c_parser *parser, enum cpp_ttype type)
> -{
> -  return c_parser_peek_token (parser)->type == type;
> -}
> -
> -/* Return true if the next token from PARSER does not have the
> -   indicated TYPE.  */
> -
> -static inline bool
> -c_parser_next_token_is_not (c_parser *parser, enum cpp_ttype type)
> -{
> -  return !c_parser_next_token_is (parser, type);
> -}
> -
> -/* Return true if the next token from PARSER is the indicated
> -   KEYWORD.  */
> -
> -static inline bool
> -c_parser_next_token_is_keyword (c_parser *parser, enum rid keyword)
> -{
> -  return c_parser_peek_token (parser)->keyword == keyword;
> -}
> -
>  /* Return a pointer to the next-but-one token from PARSER, reading it
>     in if necessary.  The next token is already read in.  */
>  
> -static c_token *
> +c_token *
>  c_parser_peek_2nd_token (c_parser *parser)
>  {
>    if (parser->tokens_avail >= 2)
> @@ -511,7 +453,7 @@ c_parser_peek_2nd_token (c_parser *parser)
>  /* Return a pointer to the Nth token from PARSER, reading it
>     in if necessary.  The N-1th token is already read in.  */
>  
> -static c_token *
> +c_token *
>  c_parser_peek_nth_token (c_parser *parser, unsigned int n)
>  {
>    /* N is 1-based, not zero-based.  */
> @@ -570,7 +512,7 @@ c_keyword_starts_typename (enum rid keyword)
>  
>  /* Return true if TOKEN can start a type name,
>     false otherwise.  */
> -static bool
> +bool
>  c_token_starts_typename (c_token *token)
>  {
>    switch (token->type)
> @@ -601,18 +543,6 @@ c_token_starts_typename (c_token *token)
>      }
>  }
>  
> -enum c_lookahead_kind {
> -  /* Always treat unknown identifiers as typenames.  */
> -  cla_prefer_type,
> -
> -  /* Could be parsing a nonabstract declarator.  Only treat an identifier
> -     as a typename if followed by another identifier or a star.  */
> -  cla_nonabstract_decl,
> -
> -  /* Never treat identifiers as typenames.  */
> -  cla_prefer_id
> -};
> -
>  /* Return true if the next token from PARSER can start a type name,
>     false otherwise.  LA specifies how to do lookahead in order to
>     detect unknown type names.  If unsure, pick CLA_PREFER_ID.  */
> @@ -779,7 +709,7 @@ c_token_starts_declaration (c_token *token)
>  
>  /* Return true if the next token from PARSER can start declaration
>     specifiers, false otherwise.  */
> -static inline bool
> +bool
>  c_parser_next_token_starts_declspecs (c_parser *parser)
>  {
>    c_token *token = c_parser_peek_token (parser);
> @@ -801,7 +731,7 @@ c_parser_next_token_starts_declspecs (c_parser *parser)
>  
>  /* Return true if the next tokens from PARSER can start declaration
>     specifiers or a static assertion, false otherwise.  */
> -static inline bool
> +bool
>  c_parser_next_tokens_start_declaration (c_parser *parser)
>  {
>    c_token *token = c_parser_peek_token (parser);
> @@ -829,7 +759,7 @@ c_parser_next_tokens_start_declaration (c_parser *parser)
>  
>  /* Consume the next token from PARSER.  */
>  
> -static void
> +void
>  c_parser_consume_token (c_parser *parser)
>  {
>    gcc_assert (parser->tokens_avail >= 1);
> @@ -922,7 +852,7 @@ c_parser_peek_conflict_marker (c_parser *parser, enum cpp_ttype tok1_kind,
>     this way is not i18n-friendly and some other approach should be
>     used.  */
>  
> -static void
> +void
>  c_parser_error (c_parser *parser, const char *gmsgid)
>  {
>    c_token *token = c_parser_peek_token (parser);
> @@ -965,7 +895,7 @@ c_parser_error (c_parser *parser, const char *gmsgid)
>     been produced and no message will be produced this time.  Returns
>     true if found, false otherwise.  */
>  
> -static bool
> +bool
>  c_parser_require (c_parser *parser,
>  		  enum cpp_ttype type,
>  		  const char *msgid)
> @@ -1008,7 +938,7 @@ c_parser_require_keyword (c_parser *parser,
>     already been produced and no message will be produced this
>     time.  */
>  
> -static void
> +void
>  c_parser_skip_until_found (c_parser *parser,
>  			   enum cpp_ttype type,
>  			   const char *msgid)
> @@ -1243,42 +1173,6 @@ restore_extension_diagnostics (int flags)
>    warn_c99_c11_compat = (flags >> 9) & 1 ? 1 : ((flags >> 10) & 1 ? -1 : 0);
>  }
>  
> -/* Possibly kinds of declarator to parse.  */
> -enum c_dtr_syn {
> -  /* A normal declarator with an identifier.  */
> -  C_DTR_NORMAL,
> -  /* An abstract declarator (maybe empty).  */
> -  C_DTR_ABSTRACT,
> -  /* A parameter declarator: may be either, but after a type name does
> -     not redeclare a typedef name as an identifier if it can
> -     alternatively be interpreted as a typedef name; see DR#009,
> -     applied in C90 TC1, omitted from C99 and reapplied in C99 TC2
> -     following DR#249.  For example, given a typedef T, "int T" and
> -     "int *T" are valid parameter declarations redeclaring T, while
> -     "int (T)" and "int * (T)" and "int (T[])" and "int (T (int))" are
> -     abstract declarators rather than involving redundant parentheses;
> -     the same applies with attributes inside the parentheses before
> -     "T".  */
> -  C_DTR_PARM
> -};
> -
> -/* The binary operation precedence levels, where 0 is a dummy lowest level
> -   used for the bottom of the stack.  */
> -enum c_parser_prec {
> -  PREC_NONE,
> -  PREC_LOGOR,
> -  PREC_LOGAND,
> -  PREC_BITOR,
> -  PREC_BITXOR,
> -  PREC_BITAND,
> -  PREC_EQ,
> -  PREC_REL,
> -  PREC_SHIFT,
> -  PREC_ADD,
> -  PREC_MULT,
> -  NUM_PRECS
> -};
> -
>  /* Helper data structure for parsing #pragma acc routine.  */
>  struct oacc_routine_data {
>    bool error_seen; /* Set if error has been reported.  */
> @@ -1295,15 +1189,11 @@ static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
>  					   bool * = NULL);
>  static void c_parser_static_assert_declaration_no_semi (c_parser *);
>  static void c_parser_static_assert_declaration (c_parser *);
> -static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
> -				bool, bool, bool, enum c_lookahead_kind);
>  static struct c_typespec c_parser_enum_specifier (c_parser *);
>  static struct c_typespec c_parser_struct_or_union_specifier (c_parser *);
>  static tree c_parser_struct_declaration (c_parser *);
>  static struct c_typespec c_parser_typeof_specifier (c_parser *);
>  static tree c_parser_alignas_specifier (c_parser *);
> -static struct c_declarator *c_parser_declarator (c_parser *, bool, c_dtr_syn,
> -						 bool *);
>  static struct c_declarator *c_parser_direct_declarator (c_parser *, bool,
>  							c_dtr_syn, bool *);
>  static struct c_declarator *c_parser_direct_declarator_inner (c_parser *,
> @@ -1343,7 +1233,6 @@ static struct c_expr c_parser_conditional_expression (c_parser *,
>  						      struct c_expr *, tree);
>  static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
>  						 tree);
> -static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
>  static struct c_expr c_parser_unary_expression (c_parser *);
>  static struct c_expr c_parser_sizeof_expression (c_parser *);
>  static struct c_expr c_parser_alignof_expression (c_parser *);
> @@ -1652,7 +1541,13 @@ static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
>     OpenMP:
>  
>     declaration:
> -     threadprivate-directive  */
> +     threadprivate-directive
> +
> +   GIMPLE:
> +
> +   gimple-function-definition:
> +     declaration-specifiers[opt] __GIMPLE (gimple-pass-list) declarator
> +       declaration-list[opt] compound-statement  */
>  
>  static void
>  c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
> @@ -1752,6 +1647,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
>        c_parser_skip_to_end_of_block_or_statement (parser);
>        return;
>      }
> +
>    finish_declspecs (specs);
>    bool auto_type_p = specs->typespec_word == cts_auto_type;
>    if (c_parser_next_token_is (parser, CPP_SEMICOLON))
> @@ -1882,7 +1778,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
>        struct c_declarator *declarator;
>        bool dummy = false;
>        timevar_id_t tv;
> -      tree fnbody;
> +      tree fnbody = NULL_TREE;
>        /* Declaring either one or more declarators (in which case we
>  	 should diagnose if there were no declaration specifiers) or a
>  	 function definition (in which case the diagnostic for
> @@ -2173,9 +2069,24 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
>  	c_finish_oacc_routine (oacc_routine_data, current_function_decl, true);
>        DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
>  	= c_parser_peek_token (parser)->location;
> -      fnbody = c_parser_compound_statement (parser);
> -      if (flag_cilkplus && contains_array_notation_expr (fnbody))
> -	fnbody = expand_array_notation_exprs (fnbody);
> +
> +      /* If the definition was marked with __GIMPLE then parse the
> +         function body as GIMPLE.  */
> +      if (specs->gimple_p)
> +	{
> +	  cfun->pass_startwith = specs->gimple_pass;
> +	  bool saved = in_late_binary_op;
> +	  in_late_binary_op = true;
> +	  c_parser_parse_gimple_body (parser);
> +	  in_late_binary_op = saved;
> +	}
> +      else
> +	{
> +	  fnbody = c_parser_compound_statement (parser);
> +	  if (flag_cilkplus && contains_array_notation_expr (fnbody))
> +	    fnbody = expand_array_notation_exprs (fnbody);
> +	}
> +      tree fndecl = current_function_decl;
>        if (nested)
>  	{
>  	  tree decl = current_function_decl;
> @@ -2191,9 +2102,13 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
>  	}
>        else
>  	{
> -	  add_stmt (fnbody);
> +	  if (fnbody)
> +	    add_stmt (fnbody);
>  	  finish_function ();
>  	}
> +      /* Get rid of the empty stmt list for GIMPLE.  */
> +      if (specs->gimple_p)
> +	DECL_SAVED_TREE (fndecl) = NULL_TREE;
>  
>        timevar_pop (tv);
>        break;
> @@ -2416,7 +2331,7 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser)
>       objc-protocol-refs
>  */
>  
> -static void
> +void
>  c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
>  		    bool scspec_ok, bool typespec_ok, bool start_attr_ok,
>  		    bool alignspec_ok, bool auto_type_ok,
> @@ -2681,6 +2596,14 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
>  	  align = c_parser_alignas_specifier (parser);
>  	  declspecs_add_alignas (loc, specs, align);
>  	  break;
> +	case RID_GIMPLE:
> +	  if (! flag_gimple)
> +	    error_at (loc, "%<__GIMPLE%> only valid with -fgimple");
> +	  c_parser_consume_token (parser);
> +	  specs->gimple_p = true;
> +	  specs->locations[cdw_gimple] = loc;
> +	  specs->gimple_pass = c_parser_gimple_pass_list (parser);
> +	  break;
>  	default:
>  	  goto out;
>  	}
> @@ -3415,7 +3338,7 @@ c_parser_alignas_specifier (c_parser * parser)
>     This function also accepts an omitted abstract declarator as being
>     an abstract declarator, although not part of the formal syntax.  */
>  
> -static struct c_declarator *
> +struct c_declarator *
>  c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
>  		     bool *seen_id)
>  {
> @@ -6866,7 +6789,7 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after,
>       ( type-name ) unary-expression
>  */
>  
> -static struct c_expr
> +struct c_expr
>  c_parser_cast_expression (c_parser *parser, struct c_expr *after)
>  {
>    location_t cast_loc = c_parser_peek_token (parser)->location;
> diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h
> new file mode 100644
> index 0000000..04fa681
> --- /dev/null
> +++ b/gcc/c/c-parser.h
> @@ -0,0 +1,189 @@
> +/* Declarations for the parser for C and Objective-C.
> +   Copyright (C) 1987-2016 Free Software Foundation, Inc.
> +
> +   Parser actions based on the old Bison parser; structure somewhat
> +   influenced by and fragments based on the C++ parser.
> +
> +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/>.  */
> +
> +#ifndef GCC_C_PARSER_H
> +#define GCC_C_PARSER_H
> +
> +/* The C lexer intermediates between the lexer in cpplib and c-lex.c
> +   and the C parser.  Unlike the C++ lexer, the parser structure
> +   stores the lexer information instead of using a separate structure.
> +   Identifiers are separated into ordinary identifiers, type names,
> +   keywords and some other Objective-C types of identifiers, and some
> +   look-ahead is maintained.
> +
> +   ??? It might be a good idea to lex the whole file up front (as for
> +   C++).  It would then be possible to share more of the C and C++
> +   lexer code, if desired.  */
> +
> +/* More information about the type of a CPP_NAME token.  */
> +enum c_id_kind {
> +  /* An ordinary identifier.  */
> +  C_ID_ID,
> +  /* An identifier declared as a typedef name.  */
> +  C_ID_TYPENAME,
> +  /* An identifier declared as an Objective-C class name.  */
> +  C_ID_CLASSNAME,
> +  /* An address space identifier.  */
> +  C_ID_ADDRSPACE,
> +  /* Not an identifier.  */
> +  C_ID_NONE
> +};
> +
> +/* A single C token after string literal concatenation and conversion
> +   of preprocessing tokens to tokens.  */
> +struct GTY (()) c_token {
> +  /* The kind of token.  */
> +  ENUM_BITFIELD (cpp_ttype) type : 8;
> +  /* If this token is a CPP_NAME, this value indicates whether also
> +     declared as some kind of type.  Otherwise, it is C_ID_NONE.  */
> +  ENUM_BITFIELD (c_id_kind) id_kind : 8;
> +  /* If this token is a keyword, this value indicates which keyword.
> +     Otherwise, this value is RID_MAX.  */
> +  ENUM_BITFIELD (rid) keyword : 8;
> +  /* If this token is a CPP_PRAGMA, this indicates the pragma that
> +     was seen.  Otherwise it is PRAGMA_NONE.  */
> +  ENUM_BITFIELD (pragma_kind) pragma_kind : 8;
> +  /* The location at which this token was found.  */
> +  location_t location;
> +  /* The value associated with this token, if any.  */
> +  tree value;
> +  /* Token flags.  */
> +  unsigned char flags;
> +
> +  source_range get_range () const
> +  {
> +    return get_range_from_loc (line_table, location);
> +  }
> +
> +  location_t get_finish () const
> +  {
> +    return get_range ().m_finish;
> +  }
> +};
> +
> +/* The parser.  */
> +struct c_parser;
> +
> +/* Possibly kinds of declarator to parse.  */
> +enum c_dtr_syn {
> +  /* A normal declarator with an identifier.  */
> +  C_DTR_NORMAL,
> +  /* An abstract declarator (maybe empty).  */
> +  C_DTR_ABSTRACT,
> +  /* A parameter declarator: may be either, but after a type name does
> +     not redeclare a typedef name as an identifier if it can
> +     alternatively be interpreted as a typedef name; see DR#009,
> +     applied in C90 TC1, omitted from C99 and reapplied in C99 TC2
> +     following DR#249.  For example, given a typedef T, "int T" and
> +     "int *T" are valid parameter declarations redeclaring T, while
> +     "int (T)" and "int * (T)" and "int (T[])" and "int (T (int))" are
> +     abstract declarators rather than involving redundant parentheses;
> +     the same applies with attributes inside the parentheses before
> +     "T".  */
> +  C_DTR_PARM
> +};
> +
> +/* The binary operation precedence levels, where 0 is a dummy lowest level
> +   used for the bottom of the stack.  */
> +enum c_parser_prec {
> +  PREC_NONE,
> +  PREC_LOGOR,
> +  PREC_LOGAND,
> +  PREC_BITOR,
> +  PREC_BITXOR,
> +  PREC_BITAND,
> +  PREC_EQ,
> +  PREC_REL,
> +  PREC_SHIFT,
> +  PREC_ADD,
> +  PREC_MULT,
> +  NUM_PRECS
> +};
> +
> +enum c_lookahead_kind {
> +  /* Always treat unknown identifiers as typenames.  */
> +  cla_prefer_type,
> +
> +  /* Could be parsing a nonabstract declarator.  Only treat an identifier
> +     as a typename if followed by another identifier or a star.  */
> +  cla_nonabstract_decl,
> +
> +  /* Never treat identifiers as typenames.  */
> +  cla_prefer_id
> +};
> +
> +
> +extern c_token * c_parser_peek_token (c_parser *parser);
> +extern c_token * c_parser_peek_2nd_token (c_parser *parser);
> +extern c_token * c_parser_peek_nth_token (c_parser *parser, unsigned int n);
> +extern bool c_parser_require (c_parser *parser, enum cpp_ttype type,
> +			      const char *msgid);
> +extern void c_parser_error (c_parser *parser, const char *gmsgid);
> +extern void c_parser_consume_token (c_parser *parser);
> +extern void c_parser_skip_until_found (c_parser *parser, enum cpp_ttype type,
> +				       const char *msgid);
> +extern bool c_parser_next_token_starts_declspecs (c_parser *parser);
> +bool c_parser_next_tokens_start_declaration (c_parser *parser);
> +bool c_token_starts_typename (c_token *token);
> +
> +/* Abstraction to avoid defining c_parser here which messes up gengtype
> +   output wrt ObjC due to vec<c_token> routines being put in gtype-c.h
> +   but not gtype-objc.h.  */
> +extern c_token * c_parser_tokens_buf (c_parser *parser, unsigned n);
> +extern bool c_parser_error (c_parser *parser);
> +extern void c_parser_set_error (c_parser *parser, bool);
> +
> +/* Return true if the next token from PARSER has the indicated
> +   TYPE.  */
> +
> +static inline bool
> +c_parser_next_token_is (c_parser *parser, enum cpp_ttype type)
> +{
> +  return c_parser_peek_token (parser)->type == type;
> +}
> +
> +/* Return true if the next token from PARSER does not have the
> +   indicated TYPE.  */
> +
> +static inline bool
> +c_parser_next_token_is_not (c_parser *parser, enum cpp_ttype type)
> +{
> +  return !c_parser_next_token_is (parser, type);
> +}
> +
> +/* Return true if the next token from PARSER is the indicated
> +   KEYWORD.  */
> +
> +static inline bool
> +c_parser_next_token_is_keyword (c_parser *parser, enum rid keyword)
> +{
> +  return c_parser_peek_token (parser)->keyword == keyword;
> +}
> +
> +extern struct c_declarator *
> +c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
> +		     bool *seen_id);
> +extern void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
> +				bool, bool, bool, enum c_lookahead_kind);
> +extern struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
> +
> +#endif
> diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
> index e8060f8..a8cf353 100644
> --- a/gcc/c/c-tree.h
> +++ b/gcc/c/c-tree.h
> @@ -267,6 +267,7 @@ enum c_declspec_word {
>    cdw_saturating,
>    cdw_alignas,
>    cdw_address_space,
> +  cdw_gimple,
>    cdw_number_of_elements /* This one must always be the last
>  			    enumerator.  */
>  };
> @@ -290,6 +291,8 @@ struct c_declspecs {
>       NULL; attributes (possibly from multiple lists) will be passed
>       separately.  */
>    tree attrs;
> +  /* The pass to start compiling a __GIMPLE function with.  */
> +  char *gimple_pass;
>    /* The base-2 log of the greatest alignment required by an _Alignas
>       specifier, in bytes, or -1 if no such specifiers with nonzero
>       alignment.  */
> @@ -362,6 +365,8 @@ 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;
>    /* The address space that the declaration belongs to.  */
>    addr_space_t address_space;
>  };
> diff --git a/gcc/c/config-lang.in b/gcc/c/config-lang.in
> index b9cdc8e..51fbb53 100644
> --- a/gcc/c/config-lang.in
> +++ b/gcc/c/config-lang.in
> @@ -29,4 +29,4 @@ compilers="cc1\$(exeext)"
>  
>  target_libs=
>  
> -gtfiles="\$(srcdir)/c/c-lang.c \$(srcdir)/c/c-tree.h \$(srcdir)/c/c-decl.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/c/c-objc-common.c \$(srcdir)/c/c-parser.c \$(srcdir)/c/c-lang.h"
> +gtfiles="\$(srcdir)/c/c-lang.c \$(srcdir)/c/c-tree.h \$(srcdir)/c/c-decl.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/c/c-objc-common.c \$(srcdir)/c/c-parser.h \$(srcdir)/c/c-parser.c \$(srcdir)/c/c-lang.h"
> diff --git a/gcc/c/gimple-parser.c b/gcc/c/gimple-parser.c
> new file mode 100644
> index 0000000..7f8d948
> --- /dev/null
> +++ b/gcc/c/gimple-parser.c
> @@ -0,0 +1,1483 @@
> +/* Parser for GIMPLE.
> +   Copyright (C) 2016 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 "omp-low.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"
> +#include "tree-dump.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_expression (c_parser *, gimple_seq *);
> +static struct c_expr c_parser_gimple_binary_expression (c_parser *, enum tree_code *);
> +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 vec<tree, va_gc> *c_parser_gimple_expr_list (c_parser *,
> +		    vec<tree, va_gc> **, vec<location_t> *);
> +
> +
> +/* 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_generic, 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;
> +
> +	default:
> +expr_stmt:
> +	  c_parser_gimple_expression (parser, seq);
> +	  if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
> +	    return return_p;
> +	}
> +    }
> +  c_parser_consume_token (parser);
> +  return return_p;
> +}
> +
> +/* Parse a gimple expression.
> +
> +   gimple-expression:
> +     gimple-unary-expression
> +     gimple-call-statement
> +     gimple-binary-expression
> +     gimple-assign-expression
> +     gimple-cast-expression
> +
> +*/
> +
> +static void
> +c_parser_gimple_expression (c_parser *parser, gimple_seq *seq)
> +{
> +  struct c_expr lhs, rhs;
> +  gimple *assign = NULL;
> +  enum tree_code subcode = NOP_EXPR;
> +  location_t loc;
> +  tree arg = NULL_TREE;
> +  auto_vec<tree> vargs;
> +
> +  lhs = c_parser_gimple_unary_expression (parser);
> +  rhs.value = error_mark_node;
> +
> +  if (c_parser_next_token_is (parser, CPP_EQ))
> +    c_parser_consume_token (parser);
> +
> +  loc = EXPR_LOCATION (lhs.value);
> +
> +  /* GIMPLE call expression.  */
> +  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);
> +      gimple_seq_add_stmt (seq, call);
> +      gimple_set_location (call, loc);
> +      return;
> +    }
> +
> +  /* Cast expression.  */
> +  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
> +      && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
> +    {
> +      /* TODO: have a gimple_cast_expr function.  */
> +      rhs = c_parser_cast_expression (parser, NULL);
> +      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;
> +	}
> +    }
> +
> +  /* Pointer expression.  */
> +  if (TREE_CODE (lhs.value) == INDIRECT_REF)
> +    {
> +      tree save_expr = lhs.value;
> +      bool volatilep = TREE_THIS_VOLATILE (lhs.value);
> +      bool notrap = TREE_THIS_NOTRAP (lhs.value);
> +      tree saved_ptr_type = TREE_TYPE (TREE_OPERAND (lhs.value, 0));
> +
> +      lhs.value = fold_indirect_ref_loc (loc, lhs.value);
> +      if (lhs.value == save_expr)
> +	{
> +	  lhs.value = fold_build2_loc (input_location, MEM_REF,
> +				       TREE_TYPE (lhs.value),
> +				       TREE_OPERAND (lhs.value, 0),
> +				       build_int_cst (saved_ptr_type, 0));
> +	  TREE_THIS_VOLATILE (lhs.value) = volatilep;
> +	  TREE_THIS_NOTRAP (lhs.value) = notrap;
> +	}
> +    }
> +
> +  switch (c_parser_peek_token (parser)->type)
> +    {
> +    case CPP_AND:
> +    case CPP_PLUS:
> +    case CPP_MINUS:
> +    case CPP_COMPL:
> +    case CPP_NOT:
> +    case CPP_MULT: /* pointer deref */
> +      rhs = c_parser_gimple_unary_expression (parser);
> +      assign = gimple_build_assign (lhs.value, rhs.value);
> +      gimple_set_location (assign, loc);
> +      gimple_seq_add_stmt (seq, assign);
> +      return;
> +
> +    default:;
> +    }
> +
> +  /* GIMPLE PHI expression.  */
> +  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);
> +      gimple *call = gimple_build_call_from_tree (rhs.value);
> +      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, &subcode);
> +
> +  if (lhs.value != error_mark_node
> +      && rhs.value != error_mark_node)
> +    {
> +      if (subcode == NOP_EXPR)
> +	assign = gimple_build_assign (lhs.value, rhs.value);
> +      else
> +	assign = gimple_build_assign (lhs.value, subcode,
> +				      TREE_OPERAND (rhs.value, 0),
> +				      TREE_OPERAND (rhs.value, 1));
> +      gimple_seq_add_stmt (seq, assign);
> +      gimple_set_location (assign, loc);
> +    }
> +  return;
> +}
> +
> +/* Parse gimple binary expr.
> +
> +   gimple-multiplicative-expression:
> +     gimple-unary-expression * gimple-unary-expression
> +     gimple-unary-expression / gimple-unary-expression
> +     gimple-unary-expression % gimple-unary-expression
> +
> +   gimple-additive-expression:
> +     gimple-unary-expression + gimple-unary-expression
> +     gimple-unary-expression - gimple-unary-expression
> +
> +   gimple-shift-expression:
> +     gimple-unary-expression << gimple-unary-expression
> +     gimple-unary-expression >> gimple-unary-expression
> +
> +   gimple-relational-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-equality-expression:
> +     gimple-unary-expression == gimple-unary-expression
> +     gimple-unary-expression != gimple-unary-expression
> +
> +   gimple-AND-expression:
> +     gimple-unary-expression & gimple-unary-expression
> +
> +   gimple-exclusive-OR-expression:
> +     gimple-unary-expression ^ gimple-unary-expression
> +
> +   gimple-inclusive-OR-expression:
> +     gimple-unary-expression | gimple-unary-expression
> +
> +   gimple-logical-AND-expression:
> +     gimple-unary-expression && gimple-unary-expression
> +
> +   gimple-logical-OR-expression:
> +     gimple-unary-expression || gimple-unary-expression
> +
> +*/
> +
> +static c_expr
> +c_parser_gimple_binary_expression (c_parser *parser, enum tree_code *subcode)
> +{
> +  struct {
> +    /* The expression at this stack level.  */
> +    struct c_expr expr;
> +    /* The operation on its left.  */
> +    enum tree_code op;
> +    /* The source location of this operation.  */
> +    location_t loc;
> +  } stack[2];
> +  int sp;
> +  /* Location of the binary operator.  */
> +  location_t binary_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
> +#define POP								      \
> +  do {									      \
> +    if (sp == 1								      \
> +	&& c_parser_peek_token (parser)->type == CPP_SEMICOLON		      \
> +	&& (((1 << PREC_BITOR) | (1 << PREC_BITXOR) | (1 << PREC_BITAND)      \
> +	       | (1 << PREC_SHIFT) | (1 << PREC_ADD) | (1 << PREC_MULT)))     \
> +	&& stack[sp].op != TRUNC_MOD_EXPR				      \
> +	&& stack[0].expr.value != error_mark_node			      \
> +	&& stack[1].expr.value != error_mark_node)			      \
> +      stack[0].expr.value						      \
> +	= build2 (stack[1].op, TREE_TYPE (stack[0].expr.value),		      \
> +		  stack[0].expr.value, stack[1].expr.value);		      \
> +    else								      \
> +      stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc,	      \
> +						   stack[sp].op,	      \
> +						   stack[sp - 1].expr,	      \
> +						   stack[sp].expr);	      \
> +    sp--;								      \
> +  } while (0)
> +  stack[0].loc = c_parser_peek_token (parser)->location;
> +  stack[0].expr = c_parser_gimple_unary_expression (parser);
> +  sp = 0;
> +  source_range src_range;
> +  if (c_parser_error (parser))
> +    goto out;
> +  switch (c_parser_peek_token (parser)->type)
> +    {
> +    case CPP_MULT:
> +      *subcode = MULT_EXPR;
> +      break;
> +    case CPP_DIV:
> +      *subcode = TRUNC_DIV_EXPR;
> +      break;
> +    case CPP_MOD:
> +      *subcode = TRUNC_MOD_EXPR;
> +      break;
> +    case CPP_PLUS:
> +      *subcode = PLUS_EXPR;
> +      break;
> +    case CPP_MINUS:
> +      *subcode = MINUS_EXPR;
> +      break;
> +    case CPP_LSHIFT:
> +      *subcode = LSHIFT_EXPR;
> +      break;
> +    case CPP_RSHIFT:
> +      *subcode = RSHIFT_EXPR;
> +      break;
> +    case CPP_LESS:
> +      *subcode = LT_EXPR;
> +      break;
> +    case CPP_GREATER:
> +      *subcode = GT_EXPR;
> +      break;
> +    case CPP_LESS_EQ:
> +      *subcode = LE_EXPR;
> +      break;
> +    case CPP_GREATER_EQ:
> +      *subcode = GE_EXPR;
> +      break;
> +    case CPP_EQ_EQ:
> +      *subcode = EQ_EXPR;
> +      break;
> +    case CPP_NOT_EQ:
> +      *subcode = NE_EXPR;
> +      break;
> +    case CPP_AND:
> +      *subcode = BIT_AND_EXPR;
> +      break;
> +    case CPP_XOR:
> +      *subcode = BIT_XOR_EXPR;
> +      break;
> +    case CPP_OR:
> +      *subcode = BIT_IOR_EXPR;
> +      break;
> +    case CPP_AND_AND:
> +      *subcode = TRUTH_ANDIF_EXPR;
> +      break;
> +    case CPP_OR_OR:
> +      *subcode = TRUTH_ORIF_EXPR;
> +      break;
> +    default:
> +      /* Not a binary operator, so end of the binary expression.  */
> +      *subcode = NOP_EXPR;
> +      goto out;
> +    }
> +  binary_loc = c_parser_peek_token (parser)->location;
> +  c_parser_consume_token (parser);
> +  switch (*subcode)
> +    {
> +    case TRUTH_ANDIF_EXPR:
> +      src_range = stack[sp].expr.src_range;
> +      stack[sp].expr.value = c_objc_common_truthvalue_conversion
> +	(stack[sp].loc, default_conversion (stack[sp].expr.value));
> +      set_c_expr_source_range (&stack[sp].expr, src_range);
> +      break;
> +    case TRUTH_ORIF_EXPR:
> +      src_range = stack[sp].expr.src_range;
> +      stack[sp].expr.value = c_objc_common_truthvalue_conversion
> +	(stack[sp].loc, default_conversion (stack[sp].expr.value));
> +      set_c_expr_source_range (&stack[sp].expr, src_range);
> +      break;
> +    default:
> +      break;
> +    }
> +  sp++;
> +  stack[sp].loc = binary_loc;
> +  stack[sp].expr = c_parser_gimple_unary_expression (parser);
> +  stack[sp].op = *subcode;
> +out:
> +  while (sp > 0)
> +    POP;
> +  return stack[0].expr;
> +#undef POP
> +}
> +
> +/* Parse gimple unary expression.
> +
> +   gimple-unary-expression:
> +     gimple-postfix-expression
> +     unary-operator cast-expression
> +
> +   unary-operator: one of
> +     & * + - ~ !
> +*/
> +
> +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.original_code = ERROR_MARK;
> +  ret.original_type = NULL;
> +  switch (c_parser_peek_token (parser)->type)
> +    {
> +    case CPP_AND:
> +      c_parser_consume_token (parser);
> +      op = c_parser_cast_expression (parser, NULL);
> +      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_cast_expression (parser, NULL);
> +	finish = op.get_finish ();
> +	location_t combined_loc = make_location (op_loc, op_loc, finish);
> +	ret.value = build_indirect_ref (combined_loc, op.value,
> +					RO_UNARY_STAR);
> +	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_cast_expression (parser, NULL);
> +      return parser_build_unary_op (op_loc, CONVERT_EXPR, op);
> +    case CPP_MINUS:
> +      c_parser_consume_token (parser);
> +      op = c_parser_cast_expression (parser, NULL);
> +      return parser_build_unary_op (op_loc, NEGATE_EXPR, op);
> +    case CPP_COMPL:
> +      c_parser_consume_token (parser);
> +      op = c_parser_cast_expression (parser, NULL);
> +      return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op);
> +    case CPP_NOT:
> +      c_parser_consume_token (parser);
> +      op = c_parser_cast_expression (parser, NULL);
> +      return parser_build_unary_op (op_loc, TRUTH_NOT_EXPR, op);
> +    case CPP_KEYWORD:
> +      switch (c_parser_peek_token (parser)->keyword)
> +	{
> +	case RID_REALPART:
> +	  c_parser_consume_token (parser);
> +	  op = c_parser_cast_expression (parser, NULL);
> +	  return parser_build_unary_op (op_loc, REALPART_EXPR, op);
> +	case RID_IMAGPART:
> +	  c_parser_consume_token (parser);
> +	  op = c_parser_cast_expression (parser, NULL);
> +	  return parser_build_unary_op (op_loc, IMAGPART_EXPR, op);
> +	default:
> +	  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 not declared"); 
> +	      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)
> +	    {
> +	      c_parser_error (parser, "base variable or SSA name not declared"); 
> +	      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)
> +{
> +  struct c_expr expr;
> +  location_t loc = c_parser_peek_token (parser)->location;
> +  source_range tok_range = c_parser_peek_token (parser)->get_range ();
> +  expr.original_code = ERROR_MARK;
> +  expr.original_type = NULL;
> +  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;
> +	  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);
> +	      /* 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))
> +		    {
> +		      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)
> +{
> +  struct c_expr orig_expr;
> +  vec<tree, va_gc> *exprlist;
> +  vec<tree, va_gc> *origtypes = NULL;
> +  vec<location_t> arg_loc = vNULL;
> +  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 %<]%>"))
> +	      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);
> +	    if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
> +	      exprlist = NULL;
> +	    else
> +	      exprlist = c_parser_gimple_expr_list (parser, &origtypes,
> +						    &arg_loc);
> +	    c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
> +				       "expected %<)%>");
> +	    orig_expr = expr;
> +	    start = expr.get_start ();
> +	    finish = c_parser_tokens_buf (parser, 0)->get_finish ();
> +	    expr.value = c_build_function_call_vec (expr_loc, arg_loc,
> +						    expr.value,
> +						    exprlist, origtypes);
> +	    set_c_expr_source_range (&expr, start, finish);
> +
> +	    expr.original_code = ERROR_MARK;
> +	    if (TREE_CODE (expr.value) == INTEGER_CST
> +		&& TREE_CODE (orig_expr.value) == FUNCTION_DECL
> +		&& DECL_BUILT_IN_CLASS (orig_expr.value) == BUILT_IN_NORMAL
> +		&& DECL_FUNCTION_CODE (orig_expr.value) == BUILT_IN_CONSTANT_P)
> +	      expr.original_code = C_MAYBE_CONST_EXPR;
> +	    expr.original_type = NULL;
> +	    if (exprlist)
> +	      {
> +		release_tree_vector (exprlist);
> +		release_tree_vector (origtypes);
> +	      }
> +	    arg_loc.release ();
> +	    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 vec<tree, va_gc> *
> +c_parser_gimple_expr_list (c_parser *parser, vec<tree, va_gc> **p_orig_types,
> +			   vec<location_t> *locations)
> +{
> +  vec<tree, va_gc> *ret;
> +  vec<tree, va_gc> *orig_types;
> +  struct c_expr expr;
> +  location_t loc = c_parser_peek_token (parser)->location;
> +
> +  ret = make_tree_vector ();
> +  if (p_orig_types == NULL)
> +    orig_types = NULL;
> +  else
> +    orig_types = make_tree_vector ();
> +
> +  expr = c_parser_gimple_unary_expression (parser);
> +  vec_safe_push (ret, expr.value);
> +  if (orig_types)
> +    vec_safe_push (orig_types, expr.original_type);
> +  if (locations)
> +    locations->safe_push (loc);
> +  while (c_parser_next_token_is (parser, CPP_COMMA))
> +    {
> +      c_parser_consume_token (parser);
> +      loc = c_parser_peek_token (parser)->location;
> +      expr = c_parser_gimple_unary_expression (parser);
> +      vec_safe_push (ret, expr.value);
> +      if (orig_types)
> +	vec_safe_push (orig_types, expr.original_type);
> +      if (locations)
> +	locations->safe_push (loc);
> +    }
> +  if (orig_types)
> +    *p_orig_types = orig_types;
> +  return ret;
> +}
> +
> +/* 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 pass list.
> +
> +   gimple-pass-list:
> +     startwith("pass-name")
> + */
> +
> +char *
> +c_parser_gimple_pass_list (c_parser *parser)
> +{
> +  char *pass = NULL;
> +
> +  /* Accept __GIMPLE.  */
> +  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)
> +{
> +  enum tree_code subcode = NOP_EXPR;
> +  location_t loc = c_parser_peek_token (parser)->location;
> +  if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
> +    return error_mark_node;
> +  tree cond = c_parser_gimple_binary_expression (parser, &subcode).value;
> +  cond = c_objc_common_truthvalue_conversion (loc, cond);
> +  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);
> +      label = c_parser_peek_token (parser)->value;
> +      t_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 (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);
> +      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;
> +    }
> +
> +  gimple_seq_add_stmt (seq, gimple_build_cond_from_tree (cond, t_label,
> +							 f_label));
> +}
> +
> +/* Parse gimple switch-statement.
> +
> +   gimple-switch-statement:
> +     switch (gimple-unary-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 %<(%>"))
> +    {
> +      cond_expr = c_parser_gimple_unary_expression (parser);
> +      if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
> +	return;
> +    }
> +
> +  if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
> +    {
> +      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_unary_expression (parser);
> +		else
> +		  c_parser_error (parser, "expected expression");
> +
> +		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;
> +  gimple_seq_add_stmt (seq, gimple_build_switch (cond_expr.value,
> +						 default_label, labels));
> +  gimple_seq_add_seq (seq, switch_body);
> +  labels.release();
> +}
> +
> +/* 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);
> +      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;
> +}
> diff --git a/gcc/c/gimple-parser.h b/gcc/c/gimple-parser.h
> new file mode 100644
> index 0000000..f72b626
> --- /dev/null
> +++ b/gcc/c/gimple-parser.h
> @@ -0,0 +1,27 @@
> +/* Declarations for the parser for GIMPLE.
> +   Copyright (C) 2016 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/>.  */
> +
> +#ifndef GCC_GIMPLE_PARSER_H
> +#define GCC_GIMPLE_PARSER_H
> +
> +/* Gimple parsing functions.  */
> +extern void c_parser_parse_gimple_body (c_parser *);
> +extern char *c_parser_gimple_pass_list (c_parser *);
> +
> +#endif
> diff --git a/gcc/objc/config-lang.in b/gcc/objc/config-lang.in
> index f5a74a7..912af22 100644
> --- a/gcc/objc/config-lang.in
> +++ b/gcc/objc/config-lang.in
> @@ -35,4 +35,4 @@ lang_requires="c"
>  # Order is important.  If you change this list, make sure you test
>  # building without C++ as well; that is, remove the gcc/cp directory,
>  # and build with --enable-languages=c,objc.
> -gtfiles="\$(srcdir)/objc/objc-map.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/objc/objc-act.h \$(srcdir)/objc/objc-act.c \$(srcdir)/objc/objc-runtime-shared-support.c \$(srcdir)/objc/objc-gnu-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-02.c \$(srcdir)/c/c-parser.c \$(srcdir)/c/c-tree.h \$(srcdir)/c/c-decl.c \$(srcdir)/c/c-lang.h \$(srcdir)/c/c-objc-common.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c"
> +gtfiles="\$(srcdir)/objc/objc-map.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/objc/objc-act.h \$(srcdir)/objc/objc-act.c \$(srcdir)/objc/objc-runtime-shared-support.c \$(srcdir)/objc/objc-gnu-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-02.c \$(srcdir)/c/c-parser.h \$(srcdir)/c/c-parser.c \$(srcdir)/c/c-tree.h \$(srcdir)/c/c-decl.c \$(srcdir)/c/c-lang.h \$(srcdir)/c/c-objc-common.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c"
> 
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 5ccd424..e0517b6 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -179,7 +179,7 @@ in the following sections.
>  @xref{C Dialect Options,,Options Controlling C Dialect}.
>  @gccoptlist{-ansi  -std=@var{standard}  -fgnu89-inline @gol
>  -aux-info @var{filename} -fallow-parameterless-variadic-functions @gol
> --fno-asm  -fno-builtin  -fno-builtin-@var{function} @gol
> +-fno-asm  -fno-builtin  -fno-builtin-@var{function} -fgimple@gol
>  -fhosted  -ffreestanding -fopenacc -fopenmp -fopenmp-simd @gol
>  -fms-extensions -fplan9-extensions -fsso-struct=@var{endianness}
>  -fallow-single-precision  -fcond-mismatch -flax-vector-conversions @gol
> @@ -1948,6 +1948,13 @@ built-in functions selectively when using @option{-fno-builtin} or
>  #define strcpy(d, s)    __builtin_strcpy ((d), (s))
>  @end smallexample
>  
> +@item -fgimple
> +@opindex fgimple
> +
> +Enable parsing of function definitions marked with @code{__GIMPLE}.
> +This is an experimental feature that allows unit testing of GIMPLE
> +passes.
> +
>  @item -fhosted
>  @opindex fhosted
>  @cindex hosted environment
>
Jakub Jelinek Nov. 4, 2016, 2:05 p.m. UTC | #2
Hi!

Just 2 nits:

On Fri, Oct 28, 2016 at 01:46:57PM +0200, Richard Biener wrote:
> +/* Return a pointer to the Nth token in PARERs tokens_buf.  */

PARSERs ?

> @@ -454,7 +423,7 @@ c_lex_one_token (c_parser *parser, c_token *token)
>  /* Return a pointer to the next token from PARSER, reading it in if
>     necessary.  */
>  
> -static inline c_token *
> +c_token *
>  c_parser_peek_token (c_parser *parser)
>  {
>    if (parser->tokens_avail == 0)

I wonder if turning all of these into non-inlines is a good idea.
Can't you move them to the common header instead?

The rest I defer to Joseph or Marek.

	Jakub
Richard Biener Nov. 7, 2016, 10:24 a.m. UTC | #3
On Fri, 4 Nov 2016, Jakub Jelinek wrote:

> Hi!
> 
> Just 2 nits:
> 
> On Fri, Oct 28, 2016 at 01:46:57PM +0200, Richard Biener wrote:
> > +/* Return a pointer to the Nth token in PARERs tokens_buf.  */
> 
> PARSERs ?

Fixed.

> > @@ -454,7 +423,7 @@ c_lex_one_token (c_parser *parser, c_token *token)
> >  /* Return a pointer to the next token from PARSER, reading it in if
> >     necessary.  */
> >  
> > -static inline c_token *
> > +c_token *
> >  c_parser_peek_token (c_parser *parser)
> >  {
> >    if (parser->tokens_avail == 0)
> 
> I wonder if turning all of these into non-inlines is a good idea.
> Can't you move them to the common header instead?

The issue with moving is that I failed to export the definition of
c_parser in c-parser.h due to gengtype putting vec <c_token, va_gc>
handlers into gtype-c.h but not gtype-objc.h and thus objc bootstrap
fails :/

I believe (well, I hope) that code generation for the C parser
should be mostly unaffected (inlining is still done as determined
useful) and the performance of the GIMPLE parser shouldn't be
too important.

If anybody feels like digging into the gengtype issue, I gave up
after trying for half a day to trick it to do what I want
(like for example also putting it in gtype-objc.h).

> The rest I defer to Joseph or Marek.

Thanks,
Richard.
Richard Biener Nov. 7, 2016, 10:27 a.m. UTC | #4
On Mon, 7 Nov 2016, Richard Biener wrote:

> On Fri, 4 Nov 2016, Jakub Jelinek wrote:
> 
> > Hi!
> > 
> > Just 2 nits:
> > 
> > On Fri, Oct 28, 2016 at 01:46:57PM +0200, Richard Biener wrote:
> > > +/* Return a pointer to the Nth token in PARERs tokens_buf.  */
> > 
> > PARSERs ?
> 
> Fixed.
> 
> > > @@ -454,7 +423,7 @@ c_lex_one_token (c_parser *parser, c_token *token)
> > >  /* Return a pointer to the next token from PARSER, reading it in if
> > >     necessary.  */
> > >  
> > > -static inline c_token *
> > > +c_token *
> > >  c_parser_peek_token (c_parser *parser)
> > >  {
> > >    if (parser->tokens_avail == 0)
> > 
> > I wonder if turning all of these into non-inlines is a good idea.
> > Can't you move them to the common header instead?
> 
> The issue with moving is that I failed to export the definition of
> c_parser in c-parser.h due to gengtype putting vec <c_token, va_gc>
> handlers into gtype-c.h but not gtype-objc.h and thus objc bootstrap
> fails :/

If anybody wants to try, f82dc04b921a525555a9a5c90d957a824e1c2d04
has it (objc build) still broken on the gimplefe git branch.

> I believe (well, I hope) that code generation for the C parser
> should be mostly unaffected (inlining is still done as determined
> useful) and the performance of the GIMPLE parser shouldn't be
> too important.
> 
> If anybody feels like digging into the gengtype issue, I gave up
> after trying for half a day to trick it to do what I want
> (like for example also putting it in gtype-objc.h).
> 
> > The rest I defer to Joseph or Marek.
> 
> Thanks,
> Richard.
>
Jason Merrill Nov. 9, 2016, 8:39 p.m. UTC | #5
On Mon, Nov 7, 2016 at 2:24 AM, Richard Biener <rguenther@suse.de> wrote:
> The issue with moving is that I failed to export the definition of
> c_parser in c-parser.h due to gengtype putting vec <c_token, va_gc>
> handlers into gtype-c.h but not gtype-objc.h and thus objc bootstrap
> fails :/
>
> I believe (well, I hope) that code generation for the C parser
> should be mostly unaffected (inlining is still done as determined
> useful) and the performance of the GIMPLE parser shouldn't be
> too important.
>
> If anybody feels like digging into the gengtype issue, I gave up
> after trying for half a day to trick it to do what I want
> (like for example also putting it in gtype-objc.h).

I have a fix for that issue waiting for review:

https://gcc.gnu.org/ml/gcc-patches/2016-10/msg02265.html

Jason
Joseph Myers Nov. 10, 2016, 5:38 p.m. UTC | #6
On Fri, 28 Oct 2016, Richard Biener wrote:

> +/* Parse a gimple expression.
> +
> +   gimple-expression:
> +     gimple-unary-expression
> +     gimple-call-statement
> +     gimple-binary-expression
> +     gimple-assign-expression
> +     gimple-cast-expression

I don't see any comments expanding what the syntax is for most of these 
constructs.

> +  if (c_parser_next_token_is (parser, CPP_EQ))
> +    c_parser_consume_token (parser);

That implies you're allowing an optional '=' at this point in the syntax.  
That doesn't seem to make sense to me; I'd expect you to do if (=) { 
process assignment; } else { other cases; } or similar.

> +  /* GIMPLE PHI expression.  */
> +  if (c_parser_next_token_is_keyword (parser, RID_PHI))

I don't see this mentioned in any of the syntax comments.

> +  struct {
> +    /* The expression at this stack level.  */
> +    struct c_expr expr;
> +    /* The operation on its left.  */
> +    enum tree_code op;
> +    /* The source location of this operation.  */
> +    location_t loc;
> +  } stack[2];
> +  int sp;
> +  /* Location of the binary operator.  */
> +  location_t binary_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
> +#define POP								      \

This all looks like excess complexity.  The syntax in the comment 
indicates that in GIMPLE, the operands of a binary expression are unary 
expressions.  So nothing related to precedence is needed at all, and you 
shouldn't need this stack construct.
Richard Biener Nov. 10, 2016, 6:51 p.m. UTC | #7
On November 10, 2016 6:38:12 PM GMT+01:00, Joseph Myers <joseph@codesourcery.com> wrote:
>On Fri, 28 Oct 2016, Richard Biener wrote:
>
>> +/* Parse a gimple expression.
>> +
>> +   gimple-expression:
>> +     gimple-unary-expression
>> +     gimple-call-statement
>> +     gimple-binary-expression
>> +     gimple-assign-expression
>> +     gimple-cast-expression
>
>I don't see any comments expanding what the syntax is for most of these
>
>constructs.
>
>> +  if (c_parser_next_token_is (parser, CPP_EQ))
>> +    c_parser_consume_token (parser);
>
>That implies you're allowing an optional '=' at this point in the
>syntax.  
>That doesn't seem to make sense to me; I'd expect you to do if (=) { 
>process assignment; } else { other cases; } or similar.
>
>> +  /* GIMPLE PHI expression.  */
>> +  if (c_parser_next_token_is_keyword (parser, RID_PHI))
>
>I don't see this mentioned in any of the syntax comments.
>
>> +  struct {
>> +    /* The expression at this stack level.  */
>> +    struct c_expr expr;
>> +    /* The operation on its left.  */
>> +    enum tree_code op;
>> +    /* The source location of this operation.  */
>> +    location_t loc;
>> +  } stack[2];
>> +  int sp;
>> +  /* Location of the binary operator.  */
>> +  location_t binary_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
>> +#define POP								      \
>
>This all looks like excess complexity.  The syntax in the comment 
>indicates that in GIMPLE, the operands of a binary expression are unary
>
>expressions.  So nothing related to precedence is needed at all, and
>you 
>shouldn't need this stack construct.

I'll address those comments.  As you did not have any comments on the c-parser.[CH] parts does that mean you are fine with them?  That is, does the above constitute a complete review of the patch?

Thanks,
Richard.
Joseph Myers Nov. 10, 2016, 9:47 p.m. UTC | #8
On Thu, 10 Nov 2016, Richard Biener wrote:

> I'll address those comments.  As you did not have any comments on the 
> c-parser.[CH] parts does that mean you are fine with them?  That is, 
> does the above constitute a complete review of the patch?

I am fine with the c-parser.[ch] parts.
diff mbox

Patch

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 307862b..2997c83 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -435,6 +435,8 @@  const struct c_common_resword c_common_reswords[] =
   { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
   { "__volatile",	RID_VOLATILE,	0 },
   { "__volatile__",	RID_VOLATILE,	0 },
+  { "__GIMPLE",		RID_GIMPLE,	D_CONLY },
+  { "__PHI",		RID_PHI,	D_CONLY },
   { "alignas",		RID_ALIGNAS,	D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "alignof",		RID_ALIGNOF,	D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "asm",		RID_ASM,	D_ASM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 547bab2..1fbe060 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -118,6 +118,12 @@  enum rid
 
   RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, RID_BUILTIN_CALL_WITH_STATIC_CHAIN,
 
+  /* "__GIMPLE", for the GIMPLE-parsing extension to the C frontend. */
+  RID_GIMPLE,
+
+  /* "__PHI", for parsing PHI function in GIMPLE FE.  */
+  RID_PHI,
+
   /* C11 */
   RID_ALIGNAS, RID_GENERIC,
 
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 458d453..24d3b8e 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -200,6 +200,10 @@  F
 Driver C ObjC C++ ObjC++ Joined Separate MissingArgError(missing path after %qs)
 -F <dir>	Add <dir> to the end of the main framework include path.
 
+fgimple
+C Var(flag_gimple) Init(0)
+Enable parsing GIMPLE.
+
 H
 C ObjC C++ ObjC++
 Print the name of header files as they are used.
diff --git a/gcc/c/Make-lang.in b/gcc/c/Make-lang.in
index 72c9ae7..cd7108b 100644
--- a/gcc/c/Make-lang.in
+++ b/gcc/c/Make-lang.in
@@ -51,7 +51,8 @@  CFLAGS-c/gccspec.o += $(DRIVER_DEFINES)
 # Language-specific object files for C and Objective C.
 C_AND_OBJC_OBJS = attribs.o c/c-errors.o c/c-decl.o c/c-typeck.o \
   c/c-convert.o c/c-aux-info.o c/c-objc-common.o c/c-parser.o \
-  c/c-array-notation.o c/c-fold.o $(C_COMMON_OBJS) $(C_TARGET_OBJS)
+  c/c-array-notation.o c/c-fold.o c/gimple-parser.o \
+  $(C_COMMON_OBJS) $(C_TARGET_OBJS)
 
 # Language-specific object files for C.
 C_OBJS = c/c-lang.o c-family/stub-objc.o $(C_AND_OBJC_OBJS)
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 6bc42da..d21b8e9 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -59,6 +59,8 @@  along with GCC; see the file COPYING3.  If not see
 #include "gimple-expr.h"
 #include "context.h"
 #include "gcc-rich-location.h"
+#include "c-parser.h"
+#include "gimple-parser.h"
 
 /* We need to walk over decls with incomplete struct/union/enum types
    after parsing the whole translation unit.
@@ -150,63 +152,6 @@  c_parse_init (void)
     }
 }
 
-/* The C lexer intermediates between the lexer in cpplib and c-lex.c
-   and the C parser.  Unlike the C++ lexer, the parser structure
-   stores the lexer information instead of using a separate structure.
-   Identifiers are separated into ordinary identifiers, type names,
-   keywords and some other Objective-C types of identifiers, and some
-   look-ahead is maintained.
-
-   ??? It might be a good idea to lex the whole file up front (as for
-   C++).  It would then be possible to share more of the C and C++
-   lexer code, if desired.  */
-
-/* More information about the type of a CPP_NAME token.  */
-enum c_id_kind {
-  /* An ordinary identifier.  */
-  C_ID_ID,
-  /* An identifier declared as a typedef name.  */
-  C_ID_TYPENAME,
-  /* An identifier declared as an Objective-C class name.  */
-  C_ID_CLASSNAME,
-  /* An address space identifier.  */
-  C_ID_ADDRSPACE,
-  /* Not an identifier.  */
-  C_ID_NONE
-};
-
-/* A single C token after string literal concatenation and conversion
-   of preprocessing tokens to tokens.  */
-struct GTY (()) c_token {
-  /* The kind of token.  */
-  ENUM_BITFIELD (cpp_ttype) type : 8;
-  /* If this token is a CPP_NAME, this value indicates whether also
-     declared as some kind of type.  Otherwise, it is C_ID_NONE.  */
-  ENUM_BITFIELD (c_id_kind) id_kind : 8;
-  /* If this token is a keyword, this value indicates which keyword.
-     Otherwise, this value is RID_MAX.  */
-  ENUM_BITFIELD (rid) keyword : 8;
-  /* If this token is a CPP_PRAGMA, this indicates the pragma that
-     was seen.  Otherwise it is PRAGMA_NONE.  */
-  ENUM_BITFIELD (pragma_kind) pragma_kind : 8;
-  /* The location at which this token was found.  */
-  location_t location;
-  /* The value associated with this token, if any.  */
-  tree value;
-  /* Token flags.  */
-  unsigned char flags;
-
-  source_range get_range () const
-  {
-    return get_range_from_loc (line_table, location);
-  }
-
-  location_t get_finish () const
-  {
-    return get_range ().m_finish;
-  }
-};
-
 /* A parser structure recording information about the state and
    context of parsing.  Includes lexer information with up to two
    tokens of look-ahead; more are not needed for C.  */
@@ -259,6 +204,30 @@  struct GTY(()) c_parser {
   vec <c_token, va_gc> *cilk_simd_fn_tokens;
 };
 
+/* Return a pointer to the Nth token in PARERs tokens_buf.  */
+
+c_token *
+c_parser_tokens_buf (c_parser *parser, unsigned n)
+{
+  return &parser->tokens_buf[n];
+}
+
+/* Return the error state of PARSER.  */
+
+bool
+c_parser_error (c_parser *parser)
+{
+  return parser->error;
+}
+
+/* Set the error state of PARSER to ERR.  */
+
+void
+c_parser_set_error (c_parser *parser, bool err)
+{
+  parser->error = err;
+}
+
 
 /* The actual parser and external interface.  ??? Does this need to be
    garbage-collected?  */
@@ -454,7 +423,7 @@  c_lex_one_token (c_parser *parser, c_token *token)
 /* Return a pointer to the next token from PARSER, reading it in if
    necessary.  */
 
-static inline c_token *
+c_token *
 c_parser_peek_token (c_parser *parser)
 {
   if (parser->tokens_avail == 0)
@@ -465,37 +434,10 @@  c_parser_peek_token (c_parser *parser)
   return &parser->tokens[0];
 }
 
-/* Return true if the next token from PARSER has the indicated
-   TYPE.  */
-
-static inline bool
-c_parser_next_token_is (c_parser *parser, enum cpp_ttype type)
-{
-  return c_parser_peek_token (parser)->type == type;
-}
-
-/* Return true if the next token from PARSER does not have the
-   indicated TYPE.  */
-
-static inline bool
-c_parser_next_token_is_not (c_parser *parser, enum cpp_ttype type)
-{
-  return !c_parser_next_token_is (parser, type);
-}
-
-/* Return true if the next token from PARSER is the indicated
-   KEYWORD.  */
-
-static inline bool
-c_parser_next_token_is_keyword (c_parser *parser, enum rid keyword)
-{
-  return c_parser_peek_token (parser)->keyword == keyword;
-}
-
 /* Return a pointer to the next-but-one token from PARSER, reading it
    in if necessary.  The next token is already read in.  */
 
-static c_token *
+c_token *
 c_parser_peek_2nd_token (c_parser *parser)
 {
   if (parser->tokens_avail >= 2)
@@ -511,7 +453,7 @@  c_parser_peek_2nd_token (c_parser *parser)
 /* Return a pointer to the Nth token from PARSER, reading it
    in if necessary.  The N-1th token is already read in.  */
 
-static c_token *
+c_token *
 c_parser_peek_nth_token (c_parser *parser, unsigned int n)
 {
   /* N is 1-based, not zero-based.  */
@@ -570,7 +512,7 @@  c_keyword_starts_typename (enum rid keyword)
 
 /* Return true if TOKEN can start a type name,
    false otherwise.  */
-static bool
+bool
 c_token_starts_typename (c_token *token)
 {
   switch (token->type)
@@ -601,18 +543,6 @@  c_token_starts_typename (c_token *token)
     }
 }
 
-enum c_lookahead_kind {
-  /* Always treat unknown identifiers as typenames.  */
-  cla_prefer_type,
-
-  /* Could be parsing a nonabstract declarator.  Only treat an identifier
-     as a typename if followed by another identifier or a star.  */
-  cla_nonabstract_decl,
-
-  /* Never treat identifiers as typenames.  */
-  cla_prefer_id
-};
-
 /* Return true if the next token from PARSER can start a type name,
    false otherwise.  LA specifies how to do lookahead in order to
    detect unknown type names.  If unsure, pick CLA_PREFER_ID.  */
@@ -779,7 +709,7 @@  c_token_starts_declaration (c_token *token)
 
 /* Return true if the next token from PARSER can start declaration
    specifiers, false otherwise.  */
-static inline bool
+bool
 c_parser_next_token_starts_declspecs (c_parser *parser)
 {
   c_token *token = c_parser_peek_token (parser);
@@ -801,7 +731,7 @@  c_parser_next_token_starts_declspecs (c_parser *parser)
 
 /* Return true if the next tokens from PARSER can start declaration
    specifiers or a static assertion, false otherwise.  */
-static inline bool
+bool
 c_parser_next_tokens_start_declaration (c_parser *parser)
 {
   c_token *token = c_parser_peek_token (parser);
@@ -829,7 +759,7 @@  c_parser_next_tokens_start_declaration (c_parser *parser)
 
 /* Consume the next token from PARSER.  */
 
-static void
+void
 c_parser_consume_token (c_parser *parser)
 {
   gcc_assert (parser->tokens_avail >= 1);
@@ -922,7 +852,7 @@  c_parser_peek_conflict_marker (c_parser *parser, enum cpp_ttype tok1_kind,
    this way is not i18n-friendly and some other approach should be
    used.  */
 
-static void
+void
 c_parser_error (c_parser *parser, const char *gmsgid)
 {
   c_token *token = c_parser_peek_token (parser);
@@ -965,7 +895,7 @@  c_parser_error (c_parser *parser, const char *gmsgid)
    been produced and no message will be produced this time.  Returns
    true if found, false otherwise.  */
 
-static bool
+bool
 c_parser_require (c_parser *parser,
 		  enum cpp_ttype type,
 		  const char *msgid)
@@ -1008,7 +938,7 @@  c_parser_require_keyword (c_parser *parser,
    already been produced and no message will be produced this
    time.  */
 
-static void
+void
 c_parser_skip_until_found (c_parser *parser,
 			   enum cpp_ttype type,
 			   const char *msgid)
@@ -1243,42 +1173,6 @@  restore_extension_diagnostics (int flags)
   warn_c99_c11_compat = (flags >> 9) & 1 ? 1 : ((flags >> 10) & 1 ? -1 : 0);
 }
 
-/* Possibly kinds of declarator to parse.  */
-enum c_dtr_syn {
-  /* A normal declarator with an identifier.  */
-  C_DTR_NORMAL,
-  /* An abstract declarator (maybe empty).  */
-  C_DTR_ABSTRACT,
-  /* A parameter declarator: may be either, but after a type name does
-     not redeclare a typedef name as an identifier if it can
-     alternatively be interpreted as a typedef name; see DR#009,
-     applied in C90 TC1, omitted from C99 and reapplied in C99 TC2
-     following DR#249.  For example, given a typedef T, "int T" and
-     "int *T" are valid parameter declarations redeclaring T, while
-     "int (T)" and "int * (T)" and "int (T[])" and "int (T (int))" are
-     abstract declarators rather than involving redundant parentheses;
-     the same applies with attributes inside the parentheses before
-     "T".  */
-  C_DTR_PARM
-};
-
-/* The binary operation precedence levels, where 0 is a dummy lowest level
-   used for the bottom of the stack.  */
-enum c_parser_prec {
-  PREC_NONE,
-  PREC_LOGOR,
-  PREC_LOGAND,
-  PREC_BITOR,
-  PREC_BITXOR,
-  PREC_BITAND,
-  PREC_EQ,
-  PREC_REL,
-  PREC_SHIFT,
-  PREC_ADD,
-  PREC_MULT,
-  NUM_PRECS
-};
-
 /* Helper data structure for parsing #pragma acc routine.  */
 struct oacc_routine_data {
   bool error_seen; /* Set if error has been reported.  */
@@ -1295,15 +1189,11 @@  static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
 					   bool * = NULL);
 static void c_parser_static_assert_declaration_no_semi (c_parser *);
 static void c_parser_static_assert_declaration (c_parser *);
-static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
-				bool, bool, bool, enum c_lookahead_kind);
 static struct c_typespec c_parser_enum_specifier (c_parser *);
 static struct c_typespec c_parser_struct_or_union_specifier (c_parser *);
 static tree c_parser_struct_declaration (c_parser *);
 static struct c_typespec c_parser_typeof_specifier (c_parser *);
 static tree c_parser_alignas_specifier (c_parser *);
-static struct c_declarator *c_parser_declarator (c_parser *, bool, c_dtr_syn,
-						 bool *);
 static struct c_declarator *c_parser_direct_declarator (c_parser *, bool,
 							c_dtr_syn, bool *);
 static struct c_declarator *c_parser_direct_declarator_inner (c_parser *,
@@ -1343,7 +1233,6 @@  static struct c_expr c_parser_conditional_expression (c_parser *,
 						      struct c_expr *, tree);
 static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
 						 tree);
-static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
 static struct c_expr c_parser_unary_expression (c_parser *);
 static struct c_expr c_parser_sizeof_expression (c_parser *);
 static struct c_expr c_parser_alignof_expression (c_parser *);
@@ -1652,7 +1541,13 @@  static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
    OpenMP:
 
    declaration:
-     threadprivate-directive  */
+     threadprivate-directive
+
+   GIMPLE:
+
+   gimple-function-definition:
+     declaration-specifiers[opt] __GIMPLE (gimple-pass-list) declarator
+       declaration-list[opt] compound-statement  */
 
 static void
 c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
@@ -1752,6 +1647,7 @@  c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       c_parser_skip_to_end_of_block_or_statement (parser);
       return;
     }
+
   finish_declspecs (specs);
   bool auto_type_p = specs->typespec_word == cts_auto_type;
   if (c_parser_next_token_is (parser, CPP_SEMICOLON))
@@ -1882,7 +1778,7 @@  c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       struct c_declarator *declarator;
       bool dummy = false;
       timevar_id_t tv;
-      tree fnbody;
+      tree fnbody = NULL_TREE;
       /* Declaring either one or more declarators (in which case we
 	 should diagnose if there were no declaration specifiers) or a
 	 function definition (in which case the diagnostic for
@@ -2173,9 +2069,24 @@  c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 	c_finish_oacc_routine (oacc_routine_data, current_function_decl, true);
       DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
 	= c_parser_peek_token (parser)->location;
-      fnbody = c_parser_compound_statement (parser);
-      if (flag_cilkplus && contains_array_notation_expr (fnbody))
-	fnbody = expand_array_notation_exprs (fnbody);
+
+      /* If the definition was marked with __GIMPLE then parse the
+         function body as GIMPLE.  */
+      if (specs->gimple_p)
+	{
+	  cfun->pass_startwith = specs->gimple_pass;
+	  bool saved = in_late_binary_op;
+	  in_late_binary_op = true;
+	  c_parser_parse_gimple_body (parser);
+	  in_late_binary_op = saved;
+	}
+      else
+	{
+	  fnbody = c_parser_compound_statement (parser);
+	  if (flag_cilkplus && contains_array_notation_expr (fnbody))
+	    fnbody = expand_array_notation_exprs (fnbody);
+	}
+      tree fndecl = current_function_decl;
       if (nested)
 	{
 	  tree decl = current_function_decl;
@@ -2191,9 +2102,13 @@  c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 	}
       else
 	{
-	  add_stmt (fnbody);
+	  if (fnbody)
+	    add_stmt (fnbody);
 	  finish_function ();
 	}
+      /* Get rid of the empty stmt list for GIMPLE.  */
+      if (specs->gimple_p)
+	DECL_SAVED_TREE (fndecl) = NULL_TREE;
 
       timevar_pop (tv);
       break;
@@ -2416,7 +2331,7 @@  c_parser_static_assert_declaration_no_semi (c_parser *parser)
      objc-protocol-refs
 */
 
-static void
+void
 c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 		    bool scspec_ok, bool typespec_ok, bool start_attr_ok,
 		    bool alignspec_ok, bool auto_type_ok,
@@ -2681,6 +2596,14 @@  c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 	  align = c_parser_alignas_specifier (parser);
 	  declspecs_add_alignas (loc, specs, align);
 	  break;
+	case RID_GIMPLE:
+	  if (! flag_gimple)
+	    error_at (loc, "%<__GIMPLE%> only valid with -fgimple");
+	  c_parser_consume_token (parser);
+	  specs->gimple_p = true;
+	  specs->locations[cdw_gimple] = loc;
+	  specs->gimple_pass = c_parser_gimple_pass_list (parser);
+	  break;
 	default:
 	  goto out;
 	}
@@ -3415,7 +3338,7 @@  c_parser_alignas_specifier (c_parser * parser)
    This function also accepts an omitted abstract declarator as being
    an abstract declarator, although not part of the formal syntax.  */
 
-static struct c_declarator *
+struct c_declarator *
 c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
 		     bool *seen_id)
 {
@@ -6866,7 +6789,7 @@  c_parser_binary_expression (c_parser *parser, struct c_expr *after,
      ( type-name ) unary-expression
 */
 
-static struct c_expr
+struct c_expr
 c_parser_cast_expression (c_parser *parser, struct c_expr *after)
 {
   location_t cast_loc = c_parser_peek_token (parser)->location;
diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h
new file mode 100644
index 0000000..04fa681
--- /dev/null
+++ b/gcc/c/c-parser.h
@@ -0,0 +1,189 @@ 
+/* Declarations for the parser for C and Objective-C.
+   Copyright (C) 1987-2016 Free Software Foundation, Inc.
+
+   Parser actions based on the old Bison parser; structure somewhat
+   influenced by and fragments based on the C++ parser.
+
+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/>.  */
+
+#ifndef GCC_C_PARSER_H
+#define GCC_C_PARSER_H
+
+/* The C lexer intermediates between the lexer in cpplib and c-lex.c
+   and the C parser.  Unlike the C++ lexer, the parser structure
+   stores the lexer information instead of using a separate structure.
+   Identifiers are separated into ordinary identifiers, type names,
+   keywords and some other Objective-C types of identifiers, and some
+   look-ahead is maintained.
+
+   ??? It might be a good idea to lex the whole file up front (as for
+   C++).  It would then be possible to share more of the C and C++
+   lexer code, if desired.  */
+
+/* More information about the type of a CPP_NAME token.  */
+enum c_id_kind {
+  /* An ordinary identifier.  */
+  C_ID_ID,
+  /* An identifier declared as a typedef name.  */
+  C_ID_TYPENAME,
+  /* An identifier declared as an Objective-C class name.  */
+  C_ID_CLASSNAME,
+  /* An address space identifier.  */
+  C_ID_ADDRSPACE,
+  /* Not an identifier.  */
+  C_ID_NONE
+};
+
+/* A single C token after string literal concatenation and conversion
+   of preprocessing tokens to tokens.  */
+struct GTY (()) c_token {
+  /* The kind of token.  */
+  ENUM_BITFIELD (cpp_ttype) type : 8;
+  /* If this token is a CPP_NAME, this value indicates whether also
+     declared as some kind of type.  Otherwise, it is C_ID_NONE.  */
+  ENUM_BITFIELD (c_id_kind) id_kind : 8;
+  /* If this token is a keyword, this value indicates which keyword.
+     Otherwise, this value is RID_MAX.  */
+  ENUM_BITFIELD (rid) keyword : 8;
+  /* If this token is a CPP_PRAGMA, this indicates the pragma that
+     was seen.  Otherwise it is PRAGMA_NONE.  */
+  ENUM_BITFIELD (pragma_kind) pragma_kind : 8;
+  /* The location at which this token was found.  */
+  location_t location;
+  /* The value associated with this token, if any.  */
+  tree value;
+  /* Token flags.  */
+  unsigned char flags;
+
+  source_range get_range () const
+  {
+    return get_range_from_loc (line_table, location);
+  }
+
+  location_t get_finish () const
+  {
+    return get_range ().m_finish;
+  }
+};
+
+/* The parser.  */
+struct c_parser;
+
+/* Possibly kinds of declarator to parse.  */
+enum c_dtr_syn {
+  /* A normal declarator with an identifier.  */
+  C_DTR_NORMAL,
+  /* An abstract declarator (maybe empty).  */
+  C_DTR_ABSTRACT,
+  /* A parameter declarator: may be either, but after a type name does
+     not redeclare a typedef name as an identifier if it can
+     alternatively be interpreted as a typedef name; see DR#009,
+     applied in C90 TC1, omitted from C99 and reapplied in C99 TC2
+     following DR#249.  For example, given a typedef T, "int T" and
+     "int *T" are valid parameter declarations redeclaring T, while
+     "int (T)" and "int * (T)" and "int (T[])" and "int (T (int))" are
+     abstract declarators rather than involving redundant parentheses;
+     the same applies with attributes inside the parentheses before
+     "T".  */
+  C_DTR_PARM
+};
+
+/* The binary operation precedence levels, where 0 is a dummy lowest level
+   used for the bottom of the stack.  */
+enum c_parser_prec {
+  PREC_NONE,
+  PREC_LOGOR,
+  PREC_LOGAND,
+  PREC_BITOR,
+  PREC_BITXOR,
+  PREC_BITAND,
+  PREC_EQ,
+  PREC_REL,
+  PREC_SHIFT,
+  PREC_ADD,
+  PREC_MULT,
+  NUM_PRECS
+};
+
+enum c_lookahead_kind {
+  /* Always treat unknown identifiers as typenames.  */
+  cla_prefer_type,
+
+  /* Could be parsing a nonabstract declarator.  Only treat an identifier
+     as a typename if followed by another identifier or a star.  */
+  cla_nonabstract_decl,
+
+  /* Never treat identifiers as typenames.  */
+  cla_prefer_id
+};
+
+
+extern c_token * c_parser_peek_token (c_parser *parser);
+extern c_token * c_parser_peek_2nd_token (c_parser *parser);
+extern c_token * c_parser_peek_nth_token (c_parser *parser, unsigned int n);
+extern bool c_parser_require (c_parser *parser, enum cpp_ttype type,
+			      const char *msgid);
+extern void c_parser_error (c_parser *parser, const char *gmsgid);
+extern void c_parser_consume_token (c_parser *parser);
+extern void c_parser_skip_until_found (c_parser *parser, enum cpp_ttype type,
+				       const char *msgid);
+extern bool c_parser_next_token_starts_declspecs (c_parser *parser);
+bool c_parser_next_tokens_start_declaration (c_parser *parser);
+bool c_token_starts_typename (c_token *token);
+
+/* Abstraction to avoid defining c_parser here which messes up gengtype
+   output wrt ObjC due to vec<c_token> routines being put in gtype-c.h
+   but not gtype-objc.h.  */
+extern c_token * c_parser_tokens_buf (c_parser *parser, unsigned n);
+extern bool c_parser_error (c_parser *parser);
+extern void c_parser_set_error (c_parser *parser, bool);
+
+/* Return true if the next token from PARSER has the indicated
+   TYPE.  */
+
+static inline bool
+c_parser_next_token_is (c_parser *parser, enum cpp_ttype type)
+{
+  return c_parser_peek_token (parser)->type == type;
+}
+
+/* Return true if the next token from PARSER does not have the
+   indicated TYPE.  */
+
+static inline bool
+c_parser_next_token_is_not (c_parser *parser, enum cpp_ttype type)
+{
+  return !c_parser_next_token_is (parser, type);
+}
+
+/* Return true if the next token from PARSER is the indicated
+   KEYWORD.  */
+
+static inline bool
+c_parser_next_token_is_keyword (c_parser *parser, enum rid keyword)
+{
+  return c_parser_peek_token (parser)->keyword == keyword;
+}
+
+extern struct c_declarator *
+c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
+		     bool *seen_id);
+extern void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
+				bool, bool, bool, enum c_lookahead_kind);
+extern struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
+
+#endif
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index e8060f8..a8cf353 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -267,6 +267,7 @@  enum c_declspec_word {
   cdw_saturating,
   cdw_alignas,
   cdw_address_space,
+  cdw_gimple,
   cdw_number_of_elements /* This one must always be the last
 			    enumerator.  */
 };
@@ -290,6 +291,8 @@  struct c_declspecs {
      NULL; attributes (possibly from multiple lists) will be passed
      separately.  */
   tree attrs;
+  /* The pass to start compiling a __GIMPLE function with.  */
+  char *gimple_pass;
   /* The base-2 log of the greatest alignment required by an _Alignas
      specifier, in bytes, or -1 if no such specifiers with nonzero
      alignment.  */
@@ -362,6 +365,8 @@  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;
   /* The address space that the declaration belongs to.  */
   addr_space_t address_space;
 };
diff --git a/gcc/c/config-lang.in b/gcc/c/config-lang.in
index b9cdc8e..51fbb53 100644
--- a/gcc/c/config-lang.in
+++ b/gcc/c/config-lang.in
@@ -29,4 +29,4 @@  compilers="cc1\$(exeext)"
 
 target_libs=
 
-gtfiles="\$(srcdir)/c/c-lang.c \$(srcdir)/c/c-tree.h \$(srcdir)/c/c-decl.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/c/c-objc-common.c \$(srcdir)/c/c-parser.c \$(srcdir)/c/c-lang.h"
+gtfiles="\$(srcdir)/c/c-lang.c \$(srcdir)/c/c-tree.h \$(srcdir)/c/c-decl.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/c/c-objc-common.c \$(srcdir)/c/c-parser.h \$(srcdir)/c/c-parser.c \$(srcdir)/c/c-lang.h"
diff --git a/gcc/c/gimple-parser.c b/gcc/c/gimple-parser.c
new file mode 100644
index 0000000..7f8d948
--- /dev/null
+++ b/gcc/c/gimple-parser.c
@@ -0,0 +1,1483 @@ 
+/* Parser for GIMPLE.
+   Copyright (C) 2016 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 "omp-low.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"
+#include "tree-dump.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_expression (c_parser *, gimple_seq *);
+static struct c_expr c_parser_gimple_binary_expression (c_parser *, enum tree_code *);
+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 vec<tree, va_gc> *c_parser_gimple_expr_list (c_parser *,
+		    vec<tree, va_gc> **, vec<location_t> *);
+
+
+/* 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_generic, 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;
+
+	default:
+expr_stmt:
+	  c_parser_gimple_expression (parser, seq);
+	  if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+	    return return_p;
+	}
+    }
+  c_parser_consume_token (parser);
+  return return_p;
+}
+
+/* Parse a gimple expression.
+
+   gimple-expression:
+     gimple-unary-expression
+     gimple-call-statement
+     gimple-binary-expression
+     gimple-assign-expression
+     gimple-cast-expression
+
+*/
+
+static void
+c_parser_gimple_expression (c_parser *parser, gimple_seq *seq)
+{
+  struct c_expr lhs, rhs;
+  gimple *assign = NULL;
+  enum tree_code subcode = NOP_EXPR;
+  location_t loc;
+  tree arg = NULL_TREE;
+  auto_vec<tree> vargs;
+
+  lhs = c_parser_gimple_unary_expression (parser);
+  rhs.value = error_mark_node;
+
+  if (c_parser_next_token_is (parser, CPP_EQ))
+    c_parser_consume_token (parser);
+
+  loc = EXPR_LOCATION (lhs.value);
+
+  /* GIMPLE call expression.  */
+  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);
+      gimple_seq_add_stmt (seq, call);
+      gimple_set_location (call, loc);
+      return;
+    }
+
+  /* Cast expression.  */
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+      && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+    {
+      /* TODO: have a gimple_cast_expr function.  */
+      rhs = c_parser_cast_expression (parser, NULL);
+      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;
+	}
+    }
+
+  /* Pointer expression.  */
+  if (TREE_CODE (lhs.value) == INDIRECT_REF)
+    {
+      tree save_expr = lhs.value;
+      bool volatilep = TREE_THIS_VOLATILE (lhs.value);
+      bool notrap = TREE_THIS_NOTRAP (lhs.value);
+      tree saved_ptr_type = TREE_TYPE (TREE_OPERAND (lhs.value, 0));
+
+      lhs.value = fold_indirect_ref_loc (loc, lhs.value);
+      if (lhs.value == save_expr)
+	{
+	  lhs.value = fold_build2_loc (input_location, MEM_REF,
+				       TREE_TYPE (lhs.value),
+				       TREE_OPERAND (lhs.value, 0),
+				       build_int_cst (saved_ptr_type, 0));
+	  TREE_THIS_VOLATILE (lhs.value) = volatilep;
+	  TREE_THIS_NOTRAP (lhs.value) = notrap;
+	}
+    }
+
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_AND:
+    case CPP_PLUS:
+    case CPP_MINUS:
+    case CPP_COMPL:
+    case CPP_NOT:
+    case CPP_MULT: /* pointer deref */
+      rhs = c_parser_gimple_unary_expression (parser);
+      assign = gimple_build_assign (lhs.value, rhs.value);
+      gimple_set_location (assign, loc);
+      gimple_seq_add_stmt (seq, assign);
+      return;
+
+    default:;
+    }
+
+  /* GIMPLE PHI expression.  */
+  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);
+      gimple *call = gimple_build_call_from_tree (rhs.value);
+      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, &subcode);
+
+  if (lhs.value != error_mark_node
+      && rhs.value != error_mark_node)
+    {
+      if (subcode == NOP_EXPR)
+	assign = gimple_build_assign (lhs.value, rhs.value);
+      else
+	assign = gimple_build_assign (lhs.value, subcode,
+				      TREE_OPERAND (rhs.value, 0),
+				      TREE_OPERAND (rhs.value, 1));
+      gimple_seq_add_stmt (seq, assign);
+      gimple_set_location (assign, loc);
+    }
+  return;
+}
+
+/* Parse gimple binary expr.
+
+   gimple-multiplicative-expression:
+     gimple-unary-expression * gimple-unary-expression
+     gimple-unary-expression / gimple-unary-expression
+     gimple-unary-expression % gimple-unary-expression
+
+   gimple-additive-expression:
+     gimple-unary-expression + gimple-unary-expression
+     gimple-unary-expression - gimple-unary-expression
+
+   gimple-shift-expression:
+     gimple-unary-expression << gimple-unary-expression
+     gimple-unary-expression >> gimple-unary-expression
+
+   gimple-relational-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-equality-expression:
+     gimple-unary-expression == gimple-unary-expression
+     gimple-unary-expression != gimple-unary-expression
+
+   gimple-AND-expression:
+     gimple-unary-expression & gimple-unary-expression
+
+   gimple-exclusive-OR-expression:
+     gimple-unary-expression ^ gimple-unary-expression
+
+   gimple-inclusive-OR-expression:
+     gimple-unary-expression | gimple-unary-expression
+
+   gimple-logical-AND-expression:
+     gimple-unary-expression && gimple-unary-expression
+
+   gimple-logical-OR-expression:
+     gimple-unary-expression || gimple-unary-expression
+
+*/
+
+static c_expr
+c_parser_gimple_binary_expression (c_parser *parser, enum tree_code *subcode)
+{
+  struct {
+    /* The expression at this stack level.  */
+    struct c_expr expr;
+    /* The operation on its left.  */
+    enum tree_code op;
+    /* The source location of this operation.  */
+    location_t loc;
+  } stack[2];
+  int sp;
+  /* Location of the binary operator.  */
+  location_t binary_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
+#define POP								      \
+  do {									      \
+    if (sp == 1								      \
+	&& c_parser_peek_token (parser)->type == CPP_SEMICOLON		      \
+	&& (((1 << PREC_BITOR) | (1 << PREC_BITXOR) | (1 << PREC_BITAND)      \
+	       | (1 << PREC_SHIFT) | (1 << PREC_ADD) | (1 << PREC_MULT)))     \
+	&& stack[sp].op != TRUNC_MOD_EXPR				      \
+	&& stack[0].expr.value != error_mark_node			      \
+	&& stack[1].expr.value != error_mark_node)			      \
+      stack[0].expr.value						      \
+	= build2 (stack[1].op, TREE_TYPE (stack[0].expr.value),		      \
+		  stack[0].expr.value, stack[1].expr.value);		      \
+    else								      \
+      stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc,	      \
+						   stack[sp].op,	      \
+						   stack[sp - 1].expr,	      \
+						   stack[sp].expr);	      \
+    sp--;								      \
+  } while (0)
+  stack[0].loc = c_parser_peek_token (parser)->location;
+  stack[0].expr = c_parser_gimple_unary_expression (parser);
+  sp = 0;
+  source_range src_range;
+  if (c_parser_error (parser))
+    goto out;
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_MULT:
+      *subcode = MULT_EXPR;
+      break;
+    case CPP_DIV:
+      *subcode = TRUNC_DIV_EXPR;
+      break;
+    case CPP_MOD:
+      *subcode = TRUNC_MOD_EXPR;
+      break;
+    case CPP_PLUS:
+      *subcode = PLUS_EXPR;
+      break;
+    case CPP_MINUS:
+      *subcode = MINUS_EXPR;
+      break;
+    case CPP_LSHIFT:
+      *subcode = LSHIFT_EXPR;
+      break;
+    case CPP_RSHIFT:
+      *subcode = RSHIFT_EXPR;
+      break;
+    case CPP_LESS:
+      *subcode = LT_EXPR;
+      break;
+    case CPP_GREATER:
+      *subcode = GT_EXPR;
+      break;
+    case CPP_LESS_EQ:
+      *subcode = LE_EXPR;
+      break;
+    case CPP_GREATER_EQ:
+      *subcode = GE_EXPR;
+      break;
+    case CPP_EQ_EQ:
+      *subcode = EQ_EXPR;
+      break;
+    case CPP_NOT_EQ:
+      *subcode = NE_EXPR;
+      break;
+    case CPP_AND:
+      *subcode = BIT_AND_EXPR;
+      break;
+    case CPP_XOR:
+      *subcode = BIT_XOR_EXPR;
+      break;
+    case CPP_OR:
+      *subcode = BIT_IOR_EXPR;
+      break;
+    case CPP_AND_AND:
+      *subcode = TRUTH_ANDIF_EXPR;
+      break;
+    case CPP_OR_OR:
+      *subcode = TRUTH_ORIF_EXPR;
+      break;
+    default:
+      /* Not a binary operator, so end of the binary expression.  */
+      *subcode = NOP_EXPR;
+      goto out;
+    }
+  binary_loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_token (parser);
+  switch (*subcode)
+    {
+    case TRUTH_ANDIF_EXPR:
+      src_range = stack[sp].expr.src_range;
+      stack[sp].expr.value = c_objc_common_truthvalue_conversion
+	(stack[sp].loc, default_conversion (stack[sp].expr.value));
+      set_c_expr_source_range (&stack[sp].expr, src_range);
+      break;
+    case TRUTH_ORIF_EXPR:
+      src_range = stack[sp].expr.src_range;
+      stack[sp].expr.value = c_objc_common_truthvalue_conversion
+	(stack[sp].loc, default_conversion (stack[sp].expr.value));
+      set_c_expr_source_range (&stack[sp].expr, src_range);
+      break;
+    default:
+      break;
+    }
+  sp++;
+  stack[sp].loc = binary_loc;
+  stack[sp].expr = c_parser_gimple_unary_expression (parser);
+  stack[sp].op = *subcode;
+out:
+  while (sp > 0)
+    POP;
+  return stack[0].expr;
+#undef POP
+}
+
+/* Parse gimple unary expression.
+
+   gimple-unary-expression:
+     gimple-postfix-expression
+     unary-operator cast-expression
+
+   unary-operator: one of
+     & * + - ~ !
+*/
+
+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.original_code = ERROR_MARK;
+  ret.original_type = NULL;
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_AND:
+      c_parser_consume_token (parser);
+      op = c_parser_cast_expression (parser, NULL);
+      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_cast_expression (parser, NULL);
+	finish = op.get_finish ();
+	location_t combined_loc = make_location (op_loc, op_loc, finish);
+	ret.value = build_indirect_ref (combined_loc, op.value,
+					RO_UNARY_STAR);
+	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_cast_expression (parser, NULL);
+      return parser_build_unary_op (op_loc, CONVERT_EXPR, op);
+    case CPP_MINUS:
+      c_parser_consume_token (parser);
+      op = c_parser_cast_expression (parser, NULL);
+      return parser_build_unary_op (op_loc, NEGATE_EXPR, op);
+    case CPP_COMPL:
+      c_parser_consume_token (parser);
+      op = c_parser_cast_expression (parser, NULL);
+      return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op);
+    case CPP_NOT:
+      c_parser_consume_token (parser);
+      op = c_parser_cast_expression (parser, NULL);
+      return parser_build_unary_op (op_loc, TRUTH_NOT_EXPR, op);
+    case CPP_KEYWORD:
+      switch (c_parser_peek_token (parser)->keyword)
+	{
+	case RID_REALPART:
+	  c_parser_consume_token (parser);
+	  op = c_parser_cast_expression (parser, NULL);
+	  return parser_build_unary_op (op_loc, REALPART_EXPR, op);
+	case RID_IMAGPART:
+	  c_parser_consume_token (parser);
+	  op = c_parser_cast_expression (parser, NULL);
+	  return parser_build_unary_op (op_loc, IMAGPART_EXPR, op);
+	default:
+	  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 not declared"); 
+	      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)
+	    {
+	      c_parser_error (parser, "base variable or SSA name not declared"); 
+	      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)
+{
+  struct c_expr expr;
+  location_t loc = c_parser_peek_token (parser)->location;
+  source_range tok_range = c_parser_peek_token (parser)->get_range ();
+  expr.original_code = ERROR_MARK;
+  expr.original_type = NULL;
+  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;
+	  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);
+	      /* 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))
+		    {
+		      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)
+{
+  struct c_expr orig_expr;
+  vec<tree, va_gc> *exprlist;
+  vec<tree, va_gc> *origtypes = NULL;
+  vec<location_t> arg_loc = vNULL;
+  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 %<]%>"))
+	      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);
+	    if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+	      exprlist = NULL;
+	    else
+	      exprlist = c_parser_gimple_expr_list (parser, &origtypes,
+						    &arg_loc);
+	    c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+				       "expected %<)%>");
+	    orig_expr = expr;
+	    start = expr.get_start ();
+	    finish = c_parser_tokens_buf (parser, 0)->get_finish ();
+	    expr.value = c_build_function_call_vec (expr_loc, arg_loc,
+						    expr.value,
+						    exprlist, origtypes);
+	    set_c_expr_source_range (&expr, start, finish);
+
+	    expr.original_code = ERROR_MARK;
+	    if (TREE_CODE (expr.value) == INTEGER_CST
+		&& TREE_CODE (orig_expr.value) == FUNCTION_DECL
+		&& DECL_BUILT_IN_CLASS (orig_expr.value) == BUILT_IN_NORMAL
+		&& DECL_FUNCTION_CODE (orig_expr.value) == BUILT_IN_CONSTANT_P)
+	      expr.original_code = C_MAYBE_CONST_EXPR;
+	    expr.original_type = NULL;
+	    if (exprlist)
+	      {
+		release_tree_vector (exprlist);
+		release_tree_vector (origtypes);
+	      }
+	    arg_loc.release ();
+	    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 vec<tree, va_gc> *
+c_parser_gimple_expr_list (c_parser *parser, vec<tree, va_gc> **p_orig_types,
+			   vec<location_t> *locations)
+{
+  vec<tree, va_gc> *ret;
+  vec<tree, va_gc> *orig_types;
+  struct c_expr expr;
+  location_t loc = c_parser_peek_token (parser)->location;
+
+  ret = make_tree_vector ();
+  if (p_orig_types == NULL)
+    orig_types = NULL;
+  else
+    orig_types = make_tree_vector ();
+
+  expr = c_parser_gimple_unary_expression (parser);
+  vec_safe_push (ret, expr.value);
+  if (orig_types)
+    vec_safe_push (orig_types, expr.original_type);
+  if (locations)
+    locations->safe_push (loc);
+  while (c_parser_next_token_is (parser, CPP_COMMA))
+    {
+      c_parser_consume_token (parser);
+      loc = c_parser_peek_token (parser)->location;
+      expr = c_parser_gimple_unary_expression (parser);
+      vec_safe_push (ret, expr.value);
+      if (orig_types)
+	vec_safe_push (orig_types, expr.original_type);
+      if (locations)
+	locations->safe_push (loc);
+    }
+  if (orig_types)
+    *p_orig_types = orig_types;
+  return ret;
+}
+
+/* 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 pass list.
+
+   gimple-pass-list:
+     startwith("pass-name")
+ */
+
+char *
+c_parser_gimple_pass_list (c_parser *parser)
+{
+  char *pass = NULL;
+
+  /* Accept __GIMPLE.  */
+  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)
+{
+  enum tree_code subcode = NOP_EXPR;
+  location_t loc = c_parser_peek_token (parser)->location;
+  if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return error_mark_node;
+  tree cond = c_parser_gimple_binary_expression (parser, &subcode).value;
+  cond = c_objc_common_truthvalue_conversion (loc, cond);
+  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);
+      label = c_parser_peek_token (parser)->value;
+      t_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 (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);
+      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;
+    }
+
+  gimple_seq_add_stmt (seq, gimple_build_cond_from_tree (cond, t_label,
+							 f_label));
+}
+
+/* Parse gimple switch-statement.
+
+   gimple-switch-statement:
+     switch (gimple-unary-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 %<(%>"))
+    {
+      cond_expr = c_parser_gimple_unary_expression (parser);
+      if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+	return;
+    }
+
+  if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+    {
+      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_unary_expression (parser);
+		else
+		  c_parser_error (parser, "expected expression");
+
+		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;
+  gimple_seq_add_stmt (seq, gimple_build_switch (cond_expr.value,
+						 default_label, labels));
+  gimple_seq_add_seq (seq, switch_body);
+  labels.release();
+}
+
+/* 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);
+      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;
+}
diff --git a/gcc/c/gimple-parser.h b/gcc/c/gimple-parser.h
new file mode 100644
index 0000000..f72b626
--- /dev/null
+++ b/gcc/c/gimple-parser.h
@@ -0,0 +1,27 @@ 
+/* Declarations for the parser for GIMPLE.
+   Copyright (C) 2016 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/>.  */
+
+#ifndef GCC_GIMPLE_PARSER_H
+#define GCC_GIMPLE_PARSER_H
+
+/* Gimple parsing functions.  */
+extern void c_parser_parse_gimple_body (c_parser *);
+extern char *c_parser_gimple_pass_list (c_parser *);
+
+#endif
diff --git a/gcc/objc/config-lang.in b/gcc/objc/config-lang.in
index f5a74a7..912af22 100644
--- a/gcc/objc/config-lang.in
+++ b/gcc/objc/config-lang.in
@@ -35,4 +35,4 @@  lang_requires="c"
 # Order is important.  If you change this list, make sure you test
 # building without C++ as well; that is, remove the gcc/cp directory,
 # and build with --enable-languages=c,objc.
-gtfiles="\$(srcdir)/objc/objc-map.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/objc/objc-act.h \$(srcdir)/objc/objc-act.c \$(srcdir)/objc/objc-runtime-shared-support.c \$(srcdir)/objc/objc-gnu-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-02.c \$(srcdir)/c/c-parser.c \$(srcdir)/c/c-tree.h \$(srcdir)/c/c-decl.c \$(srcdir)/c/c-lang.h \$(srcdir)/c/c-objc-common.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c"
+gtfiles="\$(srcdir)/objc/objc-map.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/objc/objc-act.h \$(srcdir)/objc/objc-act.c \$(srcdir)/objc/objc-runtime-shared-support.c \$(srcdir)/objc/objc-gnu-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-02.c \$(srcdir)/c/c-parser.h \$(srcdir)/c/c-parser.c \$(srcdir)/c/c-tree.h \$(srcdir)/c/c-decl.c \$(srcdir)/c/c-lang.h \$(srcdir)/c/c-objc-common.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c"

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5ccd424..e0517b6 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -179,7 +179,7 @@  in the following sections.
 @xref{C Dialect Options,,Options Controlling C Dialect}.
 @gccoptlist{-ansi  -std=@var{standard}  -fgnu89-inline @gol
 -aux-info @var{filename} -fallow-parameterless-variadic-functions @gol
--fno-asm  -fno-builtin  -fno-builtin-@var{function} @gol
+-fno-asm  -fno-builtin  -fno-builtin-@var{function} -fgimple@gol
 -fhosted  -ffreestanding -fopenacc -fopenmp -fopenmp-simd @gol
 -fms-extensions -fplan9-extensions -fsso-struct=@var{endianness}
 -fallow-single-precision  -fcond-mismatch -flax-vector-conversions @gol
@@ -1948,6 +1948,13 @@  built-in functions selectively when using @option{-fno-builtin} or
 #define strcpy(d, s)    __builtin_strcpy ((d), (s))
 @end smallexample
 
+@item -fgimple
+@opindex fgimple
+
+Enable parsing of function definitions marked with @code{__GIMPLE}.
+This is an experimental feature that allows unit testing of GIMPLE
+passes.
+
 @item -fhosted
 @opindex fhosted
 @cindex hosted environment