diff options
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r-- | gcc/cp/parser.c | 139 |
1 files changed, 116 insertions, 23 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 57467bd..b04ed9a 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -2112,15 +2112,15 @@ static tree cp_parser_selection_statement static tree cp_parser_condition (cp_parser *); static tree cp_parser_iteration_statement - (cp_parser *, bool *, bool); + (cp_parser *, bool *, bool, unsigned short); static bool cp_parser_init_statement (cp_parser *, tree *decl); static tree cp_parser_for - (cp_parser *, bool); + (cp_parser *, bool, unsigned short); static tree cp_parser_c_for - (cp_parser *, tree, tree, bool); + (cp_parser *, tree, tree, bool, unsigned short); static tree cp_parser_range_for - (cp_parser *, tree, tree, tree, bool); + (cp_parser *, tree, tree, tree, bool, unsigned short); static void do_range_for_auto_deduction (tree, tree); static tree cp_parser_perform_range_for_lookup @@ -10742,7 +10742,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, case RID_WHILE: case RID_DO: case RID_FOR: - statement = cp_parser_iteration_statement (parser, if_p, false); + statement = cp_parser_iteration_statement (parser, if_p, false, 0); break; case RID_BREAK: @@ -11579,7 +11579,7 @@ cp_parser_condition (cp_parser* parser) not included. */ static tree -cp_parser_for (cp_parser *parser, bool ivdep) +cp_parser_for (cp_parser *parser, bool ivdep, unsigned short unroll) { tree init, scope, decl; bool is_range_for; @@ -11591,13 +11591,14 @@ cp_parser_for (cp_parser *parser, bool ivdep) is_range_for = cp_parser_init_statement (parser, &decl); if (is_range_for) - return cp_parser_range_for (parser, scope, init, decl, ivdep); + return cp_parser_range_for (parser, scope, init, decl, ivdep, unroll); else - return cp_parser_c_for (parser, scope, init, ivdep); + return cp_parser_c_for (parser, scope, init, ivdep, unroll); } static tree -cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep) +cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep, + unsigned short unroll) { /* Normal for loop */ tree condition = NULL_TREE; @@ -11618,7 +11619,13 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep) "%<GCC ivdep%> pragma"); condition = error_mark_node; } - finish_for_cond (condition, stmt, ivdep); + else if (unroll) + { + cp_parser_error (parser, "missing loop condition in loop with " + "%<GCC unroll%> pragma"); + condition = error_mark_node; + } + finish_for_cond (condition, stmt, ivdep, unroll); /* Look for the `;'. */ cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); @@ -11642,7 +11649,7 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep) static tree cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, - bool ivdep) + bool ivdep, unsigned short unroll) { tree stmt, range_expr; auto_vec <cxx_binding *, 16> bindings; @@ -11711,6 +11718,8 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, stmt = begin_range_for_stmt (scope, init); if (ivdep) RANGE_FOR_IVDEP (stmt) = 1; + if (unroll) + RANGE_FOR_UNROLL (stmt) = build_int_cst (integer_type_node, unroll); finish_range_for_decl (stmt, range_decl, range_expr); if (!type_dependent_expression_p (range_expr) /* do_auto_deduction doesn't mess with template init-lists. */ @@ -11721,7 +11730,8 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, { stmt = begin_for_stmt (scope, init); stmt = cp_convert_range_for (stmt, range_decl, range_expr, - decomp_first_name, decomp_cnt, ivdep); + decomp_first_name, decomp_cnt, ivdep, + unroll); } return stmt; } @@ -11815,7 +11825,7 @@ do_range_for_auto_deduction (tree decl, tree range_expr) tree cp_convert_range_for (tree statement, tree range_decl, tree range_expr, tree decomp_first_name, unsigned int decomp_cnt, - bool ivdep) + bool ivdep, unsigned short unroll) { tree begin, end; tree iter_type, begin_expr, end_expr; @@ -11876,7 +11886,7 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr, begin, ERROR_MARK, end, ERROR_MARK, NULL, tf_warning_or_error); - finish_for_cond (condition, statement, ivdep); + finish_for_cond (condition, statement, ivdep, unroll); /* The new increment expression. */ expression = finish_unary_op_expr (input_location, @@ -12054,7 +12064,8 @@ cp_parser_range_for_member_function (tree range, tree identifier) Returns the new WHILE_STMT, DO_STMT, FOR_STMT or RANGE_FOR_STMT. */ static tree -cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep) +cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep, + unsigned short unroll) { cp_token *token; enum rid keyword; @@ -12088,7 +12099,7 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep) parens.require_open (parser); /* Parse the condition. */ condition = cp_parser_condition (parser); - finish_while_stmt_cond (condition, statement, ivdep); + finish_while_stmt_cond (condition, statement, ivdep, unroll); /* Look for the `)'. */ parens.require_close (parser); /* Parse the dependent statement. */ @@ -12123,7 +12134,7 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep) /* Parse the expression. */ expression = cp_parser_expression (parser); /* We're done with the do-statement. */ - finish_do_stmt (expression, statement, ivdep); + finish_do_stmt (expression, statement, ivdep, unroll); /* Look for the `)'. */ parens.require_close (parser); /* Look for the `;'. */ @@ -12137,7 +12148,7 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep) matching_parens parens; parens.require_open (parser); - statement = cp_parser_for (parser, ivdep); + statement = cp_parser_for (parser, ivdep, unroll); /* Look for the `)'. */ parens.require_close (parser); @@ -38377,6 +38388,45 @@ cp_parser_initial_pragma (cp_token *first_token) cp_lexer_get_preprocessor_token (NULL, first_token); } +/* Parse a pragma GCC ivdep. */ + +static bool +cp_parser_pragma_ivdep (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return true; +} + +/* Parse a pragma GCC unroll. */ + +static unsigned short +cp_parser_pragma_unroll (cp_parser *parser, cp_token *pragma_tok) +{ + location_t location = cp_lexer_peek_token (parser->lexer)->location; + tree expr = cp_parser_constant_expression (parser); + unsigned short unroll; + expr = maybe_constant_value (expr); + HOST_WIDE_INT lunroll = 0; + if (!INTEGRAL_TYPE_P (TREE_TYPE (expr)) + || TREE_CODE (expr) != INTEGER_CST + || (lunroll = tree_to_shwi (expr)) < 0 + || lunroll >= USHRT_MAX) + { + error_at (location, "%<#pragma GCC unroll%> requires an" + " assignment-expression that evaluates to a non-negative" + " integral constant less than %u", USHRT_MAX); + unroll = 0; + } + else + { + unroll = (unsigned short)lunroll; + if (unroll == 0) + unroll = 1; + } + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return unroll; +} + /* Normal parsing of a pragma token. Here we can (and must) use the regular lexer. */ @@ -38618,17 +38668,60 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) "%<#pragma GCC ivdep%> must be inside a function"); break; } - cp_parser_skip_to_pragma_eol (parser, pragma_tok); - cp_token *tok; - tok = cp_lexer_peek_token (the_parser->lexer); + const bool ivdep = cp_parser_pragma_ivdep (parser, pragma_tok); + unsigned short unroll; + cp_token *tok = cp_lexer_peek_token (the_parser->lexer); + if (tok->type == CPP_PRAGMA + && cp_parser_pragma_kind (tok) == PRAGMA_UNROLL) + { + tok = cp_lexer_consume_token (parser->lexer); + unroll = cp_parser_pragma_unroll (parser, tok); + tok = cp_lexer_peek_token (the_parser->lexer); + } + else + unroll = 0; + if (tok->type != CPP_KEYWORD + || (tok->keyword != RID_FOR + && tok->keyword != RID_WHILE + && tok->keyword != RID_DO)) + { + cp_parser_error (parser, "for, while or do statement expected"); + return false; + } + cp_parser_iteration_statement (parser, if_p, ivdep, unroll); + return true; + } + + case PRAGMA_UNROLL: + { + if (context == pragma_external) + { + error_at (pragma_tok->location, + "%<#pragma GCC unroll%> must be inside a function"); + break; + } + const unsigned short unroll + = cp_parser_pragma_unroll (parser, pragma_tok); + bool ivdep; + cp_token *tok = cp_lexer_peek_token (the_parser->lexer); + if (tok->type == CPP_PRAGMA + && cp_parser_pragma_kind (tok) == PRAGMA_IVDEP) + { + tok = cp_lexer_consume_token (parser->lexer); + ivdep = cp_parser_pragma_ivdep (parser, tok); + tok = cp_lexer_peek_token (the_parser->lexer); + } + else + ivdep = false; if (tok->type != CPP_KEYWORD - || (tok->keyword != RID_FOR && tok->keyword != RID_WHILE + || (tok->keyword != RID_FOR + && tok->keyword != RID_WHILE && tok->keyword != RID_DO)) { cp_parser_error (parser, "for, while or do statement expected"); return false; } - cp_parser_iteration_statement (parser, if_p, true); + cp_parser_iteration_statement (parser, if_p, ivdep, unroll); return true; } |