@@ -87,6 +87,7 @@ enum pragma_kind {
PRAGMA_GCC_PCH_PREPROCESS,
PRAGMA_IVDEP,
PRAGMA_UNROLL,
+ PRAGMA_INTERLEAVES,
PRAGMA_NOVECTOR,
PRAGMA_FIRST_EXTERNAL
@@ -1828,6 +1828,10 @@ init_pragma (void)
cpp_register_deferred_pragma (parse_in, "GCC", "unroll", PRAGMA_UNROLL,
false, false);
+ if (!flag_preprocess_only)
+ cpp_register_deferred_pragma (parse_in, "GCC", "interleaves", PRAGMA_INTERLEAVES,
+ false, false);
+
if (!flag_preprocess_only)
cpp_register_deferred_pragma (parse_in, "GCC", "novector", PRAGMA_NOVECTOR,
false, false);
@@ -1665,11 +1665,12 @@ 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, unsigned short, bool,
- bool *);
-static void c_parser_do_statement (c_parser *, bool, unsigned short, bool);
-static void c_parser_for_statement (c_parser *, bool, unsigned short, bool,
- bool *);
+static void c_parser_while_statement (c_parser *, bool, unsigned short,
+ unsigned short, bool, bool *);
+static void c_parser_do_statement (c_parser *, bool, unsigned short,
+ unsigned short,bool);
+static void c_parser_for_statement (c_parser *, bool, unsigned short,
+ unsigned short, bool, 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 *);
@@ -7603,13 +7604,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, 0, false, if_p);
+ c_parser_while_statement (parser, false, 0, 0, false, if_p);
break;
case RID_DO:
- c_parser_do_statement (parser, false, 0, false);
+ c_parser_do_statement (parser, false, 0, 0, false);
break;
case RID_FOR:
- c_parser_for_statement (parser, false, 0, false, if_p);
+ c_parser_for_statement (parser, false, 0, 0, false, if_p);
break;
case RID_GOTO:
c_parser_consume_token (parser);
@@ -8105,7 +8106,7 @@ c_parser_switch_statement (c_parser *parser, bool *if_p)
static void
c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll,
- bool novector, bool *if_p)
+ unsigned short interleaves, bool novector, bool *if_p)
{
tree block, cond, body;
unsigned char save_in_statement;
@@ -8135,6 +8136,11 @@ c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll,
build_int_cst (integer_type_node,
annot_expr_unroll_kind),
build_int_cst (integer_type_node, unroll));
+ if (interleaves && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_interleaves_kind),
+ build_int_cst (integer_type_node, interleaves));
if (novector && cond != error_mark_node)
cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
build_int_cst (integer_type_node,
@@ -8172,7 +8178,7 @@ c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll,
static void
c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll,
- bool novector)
+ unsigned short interleaves, bool novector)
{
tree block, cond, body;
unsigned char save_in_statement;
@@ -8209,6 +8215,11 @@ c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll,
build_int_cst (integer_type_node,
annot_expr_unroll_kind),
build_int_cst (integer_type_node, unroll));
+ if (interleaves && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_interleaves_kind),
+ build_int_cst (integer_type_node, interleaves));
if (novector && cond != error_mark_node)
cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
build_int_cst (integer_type_node,
@@ -8282,7 +8293,7 @@ c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll,
static void
c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
- bool novector, bool *if_p)
+ unsigned short interleaves, bool novector, bool *if_p)
{
tree block, cond, incr, body;
unsigned char save_in_statement;
@@ -8424,6 +8435,12 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
"with %<GCC unroll%> pragma");
cond = error_mark_node;
}
+ else if (interleaves)
+ {
+ c_parser_error (parser, "missing loop condition in loop "
+ "with %<GCC interleaves%> pragma");
+ cond = error_mark_node;
+ }
else
{
c_parser_consume_token (parser);
@@ -8446,6 +8463,11 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
build_int_cst (integer_type_node,
annot_expr_unroll_kind),
build_int_cst (integer_type_node, unroll));
+ if (interleaves && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_interleaves_kind),
+ build_int_cst (integer_type_node, interleaves));
if (novector && cond && cond != error_mark_node)
cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
build_int_cst (integer_type_node,
@@ -14466,6 +14488,37 @@ c_parser_pragma_unroll (c_parser *parser)
return unroll;
}
+static unsigned short
+c_parser_pragma_interleaves (c_parser *parser)
+{
+ unsigned short interleaves;
+ 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 linterleaves = 0;
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (expr))
+ || TREE_CODE (expr) != INTEGER_CST
+ || (linterleaves = tree_to_shwi (expr)) < 0
+ || linterleaves >= USHRT_MAX)
+ {
+ error_at (location, "%<#pragma GCC interleaves%> requires an"
+ " assignment-expression that evaluates to a non-negative"
+ " integral constant less than %u", USHRT_MAX);
+ interleaves = 0;
+ }
+ else
+ {
+ interleaves = (unsigned short)linterleaves;
+ if (interleaves == 0)
+ interleaves = 1;
+ }
+
+ c_parser_skip_to_pragma_eol (parser);
+ return interleaves;
+}
+
/* 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
@@ -14674,10 +14727,12 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
case PRAGMA_NOVECTOR:
case PRAGMA_UNROLL:
+ case PRAGMA_INTERLEAVES:
case PRAGMA_IVDEP:
{
bool novector = false;
unsigned short unroll = 0;
+ unsigned short interleaves = 0;
bool ivdep = false;
switch (id)
@@ -14688,6 +14743,9 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
case PRAGMA_UNROLL:
unroll = c_parser_pragma_unroll (parser);
break;
+ case PRAGMA_INTERLEAVES:
+ interleaves = c_parser_pragma_interleaves (parser);
+ break;
case PRAGMA_IVDEP:
ivdep = c_parse_pragma_ivdep (parser);
break;
@@ -14707,6 +14765,9 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
case PRAGMA_UNROLL:
unroll = c_parser_pragma_unroll (parser);
break;
+ case PRAGMA_INTERLEAVES:
+ interleaves = c_parser_pragma_interleaves (parser);
+ break;
case PRAGMA_NOVECTOR:
novector = c_parse_pragma_novector (parser);
break;
@@ -14725,11 +14786,13 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
return false;
}
if (c_parser_next_token_is_keyword (parser, RID_FOR))
- c_parser_for_statement (parser, ivdep, unroll, novector, if_p);
+ c_parser_for_statement (parser, ivdep, unroll, interleaves, novector,
+ if_p);
else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
- c_parser_while_statement (parser, ivdep, unroll, novector, if_p);
+ c_parser_while_statement (parser, ivdep, unroll, interleaves,
+ novector, if_p);
else
- c_parser_do_statement (parser, ivdep, unroll, novector);
+ c_parser_do_statement (parser, ivdep, unroll, interleaves, novector);
}
return true;
@@ -239,6 +239,8 @@ public:
Other values means unroll with the given unrolling factor. */
unsigned short unroll;
+ unsigned short interleaves;
+
/* If this loop was inlined the main clique of the callee which does
not need remapping when copying the loop body. */
unsigned short owned_clique;
@@ -1095,6 +1095,7 @@ copy_loop_info (class loop *loop, class loop *target)
target->in_oacc_kernels_region = loop->in_oacc_kernels_region;
target->finite_p = loop->finite_p;
target->unroll = loop->unroll;
+ target->interleaves = loop->interleaves;
target->owned_clique = loop->owned_clique;
}
@@ -7779,16 +7779,16 @@ extern void begin_else_clause (tree);
extern void finish_else_clause (tree);
extern void finish_if_stmt (tree);
extern tree begin_while_stmt (void);
-extern void finish_while_stmt_cond (tree, tree, bool, tree, bool);
+extern void finish_while_stmt_cond (tree, tree, bool, tree, tree, bool);
extern void finish_while_stmt (tree);
extern tree begin_do_stmt (void);
extern void finish_do_body (tree);
-extern void finish_do_stmt (tree, tree, bool, tree, bool);
+extern void finish_do_stmt (tree, tree, bool, tree, tree, bool);
extern tree finish_return_stmt (tree);
extern tree begin_for_scope (tree *);
extern tree begin_for_stmt (tree, tree);
extern void finish_init_stmt (tree);
-extern void finish_for_cond (tree, tree, bool, tree, bool);
+extern void finish_for_cond (tree, tree, bool, tree, tree, bool);
extern void finish_for_expr (tree, tree);
extern void finish_for_stmt (tree);
extern tree begin_range_for_stmt (tree, tree);
@@ -7990,6 +7990,7 @@ extern tree finish_omp_target (location_t, tree, tree, bool);
extern void finish_omp_target_clauses (location_t, tree, tree *);
extern void maybe_warn_unparenthesized_assignment (tree, bool, tsubst_flags_t);
extern tree cp_check_pragma_unroll (location_t, tree);
+extern tree cp_check_pragma_interleaves (location_t, tree);
/* in tree.cc */
extern int cp_tree_operand_length (const_tree);
@@ -4886,7 +4886,7 @@ build_vec_init (tree base, tree maxindex, tree init,
finish_init_stmt (for_stmt);
finish_for_cond (build2 (GT_EXPR, boolean_type_node, iterator,
build_int_cst (TREE_TYPE (iterator), -1)),
- for_stmt, false, 0, false);
+ for_stmt, false, 0, 0, false);
/* We used to pass this decrement to finish_for_expr; now we add it to
elt_init below so it's part of the same full-expression as the
initialization, and thus happens before any potentially throwing
@@ -1656,7 +1656,7 @@ build_comparison_op (tree fndecl, bool defining, tsubst_flags_t complain)
add_stmt (idx);
finish_init_stmt (for_stmt);
finish_for_cond (build2 (LE_EXPR, boolean_type_node, idx,
- maxval), for_stmt, false, 0,
+ maxval), for_stmt, false, 0, 0,
false);
finish_for_expr (cp_build_unary_op (PREINCREMENT_EXPR,
TARGET_EXPR_SLOT (idx),
@@ -2451,13 +2451,13 @@ static tree cp_parser_selection_statement
static tree cp_parser_condition
(cp_parser *);
static tree cp_parser_iteration_statement
- (cp_parser *, bool *, bool, tree, bool);
+ (cp_parser *, bool *, bool, tree, tree, bool);
static bool cp_parser_init_statement
(cp_parser *, tree *decl);
static tree cp_parser_for
- (cp_parser *, bool, tree, bool);
+ (cp_parser *, bool, tree, tree, tree, bool);
static tree cp_parser_c_for
- (cp_parser *, tree, tree, bool, tree, bool);
+ (cp_parser *, tree, tree, bool, tree, tree, bool);
static tree cp_parser_range_for
(cp_parser *, tree, tree, tree, bool, tree, bool, bool);
static void do_range_for_auto_deduction
@@ -12744,7 +12744,8 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
case RID_FOR:
std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
statement = cp_parser_iteration_statement (parser, if_p, false,
- NULL_TREE, false);
+ NULL_TREE, NULL_TREE,
+ false);
break;
case RID_BREAK:
@@ -14034,7 +14035,8 @@ cp_parser_condition (cp_parser* parser)
not included. */
static tree
-cp_parser_for (cp_parser *parser, bool ivdep, tree unroll, bool novector)
+cp_parser_for (cp_parser *parser, bool ivdep, tree interleaves, tree unroll,
+ bool novector)
{
tree init, scope, decl;
bool is_range_for;
@@ -14062,16 +14064,19 @@ cp_parser_for (cp_parser *parser, bool ivdep, tree unroll, bool novector)
/* Parse the initialization. */
is_range_for = cp_parser_init_statement (parser, &decl);
+ /* TODO: should probably warn when interleaves is being used for a range_for?
+ or should we support that too? */
if (is_range_for)
return cp_parser_range_for (parser, scope, init, decl, ivdep, unroll,
novector, false);
else
- return cp_parser_c_for (parser, scope, init, ivdep, unroll, novector);
+ return cp_parser_c_for (parser, scope, init, ivdep, interleaves, unroll,
+ novector);
}
static tree
cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep,
- tree unroll, bool novector)
+ tree interleaves, tree unroll, bool novector)
{
/* Normal for loop */
tree condition = NULL_TREE;
@@ -14098,7 +14103,13 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep,
"%<GCC unroll%> pragma");
condition = error_mark_node;
}
- finish_for_cond (condition, stmt, ivdep, unroll, novector);
+ else if (interleaves)
+ {
+ cp_parser_error (parser, "missing loop condition in loop with "
+ "%<GCC interleaves%> pragma");
+ condition = error_mark_node;
+ }
+ finish_for_cond (condition, stmt, ivdep, interleaves, unroll, novector);
/* Look for the `;'. */
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
@@ -14444,7 +14455,7 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
begin, ERROR_MARK,
end, ERROR_MARK,
NULL_TREE, NULL, tf_warning_or_error);
- finish_for_cond (condition, statement, ivdep, unroll, novector);
+ finish_for_cond (condition, statement, ivdep, NULL_TREE, unroll, novector);
/* The new increment expression. */
expression = finish_unary_op_expr (input_location,
@@ -14608,7 +14619,7 @@ cp_parser_range_for_member_function (tree range, tree identifier)
static tree
cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep,
- tree unroll, bool novector)
+ tree interleaves, tree unroll, bool novector)
{
cp_token *token;
enum rid keyword;
@@ -14651,7 +14662,8 @@ 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, unroll, novector);
+ finish_while_stmt_cond (condition, statement, ivdep, interleaves,
+ unroll, novector);
/* Look for the `)'. */
parens.require_close (parser);
/* Parse the dependent statement. */
@@ -14686,7 +14698,8 @@ 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, unroll, novector);
+ finish_do_stmt (expression, statement, ivdep, interleaves, unroll,
+ novector);
/* Look for the `)'. */
parens.require_close (parser);
/* Look for the `;'. */
@@ -14700,7 +14713,8 @@ 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, unroll, novector);
+ statement = cp_parser_for (parser, ivdep, interleaves, unroll,
+ novector);
/* Look for the `)'. */
parens.require_close (parser);
@@ -51015,6 +51029,20 @@ cp_parser_pragma_unroll (cp_parser *parser, cp_token *pragma_tok)
return unroll;
}
+/* Parse a pragma GCC interleaves. */
+
+static tree
+cp_parser_pragma_interleaves (cp_parser *parser, cp_token *pragma_tok)
+{
+ location_t location = cp_lexer_peek_token (parser->lexer)->location;
+ tree interleaves = cp_parser_constant_expression (parser);
+ interleaves
+ = cp_check_pragma_interleaves (location,
+ fold_non_dependent_expr (interleaves));
+ cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ return interleaves;
+}
+
/* Parse a pragma GCC novector. */
static bool
@@ -51341,10 +51369,12 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
case PRAGMA_IVDEP:
case PRAGMA_UNROLL:
+ case PRAGMA_INTERLEAVES:
case PRAGMA_NOVECTOR:
{
bool ivdep = false;
tree unroll = NULL_TREE;
+ tree interleaves = NULL_TREE;
bool novector = false;
const char *pragma_str;
@@ -51356,6 +51386,9 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
case PRAGMA_UNROLL:
pragma_str = "unroll";
break;
+ case PRAGMA_INTERLEAVES:
+ pragma_str = "interleaves";
+ break;
case PRAGMA_NOVECTOR:
pragma_str = "novector";
break;
@@ -51391,6 +51424,13 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
unroll = cp_parser_pragma_unroll (parser, tok);
break;
}
+ case PRAGMA_INTERLEAVES:
+ {
+ if (tok != pragma_tok)
+ tok = cp_lexer_consume_token (parser->lexer);
+ interleaves = cp_parser_pragma_interleaves (parser, tok);
+ break;
+ }
case PRAGMA_NOVECTOR:
{
if (tok != pragma_tok)
@@ -51415,7 +51455,8 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
cp_parser_error (parser, "for, while or do statement expected");
return false;
}
- cp_parser_iteration_statement (parser, if_p, ivdep, unroll, novector);
+ cp_parser_iteration_statement (parser, if_p, ivdep, interleaves, unroll,
+ novector);
return true;
}
@@ -18638,7 +18638,7 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
RECUR (FOR_INIT_STMT (t));
finish_init_stmt (stmt);
tmp = RECUR (FOR_COND (t));
- finish_for_cond (tmp, stmt, false, 0, false);
+ finish_for_cond (tmp, stmt, false, 0, 0, false);
tmp = RECUR (FOR_EXPR (t));
finish_for_expr (tmp, stmt);
{
@@ -18701,7 +18701,7 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
case WHILE_STMT:
stmt = begin_while_stmt ();
tmp = RECUR (WHILE_COND (t));
- finish_while_stmt_cond (tmp, stmt, false, 0, false);
+ finish_while_stmt_cond (tmp, stmt, false, 0, 0, false);
{
bool prev = note_iteration_stmt_body_start ();
RECUR (WHILE_BODY (t));
@@ -18719,7 +18719,7 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
}
finish_do_body (stmt);
tmp = RECUR (DO_COND (t));
- finish_do_stmt (tmp, stmt, false, 0, false);
+ finish_do_stmt (tmp, stmt, false, 0, 0, false);
break;
case IF_STMT:
@@ -19470,10 +19470,18 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
tree op1 = RECUR (TREE_OPERAND (t, 0));
tree op2 = tsubst_expr (TREE_OPERAND (t, 1), args, complain, in_decl);
tree op3 = tsubst_expr (TREE_OPERAND (t, 2), args, complain, in_decl);
- if (TREE_CODE (op2) == INTEGER_CST
- && wi::to_widest (op2) == (int) annot_expr_unroll_kind)
- op3 = cp_check_pragma_unroll (EXPR_LOCATION (TREE_OPERAND (t, 2)),
- op3);
+
+ if (TREE_CODE (op2) == INTEGER_CST)
+ {
+ if (wi::to_widest (op2) == (int) annot_expr_unroll_kind)
+ op3 = cp_check_pragma_unroll (EXPR_LOCATION (TREE_OPERAND (t, 2)),
+ op3);
+ else if (wi::to_widest (op2) == (int) annot_expr_interleaves_kind)
+ {
+ location_t loc = EXPR_LOCATION (TREE_OPERAND (t, 2));
+ op3 = cp_check_pragma_interleaves (loc, op3);
+ }
+ }
RETURN (build3_loc (EXPR_LOCATION (t), ANNOTATE_EXPR,
TREE_TYPE (op1), op1, op2, op3));
}
@@ -1284,7 +1284,7 @@ begin_while_stmt (void)
void
finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep,
- tree unroll, bool novector)
+ tree interleaves, tree unroll, bool novector)
{
cond = maybe_convert_cond (cond);
finish_cond (&WHILE_COND (while_stmt), cond);
@@ -1303,6 +1303,13 @@ finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep,
build_int_cst (integer_type_node,
annot_expr_unroll_kind),
unroll);
+ if (interleaves && cond != error_mark_node)
+ WHILE_COND (while_stmt)
+ = build3 (ANNOTATE_EXPR,
+ TREE_TYPE (WHILE_COND (while_stmt)),
+ WHILE_COND (while_stmt),
+ build_int_cst (integer_type_node, annot_expr_interleaves_kind),
+ interleaves);
if (novector && cond != error_mark_node)
WHILE_COND (while_stmt) = build3 (ANNOTATE_EXPR,
TREE_TYPE (WHILE_COND (while_stmt)),
@@ -1356,7 +1363,7 @@ finish_do_body (tree do_stmt)
void
finish_do_stmt (tree cond, tree do_stmt, bool ivdep, tree unroll,
- bool novector)
+ tree interleaves, bool novector)
{
cond = maybe_convert_cond (cond);
end_maybe_infinite_loop (cond);
@@ -1373,6 +1380,10 @@ finish_do_stmt (tree cond, tree do_stmt, bool ivdep, tree unroll,
cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
build_int_cst (integer_type_node, annot_expr_unroll_kind),
unroll);
+ if (interleaves && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node, annot_expr_interleaves_kind),
+ interleaves);
if (novector && cond != error_mark_node)
cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
build_int_cst (integer_type_node, annot_expr_no_vector_kind),
@@ -1481,8 +1492,8 @@ finish_init_stmt (tree for_stmt)
FOR_STMT. */
void
-finish_for_cond (tree cond, tree for_stmt, bool ivdep, tree unroll,
- bool novector)
+finish_for_cond (tree cond, tree for_stmt, bool ivdep, tree interleaves,
+ tree unroll, bool novector)
{
cond = maybe_convert_cond (cond);
finish_cond (&FOR_COND (for_stmt), cond);
@@ -1494,6 +1505,13 @@ finish_for_cond (tree cond, tree for_stmt, bool ivdep, tree unroll,
build_int_cst (integer_type_node,
annot_expr_ivdep_kind),
integer_zero_node);
+ if (interleaves && cond != error_mark_node)
+ FOR_COND (for_stmt) = build3 (ANNOTATE_EXPR,
+ TREE_TYPE (FOR_COND (for_stmt)),
+ FOR_COND (for_stmt),
+ build_int_cst (integer_type_node,
+ annot_expr_interleaves_kind),
+ interleaves);
if (unroll && cond != error_mark_node)
FOR_COND (for_stmt) = build3 (ANNOTATE_EXPR,
TREE_TYPE (FOR_COND (for_stmt)),
@@ -13342,6 +13360,36 @@ cp_build_bit_cast (location_t loc, tree type, tree arg,
return ret;
}
+/* Diagnose invalid #pragma GCC interleaves argument and adjust
+ it if needed. */
+
+tree
+cp_check_pragma_interleaves (location_t loc, tree value)
+{
+ HOST_WIDE_INT lvalue = 0;
+ if (type_dependent_expression_p (value))
+ ;
+ else if (!INTEGRAL_TYPE_P (TREE_TYPE (value))
+ || (!value_dependent_expression_p (value)
+ && (!tree_fits_shwi_p (value)
+ || (lvalue = tree_to_shwi (value)) < 0
+ || lvalue >= USHRT_MAX
+ || (lvalue % 2 != 0))))
+ {
+ error_at (loc, "%<#pragma GCC interleaves%> requires an"
+ " assignment-expression that evaluates to a non-negative"
+ " power of two integral constant less than %u", USHRT_MAX);
+ value = NULL_TREE;
+ }
+ else if (TREE_CODE (value) == INTEGER_CST)
+ {
+ value = fold_convert (integer_type_node, value);
+ if (integer_zerop (value))
+ value = integer_one_node;
+ }
+ return value;
+}
+
/* Diagnose invalid #pragma GCC unroll argument and adjust
it if needed. */
@@ -4582,6 +4582,7 @@ gimple_boolify (tree expr)
{
case annot_expr_ivdep_kind:
case annot_expr_unroll_kind:
+ case annot_expr_interleaves_kind:
case annot_expr_no_vector_kind:
case annot_expr_vector_kind:
case annot_expr_parallel_kind:
@@ -541,6 +541,8 @@ func_checker::compare_loops (basic_block bb1, basic_block bb2)
return return_false_with_msg ("finite_p");
if (l1->unroll != l2->unroll)
return return_false_with_msg ("unroll");
+ if (l1->interleaves != l2->interleaves)
+ return return_false_with_msg ("interleaves");
if (!compare_variable_decl (l1->simduid, l2->simduid))
return return_false_with_msg ("simduid");
@@ -286,6 +286,10 @@ replace_loop_annotate_in_block (basic_block bb, class loop *loop)
= (unsigned short) tree_to_shwi (gimple_call_arg (stmt, 2));
cfun->has_unroll = true;
break;
+ case annot_expr_interleaves_kind:
+ loop->interleaves
+ = (unsigned short) tree_to_shwi (gimple_call_arg (stmt, 2));
+ break;
case annot_expr_no_vector_kind:
loop->dont_vectorize = true;
break;
@@ -347,6 +351,7 @@ replace_loop_annotate (void)
{
case annot_expr_ivdep_kind:
case annot_expr_unroll_kind:
+ case annot_expr_interleaves_kind:
case annot_expr_no_vector_kind:
case annot_expr_vector_kind:
case annot_expr_parallel_kind:
@@ -980,6 +980,7 @@ enum tree_node_kind {
enum annot_expr_kind {
annot_expr_ivdep_kind,
annot_expr_unroll_kind,
+ annot_expr_interleaves_kind,
annot_expr_no_vector_kind,
annot_expr_vector_kind,
annot_expr_parallel_kind,
@@ -3454,8 +3454,12 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
pp_string (pp, ", ivdep");
break;
case annot_expr_unroll_kind:
+ case annot_expr_interleaves_kind:
{
- pp_string (pp, ", unroll ");
+ pp_string (pp,
+ annot_expr_unroll_kind
+ ? ", unroll "
+ : ", interleaves ");
pp_decimal_int (pp,
(int) TREE_INT_CST_LOW (TREE_OPERAND (node, 2)));
break;
@@ -5008,6 +5008,9 @@ vect_estimate_min_profitable_iters (loop_vec_info loop_vinfo,
&vec_prologue_cost, &vec_inside_cost, &vec_epilogue_cost,
suggested_unroll_factor);
+ if (suggested_unroll_factor && loop_vinfo->loop->interleaves > 0)
+ *suggested_unroll_factor = loop_vinfo->loop->interleaves;
+
if (suggested_unroll_factor && *suggested_unroll_factor > 1
&& LOOP_VINFO_MAX_VECT_FACTOR (loop_vinfo) != MAX_VECTORIZATION_FACTOR
&& !known_le (LOOP_VINFO_VECT_FACTOR (loop_vinfo) *