aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c/c-parser.c')
-rw-r--r--gcc/c/c-parser.c144
1 files changed, 120 insertions, 24 deletions
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index f1bae8a..05d1e0f 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1406,9 +1406,9 @@ static tree c_parser_c99_block_statement (c_parser *, bool *,
location_t * = NULL);
static void c_parser_if_statement (c_parser *, bool *, vec<tree> *);
static void c_parser_switch_statement (c_parser *, bool *);
-static void c_parser_while_statement (c_parser *, bool, bool *);
-static void c_parser_do_statement (c_parser *, bool);
-static void c_parser_for_statement (c_parser *, bool, bool *);
+static void c_parser_while_statement (c_parser *, bool, unsigned short, bool *);
+static void c_parser_do_statement (c_parser *, bool, unsigned short);
+static void c_parser_for_statement (c_parser *, bool, unsigned short, bool *);
static tree c_parser_asm_statement (c_parser *);
static tree c_parser_asm_operands (c_parser *);
static tree c_parser_asm_goto_operands (c_parser *);
@@ -5400,13 +5400,13 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p,
c_parser_switch_statement (parser, if_p);
break;
case RID_WHILE:
- c_parser_while_statement (parser, false, if_p);
+ c_parser_while_statement (parser, false, 0, if_p);
break;
case RID_DO:
- c_parser_do_statement (parser, false);
+ c_parser_do_statement (parser, 0, false);
break;
case RID_FOR:
- c_parser_for_statement (parser, false, if_p);
+ c_parser_for_statement (parser, false, 0, if_p);
break;
case RID_GOTO:
c_parser_consume_token (parser);
@@ -5896,7 +5896,8 @@ c_parser_switch_statement (c_parser *parser, bool *if_p)
implement -Wparentheses. */
static void
-c_parser_while_statement (c_parser *parser, bool ivdep, bool *if_p)
+c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll,
+ bool *if_p)
{
tree block, cond, body, save_break, save_cont;
location_t loc;
@@ -5912,6 +5913,11 @@ c_parser_while_statement (c_parser *parser, bool ivdep, bool *if_p)
build_int_cst (integer_type_node,
annot_expr_ivdep_kind),
integer_zero_node);
+ if (unroll && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_unroll_kind),
+ build_int_cst (integer_type_node, unroll));
save_break = c_break_label;
c_break_label = NULL_TREE;
save_cont = c_cont_label;
@@ -5946,7 +5952,7 @@ c_parser_while_statement (c_parser *parser, bool ivdep, bool *if_p)
*/
static void
-c_parser_do_statement (c_parser *parser, bool ivdep)
+c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll)
{
tree block, cond, body, save_break, save_cont, new_break, new_cont;
location_t loc;
@@ -5974,6 +5980,11 @@ c_parser_do_statement (c_parser *parser, bool ivdep)
build_int_cst (integer_type_node,
annot_expr_ivdep_kind),
integer_zero_node);
+ if (unroll && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_unroll_kind),
+ build_int_cst (integer_type_node, unroll));
if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
c_parser_skip_to_end_of_block_or_statement (parser);
c_finish_loop (loc, cond, NULL, body, new_break, new_cont, false);
@@ -6040,7 +6051,8 @@ c_parser_do_statement (c_parser *parser, bool ivdep)
implement -Wparentheses. */
static void
-c_parser_for_statement (c_parser *parser, bool ivdep, bool *if_p)
+c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
+ bool *if_p)
{
tree block, cond, incr, save_break, save_cont, body;
/* The following are only used when parsing an ObjC foreach statement. */
@@ -6159,6 +6171,12 @@ c_parser_for_statement (c_parser *parser, bool ivdep, bool *if_p)
"%<GCC ivdep%> pragma");
cond = error_mark_node;
}
+ else if (unroll)
+ {
+ c_parser_error (parser, "missing loop condition in loop with "
+ "%<GCC unroll%> pragma");
+ cond = error_mark_node;
+ }
else
{
c_parser_consume_token (parser);
@@ -6176,6 +6194,11 @@ c_parser_for_statement (c_parser *parser, bool ivdep, bool *if_p)
build_int_cst (integer_type_node,
annot_expr_ivdep_kind),
integer_zero_node);
+ if (unroll && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_unroll_kind),
+ build_int_cst (integer_type_node, unroll));
}
/* Parse the increment expression (the third expression in a
for-statement). In the case of a foreach-statement, this is
@@ -10833,6 +10856,49 @@ c_parser_objc_at_dynamic_declaration (c_parser *parser)
}
+/* Parse a pragma GCC ivdep. */
+
+static bool
+c_parse_pragma_ivdep (c_parser *parser)
+{
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+ return true;
+}
+
+/* Parse a pragma GCC unroll. */
+
+static unsigned short
+c_parser_pragma_unroll (c_parser *parser)
+{
+ unsigned short unroll;
+ c_parser_consume_pragma (parser);
+ location_t location = c_parser_peek_token (parser)->location;
+ tree expr = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (expr);
+ expr = c_fully_fold (expr, false, NULL);
+ 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;
+ }
+
+ c_parser_skip_to_pragma_eol (parser);
+ return unroll;
+}
+
/* Handle pragmas. Some OpenMP pragmas are associated with, and therefore
should be considered, statements. ALLOW_STMT is true if we're within
the context of a function and such pragmas are to be allowed. Returns
@@ -10975,21 +11041,51 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
return c_parser_omp_ordered (parser, context, if_p);
case PRAGMA_IVDEP:
- c_parser_consume_pragma (parser);
- c_parser_skip_to_pragma_eol (parser);
- if (!c_parser_next_token_is_keyword (parser, RID_FOR)
- && !c_parser_next_token_is_keyword (parser, RID_WHILE)
- && !c_parser_next_token_is_keyword (parser, RID_DO))
- {
- c_parser_error (parser, "for, while or do statement expected");
- return false;
- }
- if (c_parser_next_token_is_keyword (parser, RID_FOR))
- c_parser_for_statement (parser, true, if_p);
- else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
- c_parser_while_statement (parser, true, if_p);
- else
- c_parser_do_statement (parser, true);
+ {
+ const bool ivdep = c_parse_pragma_ivdep (parser);
+ unsigned short unroll;
+ if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_UNROLL)
+ unroll = c_parser_pragma_unroll (parser);
+ else
+ unroll = 0;
+ if (!c_parser_next_token_is_keyword (parser, RID_FOR)
+ && !c_parser_next_token_is_keyword (parser, RID_WHILE)
+ && !c_parser_next_token_is_keyword (parser, RID_DO))
+ {
+ c_parser_error (parser, "for, while or do statement expected");
+ return false;
+ }
+ if (c_parser_next_token_is_keyword (parser, RID_FOR))
+ c_parser_for_statement (parser, ivdep, unroll, if_p);
+ else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
+ c_parser_while_statement (parser, ivdep, unroll, if_p);
+ else
+ c_parser_do_statement (parser, ivdep, unroll);
+ }
+ return false;
+
+ case PRAGMA_UNROLL:
+ {
+ unsigned short unroll = c_parser_pragma_unroll (parser);
+ bool ivdep;
+ if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_IVDEP)
+ ivdep = c_parse_pragma_ivdep (parser);
+ else
+ ivdep = false;
+ if (!c_parser_next_token_is_keyword (parser, RID_FOR)
+ && !c_parser_next_token_is_keyword (parser, RID_WHILE)
+ && !c_parser_next_token_is_keyword (parser, RID_DO))
+ {
+ c_parser_error (parser, "for, while or do statement expected");
+ return false;
+ }
+ if (c_parser_next_token_is_keyword (parser, RID_FOR))
+ c_parser_for_statement (parser, ivdep, unroll, if_p);
+ else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
+ c_parser_while_statement (parser, ivdep, unroll, if_p);
+ else
+ c_parser_do_statement (parser, ivdep, unroll);
+ }
return false;
case PRAGMA_GCC_PCH_PREPROCESS: