diff options
author | Prasad Ghangal <prasad.ghangal@gmail.com> | 2016-11-14 14:13:32 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2016-11-14 14:13:32 +0000 |
commit | bc08ecba2b3530944a9fd03acc90aa7cd5289bd1 (patch) | |
tree | 0c6654faae2b87c8a413b38b923795a69b96beb6 /gcc/c | |
parent | 1ee62b926411dda2bffbca8019b494481183ee15 (diff) | |
download | gcc-bc08ecba2b3530944a9fd03acc90aa7cd5289bd1.zip gcc-bc08ecba2b3530944a9fd03acc90aa7cd5289bd1.tar.gz gcc-bc08ecba2b3530944a9fd03acc90aa7cd5289bd1.tar.bz2 |
Make-lang.in (C_AND_OBJC_OBJS): Add gimple-parser.o.
2016-11-14 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_type_name): 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_type_name): 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.
* dumpfile.h (TDF_GIMPLE): Add.
* dumpfile.c (dump_options): Add gimple.
* gimple-pretty-print.c (dump_gimple_switch): Adjust dump
for TDF_GIMPLE.
(dump_gimple_label): Likewise.
(dump_gimple_phi): Likewise.
(dump_gimple_bb_header): Likewise.
(dump_phi_nodes): Likewise.
(pp_cfg_jump): Likewise. Pass in dump flags.
(dump_implicit_edges): Adjust.
* passes.c (pass_init_dump_file): Do not dump function header
for TDF_GIMPLE.
* tree-cfg.c (dump_function_to_file): Dump function return type
and __GIMPLE keyword for TDF_GIMPLE. Change guard for dumping
GIMPLE stmts.
* tree-pretty-print.c (dump_decl_name): Adjust dump for TDF_GIMPLE.
(dump_generic_node): Likewise.
* function.h (struct function): Add pass_startwith member.
* passes.c (execute_one_pass): Implement startwith.
* tree-ssanames.c (make_ssa_name_fn): New argument, check for version
and assign proper version for parsed ssa names.
* tree-ssanames.h (make_ssa_name_fn): Add new argument to the function.
* internal-fn.c (expand_PHI): New function.
* internal-fn.h (expand_PHI): Declared here.
* internal-fn.def: New defination for PHI.
* tree-cfg.c (lower_phi_internal_fn): New function.
(build_gimple_cfg): Call it.
(verify_gimple_call): Condition for passing label as arg in internal
function PHI.
* tree-into-ssa.c (rewrite_add_phi_arguments): Handle already
present PHIs with arguments.
testsuite/
* gcc.dg/gimplefe-1.c: New testcase.
* gcc.dg/gimplefe-2.c: Likewise.
* gcc.dg/gimplefe-3.c: Likewise.
* gcc.dg/gimplefe-4.c: Likewise.
* gcc.dg/gimplefe-5.c: Likewise.
* gcc.dg/gimplefe-6.c: Likewise.
* gcc.dg/gimplefe-7.c: Likewise.
* gcc.dg/gimplefe-8.c: Likewise.
* gcc.dg/gimplefe-9.c: Likewise.
* gcc.dg/gimplefe-10.c: Likewise.
* gcc.dg/gimplefe-11.c: Likewise.
* gcc.dg/gimplefe-12.c: Likewise.
* gcc.dg/gimplefe-13.c: Likewise.
* gcc.dg/gimplefe-14.c: Likewise.
* gcc.dg/gimplefe-15.c: Likewise.
* gcc.dg/gimplefe-16.c: Likewise.
* gcc.dg/gimplefe-17.c: Likewise.
* gcc.dg/gimplefe-18.c: Likewise.
From-SVN: r242388
Diffstat (limited to 'gcc/c')
-rw-r--r-- | gcc/c/c-parser.h | 189 | ||||
-rw-r--r-- | gcc/c/gimple-parser.c | 1435 | ||||
-rw-r--r-- | gcc/c/gimple-parser.h | 27 |
3 files changed, 1651 insertions, 0 deletions
diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h new file mode 100644 index 0000000..ff8aceb --- /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_type_name *c_parser_type_name (c_parser *); + +#endif diff --git a/gcc/c/gimple-parser.c b/gcc/c/gimple-parser.c new file mode 100644 index 0000000..9b6af13 --- /dev/null +++ b/gcc/c/gimple-parser.c @@ -0,0 +1,1435 @@ +/* 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_statement (c_parser *, gimple_seq *); +static struct c_expr c_parser_gimple_binary_expression (c_parser *); +static struct c_expr c_parser_gimple_unary_expression (c_parser *); +static struct c_expr c_parser_gimple_postfix_expression (c_parser *); +static struct c_expr c_parser_gimple_postfix_expression_after_primary (c_parser *, + location_t, + struct c_expr); +static void c_parser_gimple_declaration (c_parser *); +static void c_parser_gimple_goto_stmt (location_t, tree, gimple_seq *); +static void c_parser_gimple_if_stmt (c_parser *, gimple_seq *); +static void c_parser_gimple_switch_stmt (c_parser *, gimple_seq *); +static void c_parser_gimple_return_stmt (c_parser *, gimple_seq *); +static void c_finish_gimple_return (location_t, tree); +static tree c_parser_gimple_paren_condition (c_parser *); +static 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_statement (parser, seq); + if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) + return return_p; + } + } + c_parser_consume_token (parser); + return return_p; +} + +/* Parse a gimple statement. + + gimple-statement: + gimple-call-expression + gimple-assign-statement + gimple-phi-statement + + gimple-assign-statement: + gimple-unary-expression = gimple-assign-rhs + + gimple-assign-rhs: + gimple-cast-expression + gimple-unary-expression + gimple-binary-expression + gimple-call-expression + + gimple-phi-statement: + identifier = __PHI ( label : gimple_primary-expression, ... ) + + gimple-call-expr: + gimple-primary-expression ( argument-list ) + + gimple-cast-expression: + ( type-name ) gimple-primary-expression + +*/ + +static void +c_parser_gimple_statement (c_parser *parser, gimple_seq *seq) +{ + struct c_expr lhs, rhs; + gimple *assign = NULL; + location_t loc; + tree arg = NULL_TREE; + auto_vec<tree> vargs; + + lhs = c_parser_gimple_unary_expression (parser); + loc = EXPR_LOCATION (lhs.value); + rhs.value = error_mark_node; + + /* GIMPLE call statement without LHS. */ + if (c_parser_next_token_is (parser, CPP_SEMICOLON) + && TREE_CODE (lhs.value) == CALL_EXPR) + { + gimple *call; + call = gimple_build_call_from_tree (lhs.value); + gimple_seq_add_stmt (seq, call); + gimple_set_location (call, loc); + return; + } + + /* All following cases are statements with LHS. */ + if (! c_parser_require (parser, CPP_EQ, "expected %<=%>")) + return; + + /* Cast expression. */ + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) + && c_token_starts_typename (c_parser_peek_2nd_token (parser))) + { + c_parser_consume_token (parser); + struct c_type_name *type_name = c_parser_type_name (parser); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + if (type_name == NULL) + return; + /* ??? The actual type used in the cast expression is ignored as + in GIMPLE it is encoded by the type of the LHS. */ + rhs = c_parser_gimple_postfix_expression (parser); + if (lhs.value != error_mark_node + && rhs.value != error_mark_node) + { + enum tree_code code = NOP_EXPR; + if (VECTOR_TYPE_P (TREE_TYPE (lhs.value))) + { + code = VIEW_CONVERT_EXPR; + rhs.value = build1 (VIEW_CONVERT_EXPR, + TREE_TYPE (lhs.value), rhs.value); + } + else if (FLOAT_TYPE_P (TREE_TYPE (lhs.value)) + && ! FLOAT_TYPE_P (TREE_TYPE (rhs.value))) + code = FLOAT_EXPR; + else if (! FLOAT_TYPE_P (TREE_TYPE (lhs.value)) + && FLOAT_TYPE_P (TREE_TYPE (rhs.value))) + code = FIX_TRUNC_EXPR; + assign = gimple_build_assign (lhs.value, code, rhs.value); + gimple_seq_add_stmt (seq, assign); + gimple_set_location (assign, loc); + return; + } + } + + /* Unary expression. */ + switch (c_parser_peek_token (parser)->type) + { + case CPP_KEYWORD: + if (c_parser_peek_token (parser)->keyword != RID_REALPART + && c_parser_peek_token (parser)->keyword != RID_IMAGPART) + break; + /* Fallthru. */ + case CPP_AND: + case CPP_PLUS: + case CPP_MINUS: + case CPP_COMPL: + case CPP_NOT: + case CPP_MULT: /* pointer deref */ + 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 statement. */ + if (c_parser_next_token_is_keyword (parser, RID_PHI)) + { + c_parser_consume_token (parser); + + if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return; + + if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + c_parser_consume_token (parser); + + while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)) + { + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + arg = lookup_label_for_goto (loc, + c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + + if (c_parser_next_token_is (parser, CPP_COLON)) + c_parser_consume_token (parser); + vargs.safe_push (arg); + } + else if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + else + { + arg = c_parser_gimple_unary_expression (parser).value; + vargs.safe_push (arg); + } + } + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + + /* Build internal function for PHI. */ + gcall *call_stmt = gimple_build_call_internal_vec (IFN_PHI, vargs); + gimple_call_set_lhs (call_stmt, lhs.value); + gimple_set_location (call_stmt, UNKNOWN_LOCATION); + gimple_seq_add_stmt (seq, call_stmt); + return; + } + + /* GIMPLE call with lhs. */ + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN + && lookup_name (c_parser_peek_token (parser)->value)) + { + rhs = c_parser_gimple_unary_expression (parser); + 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); + if (lhs.value != error_mark_node + && rhs.value != error_mark_node) + { + assign = gimple_build_assign (lhs.value, rhs.value); + gimple_seq_add_stmt (seq, assign); + gimple_set_location (assign, loc); + } + return; +} + +/* Parse gimple binary expr. + + gimple-binary-expression: + gimple-unary-expression * gimple-unary-expression + gimple-unary-expression / gimple-unary-expression + gimple-unary-expression % gimple-unary-expression + gimple-unary-expression + gimple-unary-expression + gimple-unary-expression - gimple-unary-expression + gimple-unary-expression << gimple-unary-expression + gimple-unary-expression >> gimple-unary-expression + gimple-unary-expression < gimple-unary-expression + gimple-unary-expression > gimple-unary-expression + gimple-unary-expression <= gimple-unary-expression + gimple-unary-expression >= gimple-unary-expression + gimple-unary-expression == gimple-unary-expression + gimple-unary-expression != gimple-unary-expression + gimple-unary-expression & gimple-unary-expression + gimple-unary-expression ^ gimple-unary-expression + gimple-unary-expression | gimple-unary-expression + +*/ + +static c_expr +c_parser_gimple_binary_expression (c_parser *parser) +{ + /* Location of the binary operator. */ + struct c_expr ret, lhs, rhs; + enum tree_code code = ERROR_MARK; + ret.value = error_mark_node; + lhs = c_parser_gimple_postfix_expression (parser); + if (c_parser_error (parser)) + return ret; + tree ret_type = TREE_TYPE (lhs.value); + switch (c_parser_peek_token (parser)->type) + { + case CPP_MULT: + code = MULT_EXPR; + break; + case CPP_DIV: + code = TRUNC_DIV_EXPR; + break; + case CPP_MOD: + code = TRUNC_MOD_EXPR; + break; + case CPP_PLUS: + if (POINTER_TYPE_P (TREE_TYPE (lhs.value))) + code = POINTER_PLUS_EXPR; + else + code = PLUS_EXPR; + break; + case CPP_MINUS: + code = MINUS_EXPR; + break; + case CPP_LSHIFT: + code = LSHIFT_EXPR; + break; + case CPP_RSHIFT: + code = RSHIFT_EXPR; + break; + case CPP_LESS: + code = LT_EXPR; + ret_type = boolean_type_node; + break; + case CPP_GREATER: + code = GT_EXPR; + ret_type = boolean_type_node; + break; + case CPP_LESS_EQ: + code = LE_EXPR; + ret_type = boolean_type_node; + break; + case CPP_GREATER_EQ: + code = GE_EXPR; + ret_type = boolean_type_node; + break; + case CPP_EQ_EQ: + code = EQ_EXPR; + ret_type = boolean_type_node; + break; + case CPP_NOT_EQ: + code = NE_EXPR; + ret_type = boolean_type_node; + break; + case CPP_AND: + code = BIT_AND_EXPR; + break; + case CPP_XOR: + code = BIT_XOR_EXPR; + break; + case CPP_OR: + code = BIT_IOR_EXPR; + break; + case CPP_AND_AND: + c_parser_error (parser, "%<&&%> not valid in GIMPLE"); + return ret; + case CPP_OR_OR: + c_parser_error (parser, "%<||%> not valid in GIMPLE"); + return ret; + default: + /* Not a binary expression. */ + return lhs; + } + location_t ret_loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + rhs = c_parser_gimple_postfix_expression (parser); + if (c_parser_error (parser)) + return ret; + ret.value = build2_loc (ret_loc, code, ret_type, lhs.value, rhs.value); + return ret; +} + +/* Parse gimple unary expression. + + gimple-unary-expression: + gimple-postfix-expression + unary-operator gimple-postfix-expression + + unary-operator: one of + & * + - ~ +*/ + +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; + ret.value = error_mark_node; + switch (c_parser_peek_token (parser)->type) + { + case CPP_AND: + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + mark_exp_read (op.value); + return parser_build_unary_op (op_loc, ADDR_EXPR, op); + case CPP_MULT: + { + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + finish = op.get_finish (); + location_t combined_loc = make_location (op_loc, op_loc, finish); + ret.value = build_simple_mem_ref_loc (combined_loc, op.value); + TREE_SIDE_EFFECTS (ret.value) + = TREE_THIS_VOLATILE (ret.value) + = TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (op.value))); + ret.src_range.m_start = op_loc; + ret.src_range.m_finish = finish; + return ret; + } + case CPP_PLUS: + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + return parser_build_unary_op (op_loc, CONVERT_EXPR, op); + case CPP_MINUS: + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + return parser_build_unary_op (op_loc, NEGATE_EXPR, op); + case CPP_COMPL: + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op); + case CPP_NOT: + c_parser_error (parser, "%<!%> not valid in GIMPLE"); + return ret; + case CPP_KEYWORD: + switch (c_parser_peek_token (parser)->keyword) + { + case RID_REALPART: + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + return parser_build_unary_op (op_loc, REALPART_EXPR, op); + case RID_IMAGPART: + c_parser_consume_token (parser); + op = c_parser_gimple_postfix_expression (parser); + return parser_build_unary_op (op_loc, IMAGPART_EXPR, op); + default: + return c_parser_gimple_postfix_expression (parser); + } + 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) +{ + if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return error_mark_node; + tree cond = c_parser_gimple_binary_expression (parser).value; + if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return error_mark_node; + return cond; +} + +/* Parse gimple if-else statement. + + if-statement: + if ( gimple-binary-expression ) gimple-goto-statement + if ( gimple-binary-expression ) gimple-goto-statement \ + else gimple-goto-statement + */ + +static void +c_parser_gimple_if_stmt (c_parser *parser, gimple_seq *seq) +{ + tree t_label, f_label, label; + location_t loc; + c_parser_consume_token (parser); + tree cond = c_parser_gimple_paren_condition (parser); + + if (c_parser_next_token_is_keyword (parser, RID_GOTO)) + { + loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + 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-postfix-expression) gimple-case-statement + + gimple-case-statement: + gimple-case-statement + gimple-label-statement : gimple-goto-statment +*/ + +static void +c_parser_gimple_switch_stmt (c_parser *parser, gimple_seq *seq) +{ + c_expr cond_expr; + tree case_label, label; + auto_vec<tree> labels; + tree default_label = NULL_TREE; + gimple_seq switch_body = NULL; + c_parser_consume_token (parser); + + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + cond_expr = c_parser_gimple_postfix_expression (parser); + if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return; + } + + if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>")) + { + while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE)) + { + if (c_parser_next_token_is (parser, CPP_EOF)) + { + c_parser_error (parser, "expected statement"); + return; + } + + switch (c_parser_peek_token (parser)->keyword) + { + case RID_CASE: + { + c_expr exp1; + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_token (parser); + + if (c_parser_next_token_is (parser, CPP_NAME) + || c_parser_peek_token (parser)->type == CPP_NUMBER) + exp1 = c_parser_gimple_postfix_expression (parser); + else + c_parser_error (parser, "expected expression"); + + 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 |