/* Parser for GIMPLE.
Copyright (C) 2016-2020 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
. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "target.h"
#include "function.h"
#include "c-tree.h"
#include "timevar.h"
#include "stringpool.h"
#include "cgraph.h"
#include "attribs.h"
#include "stor-layout.h"
#include "varasm.h"
#include "trans-mem.h"
#include "c-family/c-pragma.h"
#include "c-lang.h"
#include "c-family/c-objc.h"
#include "plugin.h"
#include "builtins.h"
#include "gomp-constants.h"
#include "c-family/c-indentation.h"
#include "gimple-expr.h"
#include "context.h"
#include "gcc-rich-location.h"
#include "c-parser.h"
#include "tree-vrp.h"
#include "tree-pass.h"
#include "tree-pretty-print.h"
#include "tree.h"
#include "basic-block.h"
#include "gimple.h"
#include "gimple-pretty-print.h"
#include "tree-ssa.h"
#include "pass_manager.h"
#include "tree-ssanames.h"
#include "gimple-ssa.h"
#include "tree-dfa.h"
#include "internal-fn.h"
#include "cfg.h"
#include "cfghooks.h"
#include "cfganal.h"
#include "tree-cfg.h"
#include "gimple-iterator.h"
#include "cfgloop.h"
#include "tree-phinodes.h"
#include "tree-into-ssa.h"
#include "bitmap.h"
/* GIMPLE parser state. */
class gimple_parser
{
public:
gimple_parser (c_parser *p) : parser (p), edges(), current_bb(NULL) {}
/* c_parser is not visible here, use composition and fake inheritance
via a conversion operator. */
operator c_parser *() { return parser; }
c_parser *parser;
/* CFG build state. */
class gimple_parser_edge
{
public:
int src;
int dest;
int flags;
profile_probability probability;
};
auto_vec edges;
basic_block current_bb;
void push_edge (int, int, int, profile_probability);
};
void
gimple_parser::push_edge (int src, int dest, int flags,
profile_probability prob)
{
gimple_parser_edge e;
e.src = src;
e.dest = dest;
e.flags = flags;
e.probability = prob;
edges.safe_push (e);
}
/* Gimple parsing functions. */
static bool c_parser_gimple_compound_statement (gimple_parser &, gimple_seq *);
static void c_parser_gimple_label (gimple_parser &, gimple_seq *);
static void c_parser_gimple_statement (gimple_parser &, gimple_seq *);
static struct c_expr c_parser_gimple_binary_expression (gimple_parser &);
static struct c_expr c_parser_gimple_unary_expression (gimple_parser &);
static struct c_expr c_parser_gimple_postfix_expression (gimple_parser &);
static struct c_expr c_parser_gimple_postfix_expression_after_primary
(gimple_parser &, location_t, struct c_expr);
static void c_parser_gimple_declaration (gimple_parser &);
static void c_parser_gimple_goto_stmt (gimple_parser &, location_t,
tree, gimple_seq *);
static void c_parser_gimple_try_stmt (gimple_parser &, gimple_seq *);
static void c_parser_gimple_if_stmt (gimple_parser &, gimple_seq *);
static void c_parser_gimple_switch_stmt (gimple_parser &, gimple_seq *);
static void c_parser_gimple_return_stmt (gimple_parser &, gimple_seq *);
static void c_finish_gimple_return (location_t, tree);
static tree c_parser_gimple_paren_condition (gimple_parser &);
static void c_parser_gimple_expr_list (gimple_parser &, vec *);
/* See if VAL is an identifier matching __BB and return
in *INDEX. */
static bool
c_parser_gimple_parse_bb_spec (tree val, int *index)
{
if (strncmp (IDENTIFIER_POINTER (val), "__BB", 4) != 0)
return false;
for (const char *p = IDENTIFIER_POINTER (val) + 4; *p; ++p)
if (!ISDIGIT (*p))
return false;
*index = atoi (IDENTIFIER_POINTER (val) + 4);
return *index > 0;
}
/* See if VAL is an identifier matching __BB and return
in *INDEX. Return true if so and parse also FREQUENCY of
the edge. */
static bool
c_parser_gimple_parse_bb_spec_edge_probability (tree val,
gimple_parser &parser,
int *index,
profile_probability
*probability)
{
bool return_p = c_parser_gimple_parse_bb_spec (val, index);
if (return_p)
{
*probability = profile_probability::uninitialized ();
/* Parse frequency if provided. */
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
{
tree f;
c_parser_consume_token (parser);
if (!c_parser_next_token_is (parser, CPP_NAME))
{
c_parser_error (parser, "expected frequency quality");
return false;
}
profile_quality quality;
const char *v
= IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
if (!parse_profile_quality (v, &quality))
{
c_parser_error (parser, "unknown profile quality");
return false;
}
c_parser_consume_token (parser);
if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
return false;
if (!c_parser_next_token_is (parser, CPP_NUMBER)
|| (TREE_CODE (f = c_parser_peek_token (parser)->value)
!= INTEGER_CST))
{
c_parser_error (parser, "expected frequency value");
return false;
}
unsigned int value = TREE_INT_CST_LOW (f);
*probability = profile_probability (value, quality);
c_parser_consume_token (parser);
if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
return false;
if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
return false;
}
return true;
}
return false;
}
/* Parse the body of a function declaration marked with "__GIMPLE". */
void
c_parser_parse_gimple_body (c_parser *cparser, char *gimple_pass,
enum c_declspec_il cdil,
profile_count entry_bb_count)
{
gimple_parser parser (cparser);
gimple_seq seq = NULL;
gimple_seq body = NULL;
tree stmt = push_stmt_list ();
push_scope ();
location_t loc1 = c_parser_peek_token (parser)->location;
cfun->pass_startwith = gimple_pass;
init_tree_ssa (cfun);
if (cdil == cdil_gimple)
/* While we have SSA names in the IL we do not have a CFG built yet
and PHIs are represented using a PHI internal function. We do
have lowered control flow and exception handling (well, we do not
have parser support for EH yet). But as we still have BINDs
we have to go through lowering again. */
cfun->curr_properties = PROP_gimple_any;
else
{
/* We have at least cdil_gimple_cfg. */
gimple_register_cfg_hooks ();
init_empty_tree_cfg ();
parser.current_bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
/* Initialize the bare loop structure - we are going to only
mark headers and leave the rest to fixup. */
set_loops_for_fn (cfun, ggc_cleared_alloc ());
init_loops_structure (cfun, loops_for_fn (cfun), 1);
loops_state_set (cfun, LOOPS_NEED_FIXUP|LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
cfun->curr_properties
|= PROP_gimple_lcf | PROP_gimple_leh | PROP_cfg | PROP_loops;
if (cdil == cdil_gimple_ssa)
{
init_ssa_operands (cfun);
cfun->curr_properties |= PROP_ssa;
}
}
if (! c_parser_gimple_compound_statement (parser, &seq)
&& cdil == cdil_gimple)
{
gimple *ret = gimple_build_return (NULL);
gimple_seq_add_stmt_without_update (&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;
if (cdil == cdil_gimple)
{
gbind *bind_stmt = gimple_build_bind (BIND_EXPR_VARS (stmt), NULL,
BIND_EXPR_BLOCK (stmt));
gimple_bind_set_body (bind_stmt, seq);
gimple_seq_add_stmt_without_update (&body, bind_stmt);
gimple_set_body (current_function_decl, body);
}
else
{
/* Control-flow and binds are lowered, record local decls. */
for (tree var = BIND_EXPR_VARS (stmt); var; var = DECL_CHAIN (var))
if (VAR_P (var)
&& !DECL_EXTERNAL (var))
add_local_decl (cfun, var);
/* We have a CFG. Build the edges. */
for (unsigned i = 0; i < parser.edges.length (); ++i)
{
edge e = make_edge (BASIC_BLOCK_FOR_FN (cfun, parser.edges[i].src),
BASIC_BLOCK_FOR_FN (cfun, parser.edges[i].dest),
parser.edges[i].flags);
e->probability = parser.edges[i].probability;
}
/* Add edges for case labels. */
basic_block bb;
FOR_EACH_BB_FN (bb, cfun)
if (EDGE_COUNT (bb->succs) == 0)
{
gimple *last = last_stmt (bb);
if (gswitch *sw = safe_dyn_cast (last))
for (unsigned i = 0; i < gimple_switch_num_labels (sw); ++i)
{
basic_block label_bb = gimple_switch_label_bb (cfun, sw, i);
make_edge (bb, label_bb, 0);
}
}
/* Need those for loop fixup. */
calculate_dominance_info (CDI_DOMINATORS);
/* With SSA lower PHIs parsed as internal function calls and
update stmts. */
if (cdil == cdil_gimple_ssa)
{
/* Create PHI nodes, they are parsed into __PHI internal calls. */
FOR_EACH_BB_FN (bb, cfun)
for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
!gsi_end_p (gsi);)
{
gimple *stmt = gsi_stmt (gsi);
if (!gimple_call_internal_p (stmt, IFN_PHI))
break;
gphi *phi = create_phi_node (gimple_call_lhs (stmt), bb);
for (unsigned i = 0; i < gimple_call_num_args (stmt); i += 2)
{
int srcidx = TREE_INT_CST_LOW (gimple_call_arg (stmt, i));
edge e = find_edge (BASIC_BLOCK_FOR_FN (cfun, srcidx), bb);
if (!e)
c_parser_error (parser, "edge not found");
else
add_phi_arg (phi, gimple_call_arg (stmt, i + 1), e,
UNKNOWN_LOCATION);
}
gsi_remove (&gsi, true);
}
/* Fill SSA name gaps, putting them on the freelist. */
for (unsigned i = 1; i < num_ssa_names; ++i)
if (!ssa_name (i))
{
tree name = make_ssa_name_fn (cfun, integer_type_node, NULL, i);
release_ssa_name_fn (cfun, name);
}
/* No explicit virtual operands (yet). */
bitmap_obstack_initialize (NULL);
update_ssa (TODO_update_ssa_only_virtuals);
bitmap_obstack_release (NULL);
/* ??? By flushing the freelist after virtual operand SSA rewrite
we keep the gaps available for re-use like needed for the
PR89595 testcase but then usually virtual operands would have
taken most of them. The fix is obviously to make virtual
operands explicit in the SSA IL. */
flush_ssaname_freelist ();
}
fix_loop_structure (NULL);
}
if (cfun->curr_properties & PROP_cfg)
{
ENTRY_BLOCK_PTR_FOR_FN (cfun)->count = entry_bb_count;
gcov_type t = param_gimple_fe_computed_hot_bb_threshold;
set_hot_bb_threshold (t);
update_max_bb_count ();
cgraph_node::get_create (cfun->decl);
cgraph_edge::rebuild_edges ();
}
dump_function (TDI_gimple, current_function_decl);
}
/* Parse a compound statement in gimple function body.
gimple-statement:
gimple-statement
gimple-declaration-statement
gimple-if-statement
gimple-switch-statement
gimple-labeled-statement
gimple-expression-statement
gimple-goto-statement
gimple-phi-statement
gimple-return-statement
*/
static bool
c_parser_gimple_compound_statement (gimple_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_AT_TRY:
c_parser_gimple_try_stmt (parser, seq);
break;
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))
{
tree label = c_parser_peek_token (parser)->value;
c_parser_consume_token (parser);
c_parser_gimple_goto_stmt (parser, loc, label, seq);
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;
if (cfun->curr_properties & PROP_cfg)
parser.push_edge (parser.current_bb->index, EXIT_BLOCK, 0,
profile_probability::uninitialized ());
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;
}
if (c_parser_next_token_is (parser, CPP_NAME)
&& c_parser_peek_token (parser)->id_kind == C_ID_ID
&& strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value),
"try") == 0)
{
c_parser_gimple_try_stmt (parser, seq);
break;
}
/* Basic block specification.
__BB (index, ...) */
if ((cfun->curr_properties & PROP_cfg)
&& !strcmp (IDENTIFIER_POINTER
(c_parser_peek_token (parser)->value), "__BB"))
{
c_parser_consume_token (parser);
if (! c_parser_require (parser, CPP_OPEN_PAREN,
"expected %<(%>"))
return return_p;
if (c_parser_next_token_is_not (parser, CPP_NUMBER))
{
c_parser_error (parser, "expected block index");
return return_p;
}
tree tnum = c_parser_peek_token (parser)->value;
if (TREE_CODE (tnum) != INTEGER_CST)
{
c_parser_error (parser, "expected block index");
return return_p;
}
int index = TREE_INT_CST_LOW (tnum);
if (index < NUM_FIXED_BLOCKS
|| (index < last_basic_block_for_fn (cfun)
&& BASIC_BLOCK_FOR_FN (cfun, index) != NULL))
{
c_parser_error (parser, "invalid block index");
return return_p;
}
int is_loop_header_of = -1;
profile_count bb_count = profile_count::uninitialized ();
c_parser_consume_token (parser);
while (c_parser_next_token_is (parser, CPP_COMMA))
{
c_parser_consume_token (parser);
if (! c_parser_next_token_is (parser, CPP_NAME))
{
c_parser_error (parser, "expected block specifier");
return return_p;
}
/* loop_header (NUM) */
if (!strcmp (IDENTIFIER_POINTER
(c_parser_peek_token (parser)->value),
"loop_header"))
{
c_parser_consume_token (parser);
if (! c_parser_require (parser, CPP_OPEN_PAREN,
"expected %<(%>"))
return return_p;
tree loop_num;
if (! c_parser_next_token_is (parser, CPP_NUMBER)
|| TREE_CODE (loop_num
= c_parser_peek_token (parser)->value)
!= INTEGER_CST)
{
c_parser_error (parser, "expected loop number");
return return_p;
}
c_parser_consume_token (parser);
is_loop_header_of = TREE_INT_CST_LOW (loop_num);
if (! c_parser_require (parser, CPP_CLOSE_PAREN,
"expected %<)%>"))
return return_p;
}
/* Parse profile: quality(value) */
else
{
tree q;
profile_quality quality;
tree v = c_parser_peek_token (parser)->value;
if (!parse_profile_quality (IDENTIFIER_POINTER (v),
&quality))
{
c_parser_error (parser, "unknown block specifier");
return false;
}
c_parser_consume_token (parser);
if (!c_parser_require (parser, CPP_OPEN_PAREN,
"expected %<(%>"))
return false;
if (!c_parser_next_token_is (parser, CPP_NUMBER)
|| (TREE_CODE (q = c_parser_peek_token (parser)->value)
!= INTEGER_CST))
{
c_parser_error (parser, "expected count value");
return false;
}
bb_count
= profile_count::from_gcov_type (TREE_INT_CST_LOW (q),
quality);
c_parser_consume_token (parser);
if (! c_parser_require (parser, CPP_CLOSE_PAREN,
"expected %<)%>"))
return return_p;
}
}
if (! c_parser_require (parser, CPP_CLOSE_PAREN,
"expected %<)%>")
|| ! c_parser_require (parser, CPP_COLON,
"expected %<:%>"))
return return_p;
/* Put stmts parsed in the current block. */
if (!gimple_seq_empty_p (*seq))
{
if (!parser.current_bb)
c_parser_error (parser, "stmts without block");
else
{
gimple_stmt_iterator gsi
= gsi_start_bb (parser.current_bb);
gsi_insert_seq_after (&gsi, *seq, GSI_CONTINUE_LINKING);
}
*seq = NULL;
}
/* Build an empty block with specified index, linking them
in source order. */
basic_block bb = alloc_block ();
bb->index = index;
link_block (bb, (parser.current_bb ? parser.current_bb
: ENTRY_BLOCK_PTR_FOR_FN (cfun)));
if (basic_block_info_for_fn (cfun)->length () <= (size_t)index)
vec_safe_grow_cleared (basic_block_info_for_fn (cfun),
index + 1, true);
SET_BASIC_BLOCK_FOR_FN (cfun, index, bb);
if (last_basic_block_for_fn (cfun) <= index)
last_basic_block_for_fn (cfun) = index + 1;
n_basic_blocks_for_fn (cfun)++;
if (parser.current_bb->index == ENTRY_BLOCK)
parser.push_edge (ENTRY_BLOCK, bb->index, EDGE_FALLTHRU,
profile_probability::always ());
/* We leave the proper setting to fixup. */
class loop *loop_father = loops_for_fn (cfun)->tree_root;
/* If the new block is a loop header, allocate a loop
struct. Fixup will take care of proper placement within
the loop tree. */
if (is_loop_header_of != -1)
{
if (number_of_loops (cfun) > (unsigned)is_loop_header_of
&& get_loop (cfun, is_loop_header_of) != NULL)
{
c_parser_error (parser, "duplicate loop header");
}
else
{
class loop *loop = alloc_loop ();
loop->num = is_loop_header_of;
loop->header = bb;
vec_safe_grow_cleared (loops_for_fn (cfun)->larray,
is_loop_header_of + 1, true);
(*loops_for_fn (cfun)->larray)[is_loop_header_of] = loop;
flow_loop_tree_node_add (loops_for_fn (cfun)->tree_root,
loop);
}
loop_father = get_loop (cfun, is_loop_header_of);
}
bb->loop_father = loop_father;
bb->count = bb_count;
/* Stmts now go to the new block. */
parser.current_bb = bb;
break;
}
goto expr_stmt;
case CPP_SEMICOLON:
{
/* Empty stmt. */
location_t loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
gimple *nop = gimple_build_nop ();
gimple_set_location (nop, loc);
gimple_seq_add_stmt_without_update (seq, nop);
break;
}
default:
expr_stmt:
c_parser_gimple_statement (parser, seq);
if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
}
}
c_parser_consume_token (parser);
/* Put stmts parsed in the current block. */
if ((cfun->curr_properties & PROP_cfg)
&& !gimple_seq_empty_p (*seq))
{
if (!parser.current_bb)
c_parser_error (parser, "stmts without block");
else
{
gimple_stmt_iterator gsi = gsi_start_bb (parser.current_bb);
gsi_insert_seq_after (&gsi, *seq, GSI_CONTINUE_LINKING);
}
*seq = NULL;
}
return return_p;
}
/* 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 (gimple_parser &parser, gimple_seq *seq)
{
struct c_expr lhs, rhs;
gimple *assign = NULL;
location_t loc;
tree arg = NULL_TREE;
auto_vec vargs;
lhs = c_parser_gimple_unary_expression (parser);
loc = EXPR_LOCATION (lhs.value);
rhs.set_error ();
/* GIMPLE call statement without LHS. */
if (c_parser_next_token_is (parser, CPP_SEMICOLON)
&& TREE_CODE (lhs.value) == CALL_EXPR)
{
gimple *call;
call = gimple_build_call_from_tree (lhs.value, NULL);
gimple_seq_add_stmt_without_update (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 (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_without_update (seq, assign);
gimple_set_location (assign, loc);
return;
}
}
/* Unary expression. */
switch (c_parser_peek_token (parser)->type)
{
case CPP_NAME:
{
tree id = c_parser_peek_token (parser)->value;
if (strcmp (IDENTIFIER_POINTER (id), "__ABS") == 0
|| strcmp (IDENTIFIER_POINTER (id), "__ABSU") == 0
|| strcmp (IDENTIFIER_POINTER (id), "__MIN") == 0
|| strcmp (IDENTIFIER_POINTER (id), "__MAX") == 0
|| strcmp (IDENTIFIER_POINTER (id), "__BIT_INSERT") == 0
|| strcmp (IDENTIFIER_POINTER (id), "__VEC_PERM") == 0)
goto build_unary_expr;
break;
}
case CPP_KEYWORD:
if (c_parser_peek_token (parser)->keyword != RID_REALPART
&& c_parser_peek_token (parser)->keyword != RID_IMAGPART)
break;
/* Fallthru. */
case CPP_AND:
case CPP_PLUS:
case CPP_MINUS:
case CPP_COMPL:
case CPP_NOT:
case CPP_MULT: /* pointer deref */
build_unary_expr:
rhs = c_parser_gimple_unary_expression (parser);
if (rhs.value != error_mark_node)
{
assign = gimple_build_assign (lhs.value, rhs.value);
gimple_set_location (assign, loc);
gimple_seq_add_stmt_without_update (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 = 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);
int src_index = -1;
if (!c_parser_gimple_parse_bb_spec (arg, &src_index))
c_parser_error (parser, "invalid source block specification");
vargs.safe_push (size_int (src_index));
}
else if (c_parser_next_token_is (parser, CPP_COMMA))
c_parser_consume_token (parser);
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_without_update (seq, call_stmt);
return;
}
/* GIMPLE call with lhs. */
if (c_parser_next_token_is (parser, CPP_DOT)
|| (c_parser_next_token_is (parser, CPP_NAME)
&& c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN
&& lookup_name (c_parser_peek_token (parser)->value)))
{
rhs = c_parser_gimple_unary_expression (parser);
if (rhs.value != error_mark_node)
{
gimple *call = gimple_build_call_from_tree (rhs.value, NULL);
gimple_call_set_lhs (call, lhs.value);
gimple_seq_add_stmt_without_update (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)
{
/* If we parsed a comparison and the next token is a '?' then
parse a conditional expression. */
if (COMPARISON_CLASS_P (rhs.value)
&& c_parser_next_token_is (parser, CPP_QUERY))
{
struct c_expr trueval, falseval;
c_parser_consume_token (parser);
trueval = c_parser_gimple_postfix_expression (parser);
falseval.set_error ();
if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
falseval = c_parser_gimple_postfix_expression (parser);
if (trueval.value == error_mark_node
|| falseval.value == error_mark_node)
return;
rhs.value = build3_loc (loc, COND_EXPR, TREE_TYPE (trueval.value),
rhs.value, trueval.value, falseval.value);
}
assign = gimple_build_assign (lhs.value, rhs.value);
gimple_seq_add_stmt_without_update (seq, assign);
gimple_set_location (assign, loc);
}
return;
}
/* Parse gimple binary expr.
gimple-binary-expression:
gimple-unary-expression * gimple-unary-expression
gimple-unary-expression __MULT_HIGHPART 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 (gimple_parser &parser)
{
/* Location of the binary operator. */
struct c_expr ret, lhs, rhs;
enum tree_code code = ERROR_MARK;
ret.set_error ();
lhs = c_parser_gimple_postfix_expression (parser);
if (c_parser_error (parser))
return ret;
tree ret_type = TREE_TYPE (lhs.value);
switch (c_parser_peek_token (parser)->type)
{
case CPP_MULT:
code = MULT_EXPR;
break;
case CPP_DIV:
code = TRUNC_DIV_EXPR;
break;
case CPP_MOD:
code = TRUNC_MOD_EXPR;
break;
case CPP_PLUS:
if (POINTER_TYPE_P (TREE_TYPE (lhs.value)))
code = POINTER_PLUS_EXPR;
else
code = PLUS_EXPR;
break;
case CPP_MINUS:
code = MINUS_EXPR;
break;
case CPP_LSHIFT:
code = LSHIFT_EXPR;
break;
case CPP_RSHIFT:
code = RSHIFT_EXPR;
break;
case CPP_LESS:
code = LT_EXPR;
ret_type = boolean_type_node;
break;
case CPP_GREATER:
code = GT_EXPR;
ret_type = boolean_type_node;
break;
case CPP_LESS_EQ:
code = LE_EXPR;
ret_type = boolean_type_node;
break;
case CPP_GREATER_EQ:
code = GE_EXPR;
ret_type = boolean_type_node;
break;
case CPP_EQ_EQ:
code = EQ_EXPR;
ret_type = boolean_type_node;
break;
case CPP_NOT_EQ:
code = NE_EXPR;
ret_type = boolean_type_node;
break;
case CPP_AND:
code = BIT_AND_EXPR;
break;
case CPP_XOR:
code = BIT_XOR_EXPR;
break;
case CPP_OR:
code = BIT_IOR_EXPR;
break;
case CPP_AND_AND:
c_parser_error (parser, "%<&&%> not valid in GIMPLE");
return ret;
case CPP_OR_OR:
c_parser_error (parser, "%<||%> not valid in GIMPLE");
return ret;
case CPP_NAME:
{
tree id = c_parser_peek_token (parser)->value;
if (strcmp (IDENTIFIER_POINTER (id), "__MULT_HIGHPART") == 0)
{
code = MULT_HIGHPART_EXPR;
break;
}
}
/* Fallthru. */
default:
/* Not a binary expression. */
return lhs;
}
location_t ret_loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
rhs = c_parser_gimple_postfix_expression (parser);
if (lhs.value != error_mark_node && rhs.value != error_mark_node)
ret.value = build2_loc (ret_loc, code, ret_type, lhs.value, rhs.value);
return ret;
}
/* Parse a gimple parentized binary expression. */
static c_expr
c_parser_gimple_parentized_binary_expression (gimple_parser &parser,
location_t op_loc,
tree_code code)
{
struct c_expr ret;
ret.set_error ();
c_parser_consume_token (parser);
if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
return ret;
c_expr op1 = c_parser_gimple_postfix_expression (parser);
if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
return ret;
c_expr op2 = c_parser_gimple_postfix_expression (parser);
if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
return ret;
if (op1.value != error_mark_node && op2.value != error_mark_node)
ret.value = build2_loc (op_loc,
code, TREE_TYPE (op1.value), op1.value, op2.value);
return ret;
}
/* Parse a gimple parentized binary expression. */
static c_expr
c_parser_gimple_parentized_ternary_expression (gimple_parser &parser,
location_t op_loc,
tree_code code)
{
struct c_expr ret;
ret.set_error ();
c_parser_consume_token (parser);
if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
return ret;
c_expr op1 = c_parser_gimple_postfix_expression (parser);
if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
return ret;
c_expr op2 = c_parser_gimple_postfix_expression (parser);
if (!c_parser_require (parser, CPP_COMMA, "expected %<)%>"))
return ret;
c_expr op3 = c_parser_gimple_postfix_expression (parser);
if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
return ret;
if (op1.value != error_mark_node
&& op2.value != error_mark_node
&& op3.value != error_mark_node)
ret.value = build3_loc (op_loc,
code, TREE_TYPE (op1.value),
op1.value, op2.value, op3.value);
return ret;
}
/* Parse gimple unary expression.
gimple-unary-expression:
gimple-postfix-expression
unary-operator gimple-postfix-expression
unary-operator: one of
& * + - ~ abs_expr
*/
static c_expr
c_parser_gimple_unary_expression (gimple_parser &parser)
{
struct c_expr ret, op;
location_t op_loc = c_parser_peek_token (parser)->location;
location_t finish;
ret.set_error ();
switch (c_parser_peek_token (parser)->type)
{
case CPP_AND:
c_parser_consume_token (parser);
op = c_parser_gimple_postfix_expression (parser);
mark_exp_read (op.value);
return parser_build_unary_op (op_loc, ADDR_EXPR, op);
case CPP_MULT:
{
c_parser_consume_token (parser);
op = c_parser_gimple_postfix_expression (parser);
if (op.value == error_mark_node)
return ret;
if (! POINTER_TYPE_P (TREE_TYPE (op.value)))
{
error_at (op_loc, "expected pointer as argument of unary %<*%>");
return ret;
}
finish = op.get_finish ();
location_t combined_loc = make_location (op_loc, op_loc, finish);
ret.value = build_simple_mem_ref_loc (combined_loc, op.value);
TREE_SIDE_EFFECTS (ret.value)
= TREE_THIS_VOLATILE (ret.value)
= TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (op.value)));
ret.src_range.m_start = op_loc;
ret.src_range.m_finish = finish;
return ret;
}
case CPP_PLUS:
c_parser_consume_token (parser);
op = c_parser_gimple_postfix_expression (parser);
return parser_build_unary_op (op_loc, CONVERT_EXPR, op);
case CPP_MINUS:
c_parser_consume_token (parser);
op = c_parser_gimple_postfix_expression (parser);
return parser_build_unary_op (op_loc, NEGATE_EXPR, op);
case CPP_COMPL:
c_parser_consume_token (parser);
op = c_parser_gimple_postfix_expression (parser);
return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op);
case CPP_NOT:
c_parser_error (parser, "% not valid in GIMPLE");
return ret;
case CPP_KEYWORD:
switch (c_parser_peek_token (parser)->keyword)
{
case RID_REALPART:
c_parser_consume_token (parser);
op = c_parser_gimple_postfix_expression (parser);
return parser_build_unary_op (op_loc, REALPART_EXPR, op);
case RID_IMAGPART:
c_parser_consume_token (parser);
op = c_parser_gimple_postfix_expression (parser);
return parser_build_unary_op (op_loc, IMAGPART_EXPR, op);
default:
return c_parser_gimple_postfix_expression (parser);
}
case CPP_NAME:
{
tree id = c_parser_peek_token (parser)->value;
if (strcmp (IDENTIFIER_POINTER (id), "__ABS") == 0)
{
c_parser_consume_token (parser);
op = c_parser_gimple_postfix_expression (parser);
return parser_build_unary_op (op_loc, ABS_EXPR, op);
}
else if (strcmp (IDENTIFIER_POINTER (id), "__ABSU") == 0)
{
c_parser_consume_token (parser);
op = c_parser_gimple_postfix_expression (parser);
return parser_build_unary_op (op_loc, ABSU_EXPR, op);
}
else if (strcmp (IDENTIFIER_POINTER (id), "__MIN") == 0)
return c_parser_gimple_parentized_binary_expression (parser,
op_loc,
MIN_EXPR);
else if (strcmp (IDENTIFIER_POINTER (id), "__MAX") == 0)
return c_parser_gimple_parentized_binary_expression (parser,
op_loc,
MAX_EXPR);
else if (strcmp (IDENTIFIER_POINTER (id), "__VEC_PERM") == 0)
return c_parser_gimple_parentized_ternary_expression
(parser, op_loc, VEC_PERM_EXPR);
else if (strcmp (IDENTIFIER_POINTER (id), "__BIT_INSERT") == 0)
{
/* __BIT_INSERT '(' postfix-expression, postfix-expression,
integer ')' */
location_t loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
c_expr op0 = c_parser_gimple_postfix_expression (parser);
c_parser_skip_until_found (parser, CPP_COMMA,
"expected %<,%>");
c_expr op1 = c_parser_gimple_postfix_expression (parser);
c_parser_skip_until_found (parser, CPP_COMMA,
"expected %<,%>");
c_expr op2 = c_parser_gimple_postfix_expression (parser);
if (TREE_CODE (op2.value) != INTEGER_CST
|| !int_fits_type_p (op2.value, bitsizetype))
c_parser_error (parser, "expected constant offset");
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
if (op0.value != error_mark_node
&& op1.value != error_mark_node
&& TREE_CODE (op2.value) == INTEGER_CST)
ret.value = build3_loc (loc, BIT_INSERT_EXPR,
TREE_TYPE (op0.value),
op0.value, op1.value,
fold_convert (bitsizetype,
op2.value));
}
return ret;
}
else
return c_parser_gimple_postfix_expression (parser);
}
default:
return c_parser_gimple_postfix_expression (parser);
}
}
/* Decompose ID into base name (ID until ver_offset) and VERSION. Return
true if ID matches a SSA name. */
static bool
c_parser_parse_ssa_name_id (tree id, unsigned *version, unsigned *ver_offset)
{
const char *token = IDENTIFIER_POINTER (id);
const char *var_version = strrchr (token, '_');
if (! var_version)
return false;
*ver_offset = var_version - token;
for (const char *p = var_version + 1; *p; ++p)
if (! ISDIGIT (*p))
return false;
*version = atoi (var_version + 1);
return *version > 0;
}
/* Get at the actual SSA name ID with VERSION starting at VER_OFFSET.
TYPE is the type if the SSA name is being declared. */
static tree
c_parser_parse_ssa_name (gimple_parser &parser,
tree id, tree type, unsigned version,
unsigned ver_offset)
{
tree name = NULL_TREE;
const char *token = IDENTIFIER_POINTER (id);
if (ver_offset == 0)
{
/* Anonymous unnamed SSA name. */
if (version < num_ssa_names)
name = ssa_name (version);
if (! name)
{
if (! type)
{
c_parser_error (parser, "SSA name undeclared");
return error_mark_node;
}
name = make_ssa_name_fn (cfun, type, NULL, version);
}
}
else
{
if (version < num_ssa_names)
name = ssa_name (version);
if (! name)
{
/* Separate var name from version. */
char *var_name = XNEWVEC (char, ver_offset + 1);
memcpy (var_name, token, ver_offset);
var_name[ver_offset] = '\0';
/* lookup for parent decl. */
id = get_identifier (var_name);
tree parent = lookup_name (id);
XDELETEVEC (var_name);
if (! parent || parent == error_mark_node)
{
c_parser_error (parser, "base variable or SSA name undeclared");
return error_mark_node;
}
if (!(VAR_P (parent)
|| TREE_CODE (parent) == PARM_DECL
|| TREE_CODE (parent) == RESULT_DECL))
{
error ("invalid base %qE for SSA name", parent);
return error_mark_node;
}
name = make_ssa_name_fn (cfun, parent,
gimple_build_nop (), version);
}
}
return name;
}
/* Parse a gimple call to an internal function.
gimple-call-internal:
. identifier ( gimple-argument-expression-list[opt] ) */
static struct c_expr
c_parser_gimple_call_internal (gimple_parser &parser)
{
struct c_expr expr;
expr.set_error ();
gcc_assert (c_parser_next_token_is (parser, CPP_DOT));
c_parser_consume_token (parser);
location_t loc = c_parser_peek_token (parser)->location;
if (!c_parser_next_token_is (parser, CPP_NAME)
|| c_parser_peek_token (parser)->id_kind != C_ID_ID)
{
c_parser_error (parser, "expecting internal function name");
return expr;
}
tree id = c_parser_peek_token (parser)->value;
internal_fn ifn = lookup_internal_fn (IDENTIFIER_POINTER (id));
c_parser_consume_token (parser);
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
auto_vec exprlist;
if (!c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
c_parser_gimple_expr_list (parser, &exprlist);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
if (ifn == IFN_LAST)
error_at (loc, "unknown internal function %qE", id);
else
{
expr.value = build_call_expr_internal_loc_array
(loc, ifn, void_type_node, exprlist.length (),
exprlist.address ());
expr.original_code = ERROR_MARK;
expr.original_type = NULL;
}
}
return expr;
}
/* Parse '<' type [',' alignment] '>' and return a type on success
and NULL_TREE on error. */
static tree
c_parser_gimple_typespec (gimple_parser &parser)
{
struct c_type_name *type_name = NULL;
tree alignment = NULL_TREE;
if (c_parser_require (parser, CPP_LESS, "expected %<<%>"))
{
type_name = c_parser_type_name (parser);
/* Optional alignment. */
if (c_parser_next_token_is (parser, CPP_COMMA))
{
c_parser_consume_token (parser);
alignment
= c_parser_gimple_postfix_expression (parser).value;
}
c_parser_skip_until_found (parser,
CPP_GREATER, "expected %<>%>");
}
if (!type_name)
return NULL_TREE;
tree tem;
tree type = groktypename (type_name, &tem, NULL);
if (alignment)
type = build_aligned_type (type, tree_to_uhwi (alignment));
return type;
}
/* Parse gimple postfix expression.
gimple-postfix-expression:
gimple-primary-expression
gimple-primary-expression [ gimple-primary-expression ]
gimple-primary-expression ( gimple-argument-expression-list[opt] )
gimple-postfix-expression . identifier
gimple-postfix-expression -> identifier
gimple-argument-expression-list:
gimple-unary-expression
gimple-argument-expression-list , gimple-unary-expression
gimple-primary-expression:
identifier
constant
string-literal
constructor
gimple-call-internal
*/
static struct c_expr
c_parser_gimple_postfix_expression (gimple_parser &parser)
{
location_t loc = c_parser_peek_token (parser)->location;
source_range tok_range = c_parser_peek_token (parser)->get_range ();
struct c_expr expr;
expr.set_error ();
switch (c_parser_peek_token (parser)->type)
{
case CPP_NUMBER:
expr.value = c_parser_peek_token (parser)->value;
set_c_expr_source_range (&expr, tok_range);
loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
break;
case CPP_CHAR:
case CPP_CHAR16:
case CPP_CHAR32:
case CPP_UTF8CHAR:
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 = c_parser_string_literal (parser, false, true);
break;
case CPP_DOT:
expr = c_parser_gimple_call_internal (parser);
break;
case CPP_NAME:
if (c_parser_peek_token (parser)->id_kind == C_ID_ID)
{
tree id = c_parser_peek_token (parser)->value;
if (strcmp (IDENTIFIER_POINTER (id), "__MEM") == 0)
{
/* __MEM '<' type-name [ ',' number ] '>'
'(' [ '(' type-name ')' ] unary-expression
[ '+' number ] ')' */
location_t loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
tree type = c_parser_gimple_typespec (parser);
struct c_expr ptr;
ptr.value = error_mark_node;
tree alias_off = NULL_TREE;
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
tree alias_type = NULL_TREE;
/* Optional alias-type cast. */
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
{
c_parser_consume_token (parser);
struct c_type_name *alias_type_name
= c_parser_type_name (parser);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
if (alias_type_name)
{
tree tem;
alias_type = groktypename (alias_type_name,
&tem, NULL);
}
}
ptr = c_parser_gimple_unary_expression (parser);
if (ptr.value == error_mark_node
|| ! POINTER_TYPE_P (TREE_TYPE (ptr.value)))
{
if (ptr.value != error_mark_node)
error_at (ptr.get_start (),
"invalid type of %<__MEM%> operand");
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
return expr;
}
if (! alias_type)
alias_type = TREE_TYPE (ptr.value);
/* Optional constant offset. */
if (c_parser_next_token_is (parser, CPP_PLUS))
{
c_parser_consume_token (parser);
alias_off
= c_parser_gimple_postfix_expression (parser).value;
alias_off = fold_convert (alias_type, alias_off);
}
if (! alias_off)
alias_off = build_int_cst (alias_type, 0);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
}
if (! type || c_parser_error (parser))
{
c_parser_set_error (parser, false);
return expr;
}
expr.value = build2_loc (loc, MEM_REF,
type, ptr.value, alias_off);
break;
}
else if (strcmp (IDENTIFIER_POINTER (id), "__VIEW_CONVERT") == 0)
{
/* __VIEW_CONVERT '<' type-name [ ',' number ] '>'
'(' postfix-expression ')' */
location_t loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
tree type = c_parser_gimple_typespec (parser);
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
c_expr op = c_parser_gimple_postfix_expression (parser);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
if (type && op.value != error_mark_node)
expr.value = build1_loc (loc, VIEW_CONVERT_EXPR,
type, op.value);
}
break;
}
else if (strcmp (IDENTIFIER_POINTER (id), "__BIT_FIELD_REF") == 0)
{
/* __BIT_FIELD_REF '<' type-name [ ',' number ] '>'
'(' postfix-expression, integer, integer ')' */
location_t loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
tree type = c_parser_gimple_typespec (parser);
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
c_expr op0 = c_parser_gimple_postfix_expression (parser);
c_parser_skip_until_found (parser, CPP_COMMA,
"expected %<,%>");
c_expr op1 = c_parser_gimple_postfix_expression (parser);
if (TREE_CODE (op1.value) != INTEGER_CST
|| !int_fits_type_p (op1.value, bitsizetype))
c_parser_error (parser, "expected constant size");
c_parser_skip_until_found (parser, CPP_COMMA,
"expected %<,%>");
c_expr op2 = c_parser_gimple_postfix_expression (parser);
if (TREE_CODE (op2.value) != INTEGER_CST
|| !int_fits_type_p (op2.value, bitsizetype))
c_parser_error (parser, "expected constant offset");
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
if (type
&& op0.value != error_mark_node
&& TREE_CODE (op1.value) == INTEGER_CST
&& TREE_CODE (op2.value) == INTEGER_CST)
expr.value = build3_loc (loc, BIT_FIELD_REF, type,
op0.value,
fold_convert (bitsizetype,
op1.value),
fold_convert (bitsizetype,
op2.value));
}
break;
}
else if (strcmp (IDENTIFIER_POINTER (id), "_Literal") == 0)
{
/* _Literal '(' type-name ')' ( [ '-' ] constant | constructor ) */
c_parser_consume_token (parser);
tree type = NULL_TREE;
if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
{
struct c_type_name *type_name = c_parser_type_name (parser);
tree tem;
if (type_name)
type = groktypename (type_name, &tem, NULL);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
}
if (! type)
{
c_parser_error (parser, "invalid _Literal");
return expr;
}
if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
{
c_parser_consume_token (parser);
if (!AGGREGATE_TYPE_P (type)
&& !VECTOR_TYPE_P (type))
{
c_parser_error (parser, "invalid type for _Literal with "
"constructor");
c_parser_skip_until_found (parser, CPP_CLOSE_BRACE,
"expected %<}%>");
return expr;
}
vec *v = NULL;
bool constant_p = true;
if (VECTOR_TYPE_P (type)
&& !c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
{
vec_alloc (v, TYPE_VECTOR_SUBPARTS (type).to_constant ());
do
{
tree val
= c_parser_gimple_postfix_expression (parser).value;
if (! val
|| val == error_mark_node
|| (! CONSTANT_CLASS_P (val)
&& ! SSA_VAR_P (val)))
{
c_parser_error (parser, "invalid _Literal");
return expr;
}
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, val);
if (! CONSTANT_CLASS_P (val))
constant_p = false;
if (c_parser_next_token_is (parser, CPP_COMMA))
c_parser_consume_token (parser);
else
break;
}
while (1);
}
if (c_parser_require (parser, CPP_CLOSE_BRACE,
"expected %<}%>"))
{
if (v && constant_p)
expr.value = build_vector_from_ctor (type, v);
else
expr.value = build_constructor (type, v);
}
else
{
c_parser_skip_until_found (parser, CPP_CLOSE_BRACE,
"expected %<}%>");
return expr;
}
}
else
{
bool neg_p, addr_p;
if ((neg_p = c_parser_next_token_is (parser, CPP_MINUS)))
c_parser_consume_token (parser);
if ((addr_p = c_parser_next_token_is (parser, CPP_AND)))
c_parser_consume_token (parser);
tree val = c_parser_gimple_postfix_expression (parser).value;
if (! val
|| val == error_mark_node
|| (!CONSTANT_CLASS_P (val)
&& !(addr_p
&& (TREE_CODE (val) == STRING_CST
|| DECL_P (val)))))
{
c_parser_error (parser, "invalid _Literal");
return expr;
}
if (addr_p)
val = build1 (ADDR_EXPR, type, val);
if (neg_p)
{
val = const_unop (NEGATE_EXPR, TREE_TYPE (val), val);
if (! val)
{
c_parser_error (parser, "invalid _Literal");
return expr;
}
}
expr.value = fold_convert (type, val);
}
return expr;
}
/* SSA name. */
unsigned version, ver_offset;
if (! lookup_name (id)
&& c_parser_parse_ssa_name_id (id, &version, &ver_offset))
{
c_parser_consume_token (parser);
expr.value = c_parser_parse_ssa_name (parser, id, NULL_TREE,
version, ver_offset);
if (expr.value == error_mark_node)
return expr;
set_c_expr_source_range (&expr, tok_range);
/* For default definition SSA names. */
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
&& c_parser_peek_2nd_token (parser)->type == CPP_NAME
&& strcmp ("D",
IDENTIFIER_POINTER
(c_parser_peek_2nd_token (parser)->value)) == 0
&& c_parser_peek_nth_token (parser, 3)->type == CPP_CLOSE_PAREN)
{
c_parser_consume_token (parser);
c_parser_consume_token (parser);
c_parser_consume_token (parser);
if (! SSA_NAME_IS_DEFAULT_DEF (expr.value))
{
if (!SSA_NAME_VAR (expr.value))
{
error_at (loc, "anonymous SSA name cannot have"
" default definition");
expr.value = error_mark_node;
return expr;
}
set_ssa_default_def (cfun, SSA_NAME_VAR (expr.value),
expr.value);
SSA_NAME_DEF_STMT (expr.value) = gimple_build_nop ();
}
}
}
else
{
c_parser_consume_token (parser);
expr.value
= build_external_ref (loc, id,
(c_parser_peek_token (parser)->type
== CPP_OPEN_PAREN), &expr.original_type);
set_c_expr_source_range (&expr, tok_range);
}
break;
}
else
{
c_parser_error (parser, "expected expression");
expr.set_error ();
break;
}
break;
default:
c_parser_error (parser, "expected expression");
expr.set_error ();
break;
}
return c_parser_gimple_postfix_expression_after_primary
(parser, EXPR_LOC_OR_LOC (expr.value, loc), expr);
}
/* Parse a gimple postfix expression after the initial primary or compound
literal. */
static struct c_expr
c_parser_gimple_postfix_expression_after_primary (gimple_parser &parser,
location_t expr_loc,
struct c_expr expr)
{
location_t start;
location_t finish;
tree ident;
location_t comp_loc;
while (true)
{
location_t op_loc = c_parser_peek_token (parser)->location;
switch (c_parser_peek_token (parser)->type)
{
case CPP_OPEN_SQUARE:
{
c_parser_consume_token (parser);
tree idx = c_parser_gimple_unary_expression (parser).value;
if (! c_parser_require (parser, CPP_CLOSE_SQUARE, "expected %<]%>"))
{
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL);
break;
}
start = expr.get_start ();
finish = c_parser_tokens_buf (parser, 0)->location;
expr.value = build_array_ref (op_loc, expr.value, idx);
set_c_expr_source_range (&expr, start, finish);
expr.original_code = ERROR_MARK;
expr.original_type = NULL;
break;
}
case CPP_OPEN_PAREN:
{
/* Function call. */
c_parser_consume_token (parser);
auto_vec exprlist;
if (! c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
c_parser_gimple_expr_list (parser, &exprlist);
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
"expected %<)%>");
expr.value = build_call_array_loc
(expr_loc, TREE_TYPE (TREE_TYPE (expr.value)),
expr.value, exprlist.length (), exprlist.address ());
expr.original_code = ERROR_MARK;
expr.original_type = NULL;
break;
}
case CPP_DOT:
{
/* Structure element reference. */
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_NAME))
{
c_token *comp_tok = c_parser_peek_token (parser);
ident = comp_tok->value;
comp_loc = comp_tok->location;
}
else
{
c_parser_error (parser, "expected identifier");
expr.set_error ();
expr.original_code = ERROR_MARK;
expr.original_type = NULL;
return expr;
}
start = expr.get_start ();
finish = c_parser_peek_token (parser)->get_finish ();
c_parser_consume_token (parser);
expr.value = build_component_ref (op_loc, expr.value, ident,
comp_loc);
set_c_expr_source_range (&expr, start, finish);
expr.original_code = ERROR_MARK;
if (TREE_CODE (expr.value) != COMPONENT_REF)
expr.original_type = NULL;
else
{
/* Remember the original type of a bitfield. */
tree field = TREE_OPERAND (expr.value, 1);
if (TREE_CODE (field) != FIELD_DECL)
expr.original_type = NULL;
else
expr.original_type = DECL_BIT_FIELD_TYPE (field);
}
break;
}
case CPP_DEREF:
{
/* Structure element reference. */
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_NAME))
{
c_token *comp_tok = c_parser_peek_token (parser);
ident = comp_tok->value;
comp_loc = comp_tok->location;
}
else
{
c_parser_error (parser, "expected identifier");
expr.set_error ();
expr.original_code = ERROR_MARK;
expr.original_type = NULL;
return expr;
}
start = expr.get_start ();
finish = c_parser_peek_token (parser)->get_finish ();
c_parser_consume_token (parser);
expr.value = build_component_ref (op_loc,
build_simple_mem_ref_loc
(op_loc, expr.value),
ident, comp_loc);
set_c_expr_source_range (&expr, start, finish);
expr.original_code = ERROR_MARK;
if (TREE_CODE (expr.value) != COMPONENT_REF)
expr.original_type = NULL;
else
{
/* Remember the original type of a bitfield. */
tree field = TREE_OPERAND (expr.value, 1);
if (TREE_CODE (field) != FIELD_DECL)
expr.original_type = NULL;
else
expr.original_type = DECL_BIT_FIELD_TYPE (field);
}
break;
}
default:
return expr;
}
}
}
/* Parse expression list.
gimple-expr-list:
gimple-unary-expression
gimple-expr-list , gimple-unary-expression
*/
static void
c_parser_gimple_expr_list (gimple_parser &parser, vec *ret)
{
struct c_expr expr;
expr = c_parser_gimple_unary_expression (parser);
ret->safe_push (expr.value);
while (c_parser_next_token_is (parser, CPP_COMMA))
{
c_parser_consume_token (parser);
expr = c_parser_gimple_unary_expression (parser);
ret->safe_push (expr.value);
}
}
/* Parse gimple label.
gimple-label:
identifier :
case constant-expression :
default :
*/
static void
c_parser_gimple_label (gimple_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_without_update (seq, gimple_build_label (label));
return;
}
/* Parse gimple/RTL pass list.
gimple-or-rtl-pass-list:
startwith("pass-name")[,{cfg,ssa}]
*/
void
c_parser_gimple_or_rtl_pass_list (c_parser *parser, c_declspecs *specs)
{
char *pass = NULL;
/* Accept __GIMPLE/__RTL. */
if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
return;
c_parser_consume_token (parser);
specs->entry_bb_count = profile_count::uninitialized ();
while (c_parser_next_token_is (parser, CPP_NAME))
{
profile_quality quality;
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;
if (c_parser_next_token_is_not (parser, CPP_STRING))
{
error_at (c_parser_peek_token (parser)->location,
"expected pass name");
return;
}
pass = xstrdup (TREE_STRING_POINTER
(c_parser_string_literal (parser, false,
false).value));
if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<(%>"))
return;
}
else if (parse_profile_quality (op, &quality))
{
tree q;
if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
return;
if (!c_parser_next_token_is (parser, CPP_NUMBER)
|| (TREE_CODE (q = c_parser_peek_token (parser)->value)
!= INTEGER_CST))
{
c_parser_error (parser, "expected count value");
return;
}
specs->entry_bb_count
= profile_count::from_gcov_type (TREE_INT_CST_LOW (q), quality);
c_parser_consume_token (parser);
if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
return;
}
else if (specs->declspec_il != cdil_gimple)
/* Allow only one IL specifier and none on RTL. */
;
else if (! strcmp (op, "cfg"))
specs->declspec_il = cdil_gimple_cfg;
else if (! strcmp (op, "ssa"))
specs->declspec_il = cdil_gimple_ssa;
else
{
error_at (c_parser_peek_token (parser)->location,
"invalid operation");
return;
}
if (c_parser_next_token_is (parser, CPP_COMMA))
c_parser_consume_token (parser);
}
if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
return;
specs->gimple_or_rtl_pass = 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 (gimple_parser &parser)
{
struct c_declarator *declarator;
struct c_declspecs *specs = build_null_declspecs ();
c_parser_declspecs (parser, specs, true, true, 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.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.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 (gimple_parser &parser,
location_t loc, tree label, gimple_seq *seq)
{
if (cfun->curr_properties & PROP_cfg)
{
int dest_index;
profile_probability prob;
if (c_parser_gimple_parse_bb_spec_edge_probability (label, parser,
&dest_index, &prob))
{
parser.push_edge (parser.current_bb->index, dest_index,
EDGE_FALLTHRU, prob);
return;
}
}
tree decl = lookup_label_for_goto (loc, label);
gimple_seq_add_stmt_without_update (seq, gimple_build_goto (decl));
}
/* Parse a parenthesized condition.
gimple-condition:
( gimple-binary-expression ) */
static tree
c_parser_gimple_paren_condition (gimple_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 try statement.
try-statement:
try { ... } finally { ... }
try { ... } finally { ... } else { ... }
This could support try/catch as well, but it's not implemented yet.
*/
static void
c_parser_gimple_try_stmt (gimple_parser &parser, gimple_seq *seq)
{
gimple_seq tryseq = NULL;
c_parser_consume_token (parser);
c_parser_gimple_compound_statement (parser, &tryseq);
if ((c_parser_next_token_is (parser, CPP_KEYWORD)
&& c_parser_peek_token (parser)->keyword == RID_AT_FINALLY)
|| (c_parser_next_token_is (parser, CPP_NAME)
&& c_parser_peek_token (parser)->id_kind == C_ID_ID
&& strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value),
"finally") == 0))
{
gimple_seq finseq = NULL;
c_parser_consume_token (parser);
c_parser_gimple_compound_statement (parser, &finseq);
if (c_parser_next_token_is (parser, CPP_KEYWORD)
&& c_parser_peek_token (parser)->keyword == RID_ELSE)
{
gimple_seq elsseq = NULL;
c_parser_consume_token (parser);
c_parser_gimple_compound_statement (parser, &elsseq);
geh_else *stmt = gimple_build_eh_else (finseq, elsseq);
finseq = NULL;
gimple_seq_add_stmt_without_update (&finseq, stmt);
}
gtry *stmt = gimple_build_try (tryseq, finseq, GIMPLE_TRY_FINALLY);
gimple_seq_add_stmt_without_update (seq, stmt);
}
else if (c_parser_next_token_is (parser, CPP_KEYWORD)
&& c_parser_peek_token (parser)->keyword == RID_AT_CATCH)
c_parser_error (parser, "% is not supported");
else
c_parser_error (parser, "expected % or %");
}
/* 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 (gimple_parser &parser, gimple_seq *seq)
{
tree t_label = NULL_TREE, f_label = NULL_TREE, label;
location_t loc;
c_parser_consume_token (parser);
tree cond = c_parser_gimple_paren_condition (parser);
if (c_parser_next_token_is_keyword (parser, RID_GOTO))
{
loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
if (! c_parser_next_token_is (parser, CPP_NAME))
{
c_parser_error (parser, "expected label");
return;
}
label = c_parser_peek_token (parser)->value;
c_parser_consume_token (parser);
int dest_index;
profile_probability prob;
if ((cfun->curr_properties & PROP_cfg)
&& c_parser_gimple_parse_bb_spec_edge_probability (label, parser,
&dest_index, &prob))
parser.push_edge (parser.current_bb->index, dest_index,
EDGE_TRUE_VALUE, prob);
else
t_label = lookup_label_for_goto (loc, label);
if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
return;
}
else
{
c_parser_error (parser, "expected goto expression");
return;
}
if (c_parser_next_token_is_keyword (parser, RID_ELSE))
c_parser_consume_token (parser);
else
{
c_parser_error (parser, "expected else statement");
return;
}
if (c_parser_next_token_is_keyword (parser, RID_GOTO))
{
loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
if (! c_parser_next_token_is (parser, CPP_NAME))
{
c_parser_error (parser, "expected label");
return;
}
label = c_parser_peek_token (parser)->value;
c_parser_consume_token (parser);
int dest_index;
profile_probability prob;
if ((cfun->curr_properties & PROP_cfg)
&& c_parser_gimple_parse_bb_spec_edge_probability (label, parser,
&dest_index, &prob))
parser.push_edge (parser.current_bb->index, dest_index,
EDGE_FALSE_VALUE, prob);
else
f_label = lookup_label_for_goto (loc, label);
if (! c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
return;
}
else
{
c_parser_error (parser, "expected goto expression");
return;
}
if (cond != error_mark_node)
gimple_seq_add_stmt_without_update (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 (gimple_parser &parser, gimple_seq *seq)
{
c_expr cond_expr;
tree case_label, label;
auto_vec labels;
tree default_label = NULL_TREE;
c_parser_consume_token (parser);
if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
return;
cond_expr = c_parser_gimple_postfix_expression (parser);
if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
return;
if (! c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
return;
while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
{
if (c_parser_next_token_is (parser, CPP_EOF))
{
c_parser_error (parser, "expected statement");
return;
}
switch (c_parser_peek_token (parser)->keyword)
{
case RID_CASE:
{
c_expr exp1;
location_t loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_NAME)
|| c_parser_peek_token (parser)->type == CPP_NUMBER)
exp1 = c_parser_gimple_postfix_expression (parser);
else
{
c_parser_error (parser, "expected expression");
return;
}
if (c_parser_next_token_is (parser, CPP_COLON))
{
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_NAME))
{
label = c_parser_peek_token (parser)->value;
c_parser_consume_token (parser);
tree decl = lookup_label_for_goto (loc, label);
case_label = build_case_label (exp1.value, NULL_TREE,
decl);
labels.safe_push (case_label);
if (! c_parser_require (parser, CPP_SEMICOLON,
"expected %<;%>"))
return;
}
else if (! c_parser_require (parser, CPP_NAME,
"expected label"))
return;
}
else if (! c_parser_require (parser, CPP_SEMICOLON,
"expected %<:%>"))
return;
break;
}
case RID_DEFAULT:
{
location_t loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_COLON))
{
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_NAME))
{
label = c_parser_peek_token (parser)->value;
c_parser_consume_token (parser);
tree decl = lookup_label_for_goto (loc, label);
default_label = build_case_label (NULL_TREE, NULL_TREE,
decl);
if (! c_parser_require (parser, CPP_SEMICOLON,
"expected %<;%>"))
return;
}
else if (! c_parser_require (parser, CPP_NAME,
"expected label"))
return;
}
else if (! c_parser_require (parser, CPP_SEMICOLON,
"expected %<:%>"))
return;
break;
}
default:
c_parser_error (parser, "expected case label");
return;
}
}
if (! c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"))
return;
if (cond_expr.value != error_mark_node)
{
gswitch *s = gimple_build_switch (cond_expr.value, default_label, labels);
gimple_seq_add_stmt_without_update (seq, s);
}
}
/* Parse gimple return statement. */
static void
c_parser_gimple_return_stmt (gimple_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_without_update (seq, ret);
}
else
{
location_t xloc = c_parser_peek_token (parser)->location;
c_expr expr = c_parser_gimple_unary_expression (parser);
if (expr.value != error_mark_node)
{
c_finish_gimple_return (xloc, expr.value);
ret = gimple_build_return (expr.value);
gimple_seq_add_stmt_without_update (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. */
location_t xloc = expansion_point_location_if_in_system_header (loc);
if (TREE_THIS_VOLATILE (current_function_decl))
warning_at (xloc, 0,
"function declared % has a % 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, "% 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;
}