frontend: Add novector C++ pragma
FORTRAN currently has a pragma NOVECTOR for indicating that vectorization should not be applied to a particular loop. ICC/ICX also has such a pragma for C and C++ called #pragma novector. As part of this patch series I need a way to easily turn off vectorization of particular loops, particularly for testsuite reasons. This patch proposes a #pragma GCC novector that does the same for C++ as gfortan does for FORTRAN and what ICX/ICX does for C++. I added only some basic tests here, but the next patch in the series uses this in the testsuite in about ~800 tests. gcc/cp/ChangeLog: * cp-tree.h (RANGE_FOR_NOVECTOR): New. (cp_convert_range_for, finish_while_stmt_cond, finish_do_stmt, finish_for_cond): Add novector param. * init.cc (build_vec_init): Default novector to false. * method.cc (build_comparison_op): Likewise. * parser.cc (cp_parser_statement): Likewise. (cp_parser_for, cp_parser_c_for, cp_parser_range_for, cp_convert_range_for, cp_parser_iteration_statement, cp_parser_omp_for_loop, cp_parser_pragma): Support novector. (cp_parser_pragma_novector): New. * pt.cc (tsubst_expr): Likewise. * semantics.cc (finish_while_stmt_cond, finish_do_stmt, finish_for_cond): Likewise. gcc/ChangeLog: * doc/extend.texi: Document it. gcc/testsuite/ChangeLog: * g++.dg/vect/vect.exp (support vect- prefix). * g++.dg/vect/vect-novector-pragma.cc: New test.
This commit is contained in:
parent
451391a647
commit
73b9886076
9 changed files with 219 additions and 76 deletions
|
@ -5393,6 +5393,7 @@ get_vec_init_expr (tree t)
|
|||
#define RANGE_FOR_UNROLL(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 4)
|
||||
#define RANGE_FOR_INIT_STMT(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 5)
|
||||
#define RANGE_FOR_IVDEP(NODE) TREE_LANG_FLAG_6 (RANGE_FOR_STMT_CHECK (NODE))
|
||||
#define RANGE_FOR_NOVECTOR(NODE) TREE_LANG_FLAG_5 (RANGE_FOR_STMT_CHECK (NODE))
|
||||
|
||||
/* STMT_EXPR accessor. */
|
||||
#define STMT_EXPR_STMT(NODE) TREE_OPERAND (STMT_EXPR_CHECK (NODE), 0)
|
||||
|
@ -7310,7 +7311,7 @@ extern bool maybe_clone_body (tree);
|
|||
|
||||
/* In parser.cc */
|
||||
extern tree cp_convert_range_for (tree, tree, tree, tree, unsigned int, bool,
|
||||
unsigned short);
|
||||
unsigned short, bool);
|
||||
extern void cp_convert_omp_range_for (tree &, vec<tree, va_gc> *, tree &,
|
||||
tree &, tree &, tree &, tree &, tree &);
|
||||
extern void cp_finish_omp_range_for (tree, tree);
|
||||
|
@ -7633,16 +7634,19 @@ 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, unsigned short);
|
||||
extern void finish_while_stmt_cond (tree, tree, bool, unsigned short,
|
||||
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, unsigned short);
|
||||
extern void finish_do_stmt (tree, tree, bool, unsigned short,
|
||||
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, unsigned short);
|
||||
extern void finish_for_cond (tree, tree, bool, unsigned short,
|
||||
bool);
|
||||
extern void finish_for_expr (tree, tree);
|
||||
extern void finish_for_stmt (tree);
|
||||
extern tree begin_range_for_stmt (tree, tree);
|
||||
|
|
|
@ -4853,7 +4853,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);
|
||||
for_stmt, false, 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
|
||||
|
|
|
@ -1645,7 +1645,8 @@ 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,
|
||||
false);
|
||||
finish_for_expr (cp_build_unary_op (PREINCREMENT_EXPR,
|
||||
TARGET_EXPR_SLOT (idx),
|
||||
false, complain),
|
||||
|
|
153
gcc/cp/parser.cc
153
gcc/cp/parser.cc
|
@ -2333,15 +2333,15 @@ static tree cp_parser_selection_statement
|
|||
static tree cp_parser_condition
|
||||
(cp_parser *);
|
||||
static tree cp_parser_iteration_statement
|
||||
(cp_parser *, bool *, bool, unsigned short);
|
||||
(cp_parser *, bool *, bool, unsigned short, bool);
|
||||
static bool cp_parser_init_statement
|
||||
(cp_parser *, tree *decl);
|
||||
static tree cp_parser_for
|
||||
(cp_parser *, bool, unsigned short);
|
||||
(cp_parser *, bool, unsigned short, bool);
|
||||
static tree cp_parser_c_for
|
||||
(cp_parser *, tree, tree, bool, unsigned short);
|
||||
(cp_parser *, tree, tree, bool, unsigned short, bool);
|
||||
static tree cp_parser_range_for
|
||||
(cp_parser *, tree, tree, tree, bool, unsigned short, bool);
|
||||
(cp_parser *, tree, tree, tree, bool, unsigned short, bool, bool);
|
||||
static void do_range_for_auto_deduction
|
||||
(tree, tree, tree, unsigned int);
|
||||
static tree cp_parser_perform_range_for_lookup
|
||||
|
@ -12422,7 +12422,8 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
|
|||
case RID_DO:
|
||||
case RID_FOR:
|
||||
std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
|
||||
statement = cp_parser_iteration_statement (parser, if_p, false, 0);
|
||||
statement = cp_parser_iteration_statement (parser, if_p, false, 0,
|
||||
false);
|
||||
break;
|
||||
|
||||
case RID_BREAK:
|
||||
|
@ -13602,7 +13603,8 @@ cp_parser_condition (cp_parser* parser)
|
|||
not included. */
|
||||
|
||||
static tree
|
||||
cp_parser_for (cp_parser *parser, bool ivdep, unsigned short unroll)
|
||||
cp_parser_for (cp_parser *parser, bool ivdep, unsigned short unroll,
|
||||
bool novector)
|
||||
{
|
||||
tree init, scope, decl;
|
||||
bool is_range_for;
|
||||
|
@ -13632,14 +13634,14 @@ cp_parser_for (cp_parser *parser, bool ivdep, unsigned short unroll)
|
|||
|
||||
if (is_range_for)
|
||||
return cp_parser_range_for (parser, scope, init, decl, ivdep, unroll,
|
||||
false);
|
||||
novector, false);
|
||||
else
|
||||
return cp_parser_c_for (parser, scope, init, ivdep, unroll);
|
||||
return cp_parser_c_for (parser, scope, init, ivdep, unroll, novector);
|
||||
}
|
||||
|
||||
static tree
|
||||
cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep,
|
||||
unsigned short unroll)
|
||||
unsigned short unroll, bool novector)
|
||||
{
|
||||
/* Normal for loop */
|
||||
tree condition = NULL_TREE;
|
||||
|
@ -13666,7 +13668,7 @@ 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);
|
||||
finish_for_cond (condition, stmt, ivdep, unroll, novector);
|
||||
/* Look for the `;'. */
|
||||
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
|
||||
|
||||
|
@ -13690,7 +13692,8 @@ 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, unsigned short unroll, bool is_omp)
|
||||
bool ivdep, unsigned short unroll, bool novector,
|
||||
bool is_omp)
|
||||
{
|
||||
tree stmt, range_expr;
|
||||
auto_vec <cxx_binding *, 16> bindings;
|
||||
|
@ -13766,6 +13769,8 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
|
|||
RANGE_FOR_IVDEP (stmt) = 1;
|
||||
if (unroll)
|
||||
RANGE_FOR_UNROLL (stmt) = build_int_cst (integer_type_node, unroll);
|
||||
if (novector)
|
||||
RANGE_FOR_NOVECTOR (stmt) = 1;
|
||||
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. */
|
||||
|
@ -13778,7 +13783,7 @@ 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,
|
||||
unroll);
|
||||
unroll, novector);
|
||||
}
|
||||
return stmt;
|
||||
}
|
||||
|
@ -13956,7 +13961,7 @@ warn_for_range_copy (tree decl, tree expr)
|
|||
tree
|
||||
cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
|
||||
tree decomp_first_name, unsigned int decomp_cnt,
|
||||
bool ivdep, unsigned short unroll)
|
||||
bool ivdep, unsigned short unroll, bool novector)
|
||||
{
|
||||
tree begin, end;
|
||||
tree iter_type, begin_expr, end_expr;
|
||||
|
@ -14016,7 +14021,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);
|
||||
finish_for_cond (condition, statement, ivdep, unroll, novector);
|
||||
|
||||
/* The new increment expression. */
|
||||
expression = finish_unary_op_expr (input_location,
|
||||
|
@ -14183,7 +14188,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,
|
||||
unsigned short unroll)
|
||||
unsigned short unroll, bool novector)
|
||||
{
|
||||
cp_token *token;
|
||||
enum rid keyword;
|
||||
|
@ -14217,7 +14222,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, unroll);
|
||||
finish_while_stmt_cond (condition, statement, ivdep, unroll, novector);
|
||||
/* Look for the `)'. */
|
||||
parens.require_close (parser);
|
||||
/* Parse the dependent statement. */
|
||||
|
@ -14252,7 +14257,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, unroll);
|
||||
finish_do_stmt (expression, statement, ivdep, unroll, novector);
|
||||
/* Look for the `)'. */
|
||||
parens.require_close (parser);
|
||||
/* Look for the `;'. */
|
||||
|
@ -14266,7 +14271,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, unroll);
|
||||
statement = cp_parser_for (parser, ivdep, unroll, novector);
|
||||
|
||||
/* Look for the `)'. */
|
||||
parens.require_close (parser);
|
||||
|
@ -43828,7 +43833,7 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses,
|
|||
cp_parser_require (parser, CPP_COLON, RT_COLON);
|
||||
|
||||
init = cp_parser_range_for (parser, NULL_TREE, NULL_TREE, decl,
|
||||
false, 0, true);
|
||||
false, 0, false, true);
|
||||
|
||||
cp_convert_omp_range_for (this_pre_body, for_block, decl,
|
||||
orig_decl, init, orig_init,
|
||||
|
@ -49320,6 +49325,15 @@ cp_parser_pragma_unroll (cp_parser *parser, cp_token *pragma_tok)
|
|||
return unroll;
|
||||
}
|
||||
|
||||
/* Parse a pragma GCC novector. */
|
||||
|
||||
static bool
|
||||
cp_parser_pragma_novector (cp_parser *parser, cp_token *pragma_tok)
|
||||
{
|
||||
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Normal parsing of a pragma token. Here we can (and must) use the
|
||||
regular lexer. */
|
||||
|
||||
|
@ -49625,58 +49639,73 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
|
|||
break;
|
||||
|
||||
case PRAGMA_IVDEP:
|
||||
{
|
||||
if (context == pragma_external)
|
||||
{
|
||||
error_at (pragma_tok->location,
|
||||
"%<#pragma GCC ivdep%> must be inside a function");
|
||||
break;
|
||||
}
|
||||
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:
|
||||
case PRAGMA_NOVECTOR:
|
||||
{
|
||||
bool ivdep;
|
||||
unsigned short unroll = 0;
|
||||
bool novector = false;
|
||||
const char *pragma_str;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case PRAGMA_IVDEP:
|
||||
pragma_str = "ivdep";
|
||||
break;
|
||||
case PRAGMA_UNROLL:
|
||||
pragma_str = "unroll";
|
||||
break;
|
||||
case PRAGMA_NOVECTOR:
|
||||
pragma_str = "novector";
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
if (context == pragma_external)
|
||||
{
|
||||
error_at (pragma_tok->location,
|
||||
"%<#pragma GCC unroll%> must be inside a function");
|
||||
"%<#pragma GCC %s%> must be inside a function",
|
||||
pragma_str);
|
||||
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)
|
||||
|
||||
cp_token *tok = pragma_tok;
|
||||
bool has_more = true;
|
||||
do
|
||||
{
|
||||
tok = cp_lexer_consume_token (parser->lexer);
|
||||
ivdep = cp_parser_pragma_ivdep (parser, tok);
|
||||
switch (cp_parser_pragma_kind (tok))
|
||||
{
|
||||
case PRAGMA_IVDEP:
|
||||
{
|
||||
if (tok != pragma_tok)
|
||||
tok = cp_lexer_consume_token (parser->lexer);
|
||||
ivdep = cp_parser_pragma_ivdep (parser, tok);
|
||||
break;
|
||||
}
|
||||
case PRAGMA_UNROLL:
|
||||
{
|
||||
if (tok != pragma_tok)
|
||||
tok = cp_lexer_consume_token (parser->lexer);
|
||||
unroll = cp_parser_pragma_unroll (parser, tok);
|
||||
break;
|
||||
}
|
||||
case PRAGMA_NOVECTOR:
|
||||
{
|
||||
if (tok != pragma_tok)
|
||||
tok = cp_lexer_consume_token (parser->lexer);
|
||||
novector = cp_parser_pragma_novector (parser, tok);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
has_more = false;
|
||||
break;
|
||||
}
|
||||
tok = cp_lexer_peek_token (the_parser->lexer);
|
||||
has_more = has_more && tok->type == CPP_PRAGMA;
|
||||
}
|
||||
else
|
||||
ivdep = false;
|
||||
while (has_more);
|
||||
|
||||
if (tok->type != CPP_KEYWORD
|
||||
|| (tok->keyword != RID_FOR
|
||||
&& tok->keyword != RID_WHILE
|
||||
|
@ -49685,7 +49714,7 @@ 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);
|
||||
cp_parser_iteration_statement (parser, if_p, ivdep, unroll, novector);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
10
gcc/cp/pt.cc
10
gcc/cp/pt.cc
|
@ -19094,7 +19094,7 @@ tsubst_expr (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);
|
||||
finish_for_cond (tmp, stmt, false, 0, false);
|
||||
tmp = RECUR (FOR_EXPR (t));
|
||||
finish_for_expr (tmp, stmt);
|
||||
{
|
||||
|
@ -19131,6 +19131,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
{
|
||||
RANGE_FOR_IVDEP (stmt) = RANGE_FOR_IVDEP (t);
|
||||
RANGE_FOR_UNROLL (stmt) = RANGE_FOR_UNROLL (t);
|
||||
RANGE_FOR_NOVECTOR (stmt) = RANGE_FOR_NOVECTOR (t);
|
||||
finish_range_for_decl (stmt, decl, expr);
|
||||
if (decomp_first && decl != error_mark_node)
|
||||
cp_finish_decomp (decl, decomp_first, decomp_cnt);
|
||||
|
@ -19141,7 +19142,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
? tree_to_uhwi (RANGE_FOR_UNROLL (t)) : 0);
|
||||
stmt = cp_convert_range_for (stmt, decl, expr,
|
||||
decomp_first, decomp_cnt,
|
||||
RANGE_FOR_IVDEP (t), unroll);
|
||||
RANGE_FOR_IVDEP (t), unroll,
|
||||
RANGE_FOR_NOVECTOR (t));
|
||||
}
|
||||
|
||||
bool prev = note_iteration_stmt_body_start ();
|
||||
|
@ -19154,7 +19156,7 @@ tsubst_expr (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);
|
||||
finish_while_stmt_cond (tmp, stmt, false, 0, false);
|
||||
{
|
||||
bool prev = note_iteration_stmt_body_start ();
|
||||
RECUR (WHILE_BODY (t));
|
||||
|
@ -19172,7 +19174,7 @@ tsubst_expr (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);
|
||||
finish_do_stmt (tmp, stmt, false, 0, false);
|
||||
break;
|
||||
|
||||
case IF_STMT:
|
||||
|
|
|
@ -1148,7 +1148,7 @@ begin_while_stmt (void)
|
|||
|
||||
void
|
||||
finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep,
|
||||
unsigned short unroll)
|
||||
unsigned short unroll, bool novector)
|
||||
{
|
||||
cond = maybe_convert_cond (cond);
|
||||
finish_cond (&WHILE_COND (while_stmt), cond);
|
||||
|
@ -1168,6 +1168,13 @@ finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep,
|
|||
annot_expr_unroll_kind),
|
||||
build_int_cst (integer_type_node,
|
||||
unroll));
|
||||
if (novector && 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_no_vector_kind),
|
||||
integer_zero_node);
|
||||
simplify_loop_decl_cond (&WHILE_COND (while_stmt), WHILE_BODY (while_stmt));
|
||||
}
|
||||
|
||||
|
@ -1212,7 +1219,8 @@ finish_do_body (tree do_stmt)
|
|||
COND is as indicated. */
|
||||
|
||||
void
|
||||
finish_do_stmt (tree cond, tree do_stmt, bool ivdep, unsigned short unroll)
|
||||
finish_do_stmt (tree cond, tree do_stmt, bool ivdep, unsigned short unroll,
|
||||
bool novector)
|
||||
{
|
||||
cond = maybe_convert_cond (cond);
|
||||
end_maybe_infinite_loop (cond);
|
||||
|
@ -1229,6 +1237,10 @@ finish_do_stmt (tree cond, tree do_stmt, bool ivdep, unsigned short unroll)
|
|||
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 (novector && cond != error_mark_node)
|
||||
cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
|
||||
build_int_cst (integer_type_node, annot_expr_no_vector_kind),
|
||||
integer_zero_node);
|
||||
DO_COND (do_stmt) = cond;
|
||||
}
|
||||
|
||||
|
@ -1327,7 +1339,7 @@ finish_init_stmt (tree for_stmt)
|
|||
FOR_STMT. */
|
||||
|
||||
void
|
||||
finish_for_cond (tree cond, tree for_stmt, bool ivdep, unsigned short unroll)
|
||||
finish_for_cond (tree cond, tree for_stmt, bool ivdep, unsigned short unroll, bool novector)
|
||||
{
|
||||
cond = maybe_convert_cond (cond);
|
||||
finish_cond (&FOR_COND (for_stmt), cond);
|
||||
|
@ -1347,6 +1359,13 @@ finish_for_cond (tree cond, tree for_stmt, bool ivdep, unsigned short unroll)
|
|||
annot_expr_unroll_kind),
|
||||
build_int_cst (integer_type_node,
|
||||
unroll));
|
||||
if (novector && 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_no_vector_kind),
|
||||
integer_zero_node);
|
||||
simplify_loop_decl_cond (&FOR_COND (for_stmt), FOR_BODY (for_stmt));
|
||||
}
|
||||
|
||||
|
|
|
@ -24581,6 +24581,25 @@ void ignore_vec_dep (int *a, int k, int c, int m)
|
|||
@}
|
||||
@end smallexample
|
||||
|
||||
@cindex pragma GCC novector
|
||||
@item #pragma GCC novector
|
||||
|
||||
With this pragma, the programmer asserts that the following loop should be
|
||||
prevented from executing concurrently with SIMD (single instruction multiple
|
||||
data) instructions.
|
||||
|
||||
For example, the compiler cannot vectorize the following loop with the pragma:
|
||||
|
||||
@smallexample
|
||||
void foo (int n, int *a, int *b, int *c)
|
||||
@{
|
||||
int i, j;
|
||||
#pragma GCC novector
|
||||
for (i = 0; i < n; ++i)
|
||||
a[i] = b[i] + c[i];
|
||||
@}
|
||||
@end smallexample
|
||||
|
||||
@cindex pragma GCC unroll @var{n}
|
||||
@item #pragma GCC unroll @var{n}
|
||||
|
||||
|
|
69
gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc
Normal file
69
gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-require-effective-target vect_int } */
|
||||
|
||||
#include <vector>
|
||||
|
||||
void f4 (std::vector<int> a, std::vector<int> b, int n)
|
||||
{
|
||||
int i = 0;
|
||||
#pragma GCC novector
|
||||
while (i < (n & -8))
|
||||
{
|
||||
a[i] += b[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void f5 (std::vector<int> a, std::vector<int> b, int n)
|
||||
{
|
||||
int i = 0;
|
||||
#pragma GCC novector
|
||||
#pragma GCC ivdep
|
||||
#pragma GCC unroll 2
|
||||
while (i < (n & -8))
|
||||
{
|
||||
a[i] += b[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void f6 (std::vector<int> a, std::vector<int> b, int n)
|
||||
{
|
||||
int i = 0;
|
||||
#pragma GCC ivdep
|
||||
#pragma GCC novector
|
||||
#pragma GCC unroll 2
|
||||
while (i < (n & -8))
|
||||
{
|
||||
a[i] += b[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void f7 (std::vector<int> a, std::vector<int> b, int n)
|
||||
{
|
||||
int i = 0;
|
||||
#pragma GCC ivdep
|
||||
#pragma GCC unroll 2
|
||||
#pragma GCC novector
|
||||
while (i < (n & -8))
|
||||
{
|
||||
a[i] += b[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
#if __cpp_range_based_for
|
||||
void f8 (std::vector<int> a, std::vector<int> b, int n)
|
||||
{
|
||||
int i = 0;
|
||||
#pragma GCC novector
|
||||
for (int x : b)
|
||||
{
|
||||
a[i] += x;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */
|
|
@ -64,7 +64,7 @@ dg-init
|
|||
|
||||
# Main loop.
|
||||
et-dg-runtest g++-dg-runtest [lsort [glob -nocomplain \
|
||||
$srcdir/$subdir/{pr,simd}*.{c,cc,S} ]] "" $DEFAULT_VECTCFLAGS
|
||||
$srcdir/$subdir/{pr,simd,vect-}*.{c,cc,S} ]] "" $DEFAULT_VECTCFLAGS
|
||||
et-dg-runtest g++-dg-runtest [lsort [glob -nocomplain \
|
||||
$srcdir/$subdir/slp-pr*.{c,cc,S} ]] "" $VECT_SLP_CFLAGS
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue