* [PATCH 1/2][frontend] Add novector C++ pragma
@ 2023-07-19 15:15 Tamar Christina
2023-07-19 15:16 ` [PATCH 2/2][frontend]: Add novector C pragma Tamar Christina
2023-07-25 20:53 ` [PATCH 1/2][frontend] Add novector C++ pragma Jason Merrill
0 siblings, 2 replies; 8+ messages in thread
From: Tamar Christina @ 2023-07-19 15:15 UTC (permalink / raw)
To: gcc-patches; +Cc: nd, jason, nathan
[-- Attachment #1: Type: text/plain, Size: 24416 bytes --]
Hi All,
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.
Bootstrapped Regtested on aarch64-none-linux-gnu and no issues.
Ok for master?
Thanks,
Tamar
gcc/cp/ChangeLog:
* cp-tree.def (RANGE_FOR_STMT): Update comment.
* 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.
--- inline copy of patch --
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 0e66ca70e00caa1dc4beada1024ace32954e2aaf..c13c8ea98a523c4ef1c55a11e02d5da9db7e367e 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -305,8 +305,8 @@ DEFTREECODE (IF_STMT, "if_stmt", tcc_statement, 4)
/* Used to represent a range-based `for' statement. The operands are
RANGE_FOR_DECL, RANGE_FOR_EXPR, RANGE_FOR_BODY, RANGE_FOR_SCOPE,
- RANGE_FOR_UNROLL, and RANGE_FOR_INIT_STMT, respectively. Only used in
- templates. */
+ RANGE_FOR_UNROLL, RANGE_FOR_NOVECTOR and RANGE_FOR_INIT_STMT,
+ respectively. Only used in templates. */
DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 6)
/* Used to represent an expression statement. Use `EXPR_STMT_EXPR' to
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8398223311194837441107cb335d497ff5f5ec1c..bece7bff1f01a23cfc94386fd3295a0be8c462fe 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5377,6 +5377,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)
@@ -7286,7 +7287,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);
@@ -7609,16 +7610,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);
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index af6e30f511e142c7a594e742d128b2bf0aa8fb8d..5b735b27e6f5bc6b439ae64665902f4f1ca76f95 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4846,7 +4846,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
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 91cf943f11089c0e6bcbe8377daa4e016f956d56..fce49c796199c2c65cd70684e2942fea1b6b2ebd 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -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),
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index dd3665c8ccf48a8a0b1ba2c06400fe50999ea240..8776e8f4cf8266ee715c3e7f943602fdb1acaf79 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -2324,15 +2324,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
@@ -12414,7 +12414,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:
@@ -13594,7 +13595,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;
@@ -13624,14 +13626,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;
@@ -13658,7 +13660,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);
+ else if (novector)
+ {
+ cp_parser_error (parser, "missing loop condition in loop with "
+ "%<GCC novector%> pragma");
+ condition = error_mark_node;
+ }
+ finish_for_cond (condition, stmt, ivdep, unroll, novector);
/* Look for the `;'. */
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
@@ -13682,7 +13690,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;
@@ -13758,6 +13767,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. */
@@ -13770,7 +13781,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;
}
@@ -13948,7 +13959,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;
@@ -14008,7 +14019,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,
@@ -14175,7 +14186,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;
@@ -14209,7 +14220,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. */
@@ -14244,7 +14255,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 `;'. */
@@ -14258,7 +14269,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);
@@ -43815,7 +43826,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,
@@ -49300,6 +49311,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. */
@@ -49605,58 +49625,73 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
break;
case PRAGMA_IVDEP:
+ case PRAGMA_UNROLL:
+ case PRAGMA_NOVECTOR:
{
- if (context == pragma_external)
+ bool ivdep;
+ unsigned short unroll = 0;
+ bool novector = false;
+ const char *pragma_str;
+
+ switch (id)
{
- error_at (pragma_tok->location,
- "%<#pragma GCC ivdep%> must be inside a function");
+ case PRAGMA_IVDEP:
+ pragma_str = "ivdep";
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:
+ pragma_str = "unroll";
+ break;
+ case PRAGMA_NOVECTOR:
+ pragma_str = "novector";
+ break;
+ default:
+ gcc_unreachable ();
+ }
- case PRAGMA_UNROLL:
- {
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;
+
+ do
{
- tok = cp_lexer_consume_token (parser->lexer);
- ivdep = cp_parser_pragma_ivdep (parser, tok);
- tok = cp_lexer_peek_token (the_parser->lexer);
+ 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);
+ tok = cp_lexer_peek_token (the_parser->lexer);
+ break;
+ }
+ case PRAGMA_UNROLL:
+ {
+ if (tok != pragma_tok)
+ tok = cp_lexer_consume_token (parser->lexer);
+ unroll = cp_parser_pragma_unroll (parser, tok);
+ tok = cp_lexer_peek_token (the_parser->lexer);
+ break;
+ }
+ case PRAGMA_NOVECTOR:
+ {
+ if (tok != pragma_tok)
+ tok = cp_lexer_consume_token (parser->lexer);
+ novector = cp_parser_pragma_novector (parser, tok);
+ tok = cp_lexer_peek_token (the_parser->lexer);
+ break;
+ }
+ default:
+ gcc_unreachable ();
+ }
}
- else
- ivdep = false;
+ while (tok->type == CPP_PRAGMA);
+
if (tok->type != CPP_KEYWORD
|| (tok->keyword != RID_FOR
&& tok->keyword != RID_WHILE
@@ -49665,7 +49700,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;
}
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2345a18becc1160b9d12f3d88cccb66c8917373c..7b0d01a90e3c4012ec603ebe04cbbb31a7dd1570 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -19036,7 +19036,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);
{
@@ -19073,6 +19073,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);
@@ -19083,7 +19084,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 ();
@@ -19096,7 +19098,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));
@@ -19114,7 +19116,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:
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8fb47fd179eb2af2e82bf31d188023e9b9d41de9..b79975109c22ebcfcb060b4f20f32f69f3c3c444 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -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;
}
@@ -1325,7 +1337,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);
@@ -1345,6 +1357,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));
}
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 3040a9bdea65d27f8d20572b4ed37375f5fe949b..baac6643d1abbf33d592e68aca49ac83e3c29188 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -24349,6 +24349,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}
diff --git a/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc b/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc
new file mode 100644
index 0000000000000000000000000000000000000000..cd5fb7ba9d4806f4d5e484ec68c707ea0e28ad7c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc
@@ -0,0 +1,68 @@
+/* { dg-skip-if "incorrect syntax for c++98" { *-*-* } { "-std=c++98" } { "" } } */
+/* { 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++;
+ }
+}
+
+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++;
+ }
+}
+
+/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */
diff --git a/gcc/testsuite/g++.dg/vect/vect.exp b/gcc/testsuite/g++.dg/vect/vect.exp
index df273233f47a788024bbe61128eaa96b639cb3b8..fc77120a83173c65ad147e8bb7c29ac82f06bb6d 100644
--- a/gcc/testsuite/g++.dg/vect/vect.exp
+++ b/gcc/testsuite/g++.dg/vect/vect.exp
@@ -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
--
[-- Attachment #2: rb17578.patch --]
[-- Type: text/plain, Size: 22845 bytes --]
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 0e66ca70e00caa1dc4beada1024ace32954e2aaf..c13c8ea98a523c4ef1c55a11e02d5da9db7e367e 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -305,8 +305,8 @@ DEFTREECODE (IF_STMT, "if_stmt", tcc_statement, 4)
/* Used to represent a range-based `for' statement. The operands are
RANGE_FOR_DECL, RANGE_FOR_EXPR, RANGE_FOR_BODY, RANGE_FOR_SCOPE,
- RANGE_FOR_UNROLL, and RANGE_FOR_INIT_STMT, respectively. Only used in
- templates. */
+ RANGE_FOR_UNROLL, RANGE_FOR_NOVECTOR and RANGE_FOR_INIT_STMT,
+ respectively. Only used in templates. */
DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 6)
/* Used to represent an expression statement. Use `EXPR_STMT_EXPR' to
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8398223311194837441107cb335d497ff5f5ec1c..bece7bff1f01a23cfc94386fd3295a0be8c462fe 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5377,6 +5377,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)
@@ -7286,7 +7287,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);
@@ -7609,16 +7610,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);
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index af6e30f511e142c7a594e742d128b2bf0aa8fb8d..5b735b27e6f5bc6b439ae64665902f4f1ca76f95 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4846,7 +4846,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
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 91cf943f11089c0e6bcbe8377daa4e016f956d56..fce49c796199c2c65cd70684e2942fea1b6b2ebd 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -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),
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index dd3665c8ccf48a8a0b1ba2c06400fe50999ea240..8776e8f4cf8266ee715c3e7f943602fdb1acaf79 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -2324,15 +2324,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
@@ -12414,7 +12414,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:
@@ -13594,7 +13595,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;
@@ -13624,14 +13626,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;
@@ -13658,7 +13660,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);
+ else if (novector)
+ {
+ cp_parser_error (parser, "missing loop condition in loop with "
+ "%<GCC novector%> pragma");
+ condition = error_mark_node;
+ }
+ finish_for_cond (condition, stmt, ivdep, unroll, novector);
/* Look for the `;'. */
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
@@ -13682,7 +13690,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;
@@ -13758,6 +13767,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. */
@@ -13770,7 +13781,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;
}
@@ -13948,7 +13959,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;
@@ -14008,7 +14019,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,
@@ -14175,7 +14186,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;
@@ -14209,7 +14220,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. */
@@ -14244,7 +14255,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 `;'. */
@@ -14258,7 +14269,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);
@@ -43815,7 +43826,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,
@@ -49300,6 +49311,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. */
@@ -49605,58 +49625,73 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
break;
case PRAGMA_IVDEP:
+ case PRAGMA_UNROLL:
+ case PRAGMA_NOVECTOR:
{
- if (context == pragma_external)
+ bool ivdep;
+ unsigned short unroll = 0;
+ bool novector = false;
+ const char *pragma_str;
+
+ switch (id)
{
- error_at (pragma_tok->location,
- "%<#pragma GCC ivdep%> must be inside a function");
+ case PRAGMA_IVDEP:
+ pragma_str = "ivdep";
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:
+ pragma_str = "unroll";
+ break;
+ case PRAGMA_NOVECTOR:
+ pragma_str = "novector";
+ break;
+ default:
+ gcc_unreachable ();
+ }
- case PRAGMA_UNROLL:
- {
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;
+
+ do
{
- tok = cp_lexer_consume_token (parser->lexer);
- ivdep = cp_parser_pragma_ivdep (parser, tok);
- tok = cp_lexer_peek_token (the_parser->lexer);
+ 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);
+ tok = cp_lexer_peek_token (the_parser->lexer);
+ break;
+ }
+ case PRAGMA_UNROLL:
+ {
+ if (tok != pragma_tok)
+ tok = cp_lexer_consume_token (parser->lexer);
+ unroll = cp_parser_pragma_unroll (parser, tok);
+ tok = cp_lexer_peek_token (the_parser->lexer);
+ break;
+ }
+ case PRAGMA_NOVECTOR:
+ {
+ if (tok != pragma_tok)
+ tok = cp_lexer_consume_token (parser->lexer);
+ novector = cp_parser_pragma_novector (parser, tok);
+ tok = cp_lexer_peek_token (the_parser->lexer);
+ break;
+ }
+ default:
+ gcc_unreachable ();
+ }
}
- else
- ivdep = false;
+ while (tok->type == CPP_PRAGMA);
+
if (tok->type != CPP_KEYWORD
|| (tok->keyword != RID_FOR
&& tok->keyword != RID_WHILE
@@ -49665,7 +49700,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;
}
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2345a18becc1160b9d12f3d88cccb66c8917373c..7b0d01a90e3c4012ec603ebe04cbbb31a7dd1570 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -19036,7 +19036,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);
{
@@ -19073,6 +19073,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);
@@ -19083,7 +19084,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 ();
@@ -19096,7 +19098,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));
@@ -19114,7 +19116,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:
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8fb47fd179eb2af2e82bf31d188023e9b9d41de9..b79975109c22ebcfcb060b4f20f32f69f3c3c444 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -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;
}
@@ -1325,7 +1337,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);
@@ -1345,6 +1357,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));
}
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 3040a9bdea65d27f8d20572b4ed37375f5fe949b..baac6643d1abbf33d592e68aca49ac83e3c29188 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -24349,6 +24349,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}
diff --git a/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc b/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc
new file mode 100644
index 0000000000000000000000000000000000000000..cd5fb7ba9d4806f4d5e484ec68c707ea0e28ad7c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc
@@ -0,0 +1,68 @@
+/* { dg-skip-if "incorrect syntax for c++98" { *-*-* } { "-std=c++98" } { "" } } */
+/* { 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++;
+ }
+}
+
+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++;
+ }
+}
+
+/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */
diff --git a/gcc/testsuite/g++.dg/vect/vect.exp b/gcc/testsuite/g++.dg/vect/vect.exp
index df273233f47a788024bbe61128eaa96b639cb3b8..fc77120a83173c65ad147e8bb7c29ac82f06bb6d 100644
--- a/gcc/testsuite/g++.dg/vect/vect.exp
+++ b/gcc/testsuite/g++.dg/vect/vect.exp
@@ -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
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/2][frontend]: Add novector C pragma
2023-07-19 15:15 [PATCH 1/2][frontend] Add novector C++ pragma Tamar Christina
@ 2023-07-19 15:16 ` Tamar Christina
2023-07-26 19:35 ` Tamar Christina
2023-07-25 20:53 ` [PATCH 1/2][frontend] Add novector C++ pragma Jason Merrill
1 sibling, 1 reply; 8+ messages in thread
From: Tamar Christina @ 2023-07-19 15:16 UTC (permalink / raw)
To: gcc-patches; +Cc: nd, joseph
[-- Attachment #1: Type: text/plain, Size: 11795 bytes --]
Hi All,
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.
Bootstrapped Regtested on aarch64-none-linux-gnu and no issues.
Ok for master?
Thanks,
Tamar
gcc/c-family/ChangeLog:
* c-pragma.h (enum pragma_kind): Add PRAGMA_NOVECTOR.
* c-pragma.cc (init_pragma): Use it.
gcc/c/ChangeLog:
* c-parser.cc (c_parser_while_statement, c_parser_do_statement,
c_parser_for_statement, c_parser_statement_after_labels,
c_parse_pragma_novector, c_parser_pragma): Wire through novector and
default to false.
gcc/testsuite/ChangeLog:
* gcc.dg/vect/vect-novector-pragma.c: New test.
--- inline copy of patch --
diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index 9cc95ab3ee376628dbef2485b84e6008210fa8fc..99cf2e8bd1c05537c198470f1aaa0a5a9da4e576 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -87,6 +87,7 @@ enum pragma_kind {
PRAGMA_GCC_PCH_PREPROCESS,
PRAGMA_IVDEP,
PRAGMA_UNROLL,
+ PRAGMA_NOVECTOR,
PRAGMA_FIRST_EXTERNAL
};
diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc
index 0d2b333cebbed32423d5dc6fd2a3ac0ce0bf8b94..848a850b8e123ff1c6ae1ec4b7f8ccbd599b1a88 100644
--- a/gcc/c-family/c-pragma.cc
+++ b/gcc/c-family/c-pragma.cc
@@ -1862,6 +1862,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", "novector", PRAGMA_NOVECTOR,
+ false, false);
+
#ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION
c_register_pragma_with_expansion (0, "pack", handle_pragma_pack);
#else
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 24a6eb6e4596f32c477e3f1c3f98b9792f7bc92c..4c64d898cddac437958ce20c5603b88a05a99093 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -1572,9 +1572,11 @@ 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 *);
-static void c_parser_do_statement (c_parser *, bool, unsigned short);
-static void c_parser_for_statement (c_parser *, bool, unsigned short, 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 tree c_parser_asm_statement (c_parser *);
static tree c_parser_asm_operands (c_parser *);
static tree c_parser_asm_goto_operands (c_parser *);
@@ -6644,13 +6646,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, if_p);
+ c_parser_while_statement (parser, false, 0, false, if_p);
break;
case RID_DO:
- c_parser_do_statement (parser, false, 0);
+ c_parser_do_statement (parser, false, 0, false);
break;
case RID_FOR:
- c_parser_for_statement (parser, false, 0, if_p);
+ c_parser_for_statement (parser, false, 0, false, if_p);
break;
case RID_GOTO:
c_parser_consume_token (parser);
@@ -7146,7 +7148,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 *if_p)
+ bool novector, bool *if_p)
{
tree block, cond, body;
unsigned char save_in_statement;
@@ -7168,6 +7170,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 (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);
save_in_statement = in_statement;
in_statement = IN_ITERATION_STMT;
@@ -7199,7 +7206,8 @@ 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)
+c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll,
+ bool novector)
{
tree block, cond, body;
unsigned char save_in_statement;
@@ -7228,6 +7236,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 (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);
if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
c_parser_skip_to_end_of_block_or_statement (parser);
@@ -7296,7 +7309,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 *if_p)
+ bool novector, bool *if_p)
{
tree block, cond, incr, body;
unsigned char save_in_statement;
@@ -7430,6 +7443,12 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
"with %<GCC unroll%> pragma");
cond = error_mark_node;
}
+ else if (novector)
+ {
+ c_parser_error (parser, "missing loop condition in loop "
+ "with %<GCC novector%> pragma");
+ cond = error_mark_node;
+ }
else
{
c_parser_consume_token (parser);
@@ -7452,6 +7471,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 (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);
}
/* Parse the increment expression (the third expression in a
for-statement). In the case of a foreach-statement, this is
@@ -13037,6 +13061,16 @@ c_parse_pragma_ivdep (c_parser *parser)
return true;
}
+/* Parse a pragma GCC novector. */
+
+static bool
+c_parse_pragma_novector (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
@@ -13261,38 +13295,50 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
case PRAGMA_OMP_ORDERED:
return c_parser_omp_ordered (parser, context, if_p);
+ case PRAGMA_NOVECTOR:
+ case PRAGMA_UNROLL:
case PRAGMA_IVDEP:
{
- 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))
+ bool novector = false;
+ unsigned short unroll = 0;
+ bool ivdep = false;
+
+ switch (id)
{
- c_parser_error (parser, "for, while or do statement expected");
- return false;
+ case PRAGMA_NOVECTOR:
+ novector = c_parse_pragma_novector (parser);
+ break;
+ case PRAGMA_UNROLL:
+ unroll = c_parser_pragma_unroll (parser);
+ break;
+ case PRAGMA_IVDEP:
+ ivdep = c_parse_pragma_ivdep (parser);
+ break;
+ default:
+ gcc_unreachable ();
}
- 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 true;
- 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;
+ c_token *tok = c_parser_peek_token (parser);
+ while (tok->type == CPP_PRAGMA)
+ {
+ switch (tok->pragma_kind)
+ {
+ case PRAGMA_IVDEP:
+ ivdep = c_parse_pragma_ivdep (parser);
+ tok = c_parser_peek_token (parser);
+ break;
+ case PRAGMA_UNROLL:
+ unroll = c_parser_pragma_unroll (parser);
+ tok = c_parser_peek_token (parser);
+ break;
+ case PRAGMA_NOVECTOR:
+ novector = c_parse_pragma_novector (parser);
+ tok = c_parser_peek_token (parser);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
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))
@@ -13301,11 +13347,11 @@ 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, if_p);
+ c_parser_for_statement (parser, ivdep, unroll, novector, if_p);
else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
- c_parser_while_statement (parser, ivdep, unroll, if_p);
+ c_parser_while_statement (parser, ivdep, unroll, novector, if_p);
else
- c_parser_do_statement (parser, ivdep, unroll);
+ c_parser_do_statement (parser, ivdep, unroll, novector);
}
return true;
diff --git a/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c b/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c
new file mode 100644
index 0000000000000000000000000000000000000000..3c0b8f5d2acbd276280785e8d0cbe1f7cd650266
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+
+void f1 (int * restrict a, int * restrict b, int n)
+{
+#pragma GCC novector
+ for (int i = 0; i < (n & -8); i++)
+ a[i] += b[i];
+}
+
+void f2 (int * restrict a, int * restrict b, int n)
+{
+#pragma GCC novector
+#pragma GCC ivdep
+#pragma GCC unroll 2
+ for (int i = 0; i < (n & -8); i++)
+ a[i] += b[i];
+}
+
+void f3 (int * restrict a, int * restrict b, int n)
+{
+#pragma GCC ivdep
+#pragma GCC novector
+#pragma GCC unroll 2
+ for (int i = 0; i < (n & -8); i++)
+ a[i] += b[i];
+}
+
+void f4 (int * restrict a, int * restrict b, int n)
+{
+#pragma GCC ivdep
+#pragma GCC unroll 2
+#pragma GCC novector
+ for (int i = 0; i < (n & -8); i++)
+ a[i] += b[i];
+}
+
+void f5 (int * restrict a, int * restrict b, int n)
+{
+ int i = 0;
+#pragma GCC novector
+ do
+ {
+ a[i] += b[i];
+ i++;
+ }
+ while (i < (n & -8));
+}
+
+void f6 (int * restrict a, int * restrict b, int n)
+{
+ int i = 0;
+#pragma GCC novector
+ while (i < (n & -8))
+ {
+ a[i] += b[i];
+ i++;
+ }
+}
+
+/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */
--
[-- Attachment #2: rb17579.patch --]
[-- Type: text/plain, Size: 10663 bytes --]
diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index 9cc95ab3ee376628dbef2485b84e6008210fa8fc..99cf2e8bd1c05537c198470f1aaa0a5a9da4e576 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -87,6 +87,7 @@ enum pragma_kind {
PRAGMA_GCC_PCH_PREPROCESS,
PRAGMA_IVDEP,
PRAGMA_UNROLL,
+ PRAGMA_NOVECTOR,
PRAGMA_FIRST_EXTERNAL
};
diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc
index 0d2b333cebbed32423d5dc6fd2a3ac0ce0bf8b94..848a850b8e123ff1c6ae1ec4b7f8ccbd599b1a88 100644
--- a/gcc/c-family/c-pragma.cc
+++ b/gcc/c-family/c-pragma.cc
@@ -1862,6 +1862,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", "novector", PRAGMA_NOVECTOR,
+ false, false);
+
#ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION
c_register_pragma_with_expansion (0, "pack", handle_pragma_pack);
#else
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 24a6eb6e4596f32c477e3f1c3f98b9792f7bc92c..4c64d898cddac437958ce20c5603b88a05a99093 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -1572,9 +1572,11 @@ 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 *);
-static void c_parser_do_statement (c_parser *, bool, unsigned short);
-static void c_parser_for_statement (c_parser *, bool, unsigned short, 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 tree c_parser_asm_statement (c_parser *);
static tree c_parser_asm_operands (c_parser *);
static tree c_parser_asm_goto_operands (c_parser *);
@@ -6644,13 +6646,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, if_p);
+ c_parser_while_statement (parser, false, 0, false, if_p);
break;
case RID_DO:
- c_parser_do_statement (parser, false, 0);
+ c_parser_do_statement (parser, false, 0, false);
break;
case RID_FOR:
- c_parser_for_statement (parser, false, 0, if_p);
+ c_parser_for_statement (parser, false, 0, false, if_p);
break;
case RID_GOTO:
c_parser_consume_token (parser);
@@ -7146,7 +7148,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 *if_p)
+ bool novector, bool *if_p)
{
tree block, cond, body;
unsigned char save_in_statement;
@@ -7168,6 +7170,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 (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);
save_in_statement = in_statement;
in_statement = IN_ITERATION_STMT;
@@ -7199,7 +7206,8 @@ 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)
+c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll,
+ bool novector)
{
tree block, cond, body;
unsigned char save_in_statement;
@@ -7228,6 +7236,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 (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);
if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
c_parser_skip_to_end_of_block_or_statement (parser);
@@ -7296,7 +7309,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 *if_p)
+ bool novector, bool *if_p)
{
tree block, cond, incr, body;
unsigned char save_in_statement;
@@ -7430,6 +7443,12 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
"with %<GCC unroll%> pragma");
cond = error_mark_node;
}
+ else if (novector)
+ {
+ c_parser_error (parser, "missing loop condition in loop "
+ "with %<GCC novector%> pragma");
+ cond = error_mark_node;
+ }
else
{
c_parser_consume_token (parser);
@@ -7452,6 +7471,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 (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);
}
/* Parse the increment expression (the third expression in a
for-statement). In the case of a foreach-statement, this is
@@ -13037,6 +13061,16 @@ c_parse_pragma_ivdep (c_parser *parser)
return true;
}
+/* Parse a pragma GCC novector. */
+
+static bool
+c_parse_pragma_novector (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
@@ -13261,38 +13295,50 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
case PRAGMA_OMP_ORDERED:
return c_parser_omp_ordered (parser, context, if_p);
+ case PRAGMA_NOVECTOR:
+ case PRAGMA_UNROLL:
case PRAGMA_IVDEP:
{
- 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))
+ bool novector = false;
+ unsigned short unroll = 0;
+ bool ivdep = false;
+
+ switch (id)
{
- c_parser_error (parser, "for, while or do statement expected");
- return false;
+ case PRAGMA_NOVECTOR:
+ novector = c_parse_pragma_novector (parser);
+ break;
+ case PRAGMA_UNROLL:
+ unroll = c_parser_pragma_unroll (parser);
+ break;
+ case PRAGMA_IVDEP:
+ ivdep = c_parse_pragma_ivdep (parser);
+ break;
+ default:
+ gcc_unreachable ();
}
- 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 true;
- 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;
+ c_token *tok = c_parser_peek_token (parser);
+ while (tok->type == CPP_PRAGMA)
+ {
+ switch (tok->pragma_kind)
+ {
+ case PRAGMA_IVDEP:
+ ivdep = c_parse_pragma_ivdep (parser);
+ tok = c_parser_peek_token (parser);
+ break;
+ case PRAGMA_UNROLL:
+ unroll = c_parser_pragma_unroll (parser);
+ tok = c_parser_peek_token (parser);
+ break;
+ case PRAGMA_NOVECTOR:
+ novector = c_parse_pragma_novector (parser);
+ tok = c_parser_peek_token (parser);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
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))
@@ -13301,11 +13347,11 @@ 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, if_p);
+ c_parser_for_statement (parser, ivdep, unroll, novector, if_p);
else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
- c_parser_while_statement (parser, ivdep, unroll, if_p);
+ c_parser_while_statement (parser, ivdep, unroll, novector, if_p);
else
- c_parser_do_statement (parser, ivdep, unroll);
+ c_parser_do_statement (parser, ivdep, unroll, novector);
}
return true;
diff --git a/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c b/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c
new file mode 100644
index 0000000000000000000000000000000000000000..3c0b8f5d2acbd276280785e8d0cbe1f7cd650266
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+
+void f1 (int * restrict a, int * restrict b, int n)
+{
+#pragma GCC novector
+ for (int i = 0; i < (n & -8); i++)
+ a[i] += b[i];
+}
+
+void f2 (int * restrict a, int * restrict b, int n)
+{
+#pragma GCC novector
+#pragma GCC ivdep
+#pragma GCC unroll 2
+ for (int i = 0; i < (n & -8); i++)
+ a[i] += b[i];
+}
+
+void f3 (int * restrict a, int * restrict b, int n)
+{
+#pragma GCC ivdep
+#pragma GCC novector
+#pragma GCC unroll 2
+ for (int i = 0; i < (n & -8); i++)
+ a[i] += b[i];
+}
+
+void f4 (int * restrict a, int * restrict b, int n)
+{
+#pragma GCC ivdep
+#pragma GCC unroll 2
+#pragma GCC novector
+ for (int i = 0; i < (n & -8); i++)
+ a[i] += b[i];
+}
+
+void f5 (int * restrict a, int * restrict b, int n)
+{
+ int i = 0;
+#pragma GCC novector
+ do
+ {
+ a[i] += b[i];
+ i++;
+ }
+ while (i < (n & -8));
+}
+
+void f6 (int * restrict a, int * restrict b, int n)
+{
+ int i = 0;
+#pragma GCC novector
+ while (i < (n & -8))
+ {
+ a[i] += b[i];
+ i++;
+ }
+}
+
+/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2][frontend] Add novector C++ pragma
2023-07-19 15:15 [PATCH 1/2][frontend] Add novector C++ pragma Tamar Christina
2023-07-19 15:16 ` [PATCH 2/2][frontend]: Add novector C pragma Tamar Christina
@ 2023-07-25 20:53 ` Jason Merrill
2023-07-26 19:32 ` Tamar Christina
1 sibling, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2023-07-25 20:53 UTC (permalink / raw)
To: Tamar Christina, gcc-patches; +Cc: nd, nathan
On 7/19/23 11:15, Tamar Christina wrote:
> Hi All,
>
> 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.
>
> Bootstrapped Regtested on aarch64-none-linux-gnu and no issues.
>
> Ok for master?
>
> Thanks,
> Tamar
>
> gcc/cp/ChangeLog:
>
> * cp-tree.def (RANGE_FOR_STMT): Update comment.
> * 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.
>
> --- inline copy of patch --
> diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
> index 0e66ca70e00caa1dc4beada1024ace32954e2aaf..c13c8ea98a523c4ef1c55a11e02d5da9db7e367e 100644
> --- a/gcc/cp/cp-tree.def
> +++ b/gcc/cp/cp-tree.def
> @@ -305,8 +305,8 @@ DEFTREECODE (IF_STMT, "if_stmt", tcc_statement, 4)
>
> /* Used to represent a range-based `for' statement. The operands are
> RANGE_FOR_DECL, RANGE_FOR_EXPR, RANGE_FOR_BODY, RANGE_FOR_SCOPE,
> - RANGE_FOR_UNROLL, and RANGE_FOR_INIT_STMT, respectively. Only used in
> - templates. */
> + RANGE_FOR_UNROLL, RANGE_FOR_NOVECTOR and RANGE_FOR_INIT_STMT,
> + respectively. Only used in templates. */
This change is unnecessary; RANGE_FOR_NOVECTOR is a flag, not an operand.
> DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 6)
>
> /* Used to represent an expression statement. Use `EXPR_STMT_EXPR' to
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index dd3665c8ccf48a8a0b1ba2c06400fe50999ea240..8776e8f4cf8266ee715c3e7f943602fdb1acaf79 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -13658,7 +13660,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);
> + else if (novector)
> + {
> + cp_parser_error (parser, "missing loop condition in loop with "
> + "%<GCC novector%> pragma");
> + condition = error_mark_node;
> + }
Why is it a problem for a loop with novector to have no condition? This
error makes sense for the other pragmas that want to optimize based on
the condition, it seems unneeded for this pragma.
> +
> + cp_token *tok = pragma_tok;
> +
> + do
> {
> - tok = cp_lexer_consume_token (parser->lexer);
> - ivdep = cp_parser_pragma_ivdep (parser, tok);
> - tok = cp_lexer_peek_token (the_parser->lexer);
> + 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);
> + tok = cp_lexer_peek_token (the_parser->lexer);
> + break;
> + }
> + case PRAGMA_UNROLL:
> + {
> + if (tok != pragma_tok)
> + tok = cp_lexer_consume_token (parser->lexer);
> + unroll = cp_parser_pragma_unroll (parser, tok);
> + tok = cp_lexer_peek_token (the_parser->lexer);
> + break;
> + }
> + case PRAGMA_NOVECTOR:
> + {
> + if (tok != pragma_tok)
> + tok = cp_lexer_consume_token (parser->lexer);
> + novector = cp_parser_pragma_novector (parser, tok);
> + tok = cp_lexer_peek_token (the_parser->lexer);
> + break;
> + }
> + default:
> + gcc_unreachable ();
This unreachable seems to assert that if a pragma follows one of these
pragmas, it must be another one of these pragmas? That seems wrong;
instead of hitting gcc_unreachable() in that case we should fall through
to the diagnostic below.
I also think you could factor the peek out of the switch.
> diff --git a/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc b/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc
> new file mode 100644
> index 0000000000000000000000000000000000000000..cd5fb7ba9d4806f4d5e484ec68c707ea0e28ad7c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc
> @@ -0,0 +1,68 @@
> +/* { dg-skip-if "incorrect syntax for c++98" { *-*-* } { "-std=c++98" } { "" } } */
> +/* { dg-do compile } */
This is usually expressed as { dg-do compile { target c++11 } }
Or you could run in C++98 mode but guard the range-for tests with
#if __cpp_range_based_for
Jason
^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: [PATCH 1/2][frontend] Add novector C++ pragma
2023-07-25 20:53 ` [PATCH 1/2][frontend] Add novector C++ pragma Jason Merrill
@ 2023-07-26 19:32 ` Tamar Christina
2023-07-26 20:52 ` Jason Merrill
0 siblings, 1 reply; 8+ messages in thread
From: Tamar Christina @ 2023-07-26 19:32 UTC (permalink / raw)
To: Jason Merrill, gcc-patches; +Cc: nd, nathan
[-- Attachment #1: Type: text/plain, Size: 24947 bytes --]
> > +
> > + cp_token *tok = pragma_tok;
> > +
> > + do
> > {
> > - tok = cp_lexer_consume_token (parser->lexer);
> > - ivdep = cp_parser_pragma_ivdep (parser, tok);
> > - tok = cp_lexer_peek_token (the_parser->lexer);
> > + 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);
> > + tok = cp_lexer_peek_token (the_parser->lexer);
> > + break;
> > + }
> > + case PRAGMA_UNROLL:
> > + {
> > + if (tok != pragma_tok)
> > + tok = cp_lexer_consume_token (parser->lexer);
> > + unroll = cp_parser_pragma_unroll (parser, tok);
> > + tok = cp_lexer_peek_token (the_parser->lexer);
> > + break;
> > + }
> > + case PRAGMA_NOVECTOR:
> > + {
> > + if (tok != pragma_tok)
> > + tok = cp_lexer_consume_token (parser->lexer);
> > + novector = cp_parser_pragma_novector (parser, tok);
> > + tok = cp_lexer_peek_token (the_parser->lexer);
> > + break;
> > + }
> > + default:
> > + gcc_unreachable ();
>
> This unreachable seems to assert that if a pragma follows one of these
> pragmas, it must be another one of these pragmas? That seems wrong;
> instead of hitting gcc_unreachable() in that case we should fall through to the
> diagnostic below.
>
Ah, good should. Since it has to exit two levels I had to introduce a bool
for controlling the loop iterations. New patch below.
Bootstrapped Regtested on aarch64-none-linux-gnu and no issues.
Ok for master?
Thanks,
Tamar
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.
--- inline copy of patch ---
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8398223311194837441107cb335d497ff5f5ec1c..bece7bff1f01a23cfc94386fd3295a0be8c462fe 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5377,6 +5377,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)
@@ -7286,7 +7287,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);
@@ -7609,16 +7610,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);
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index af6e30f511e142c7a594e742d128b2bf0aa8fb8d..5b735b27e6f5bc6b439ae64665902f4f1ca76f95 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4846,7 +4846,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
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 91cf943f11089c0e6bcbe8377daa4e016f956d56..fce49c796199c2c65cd70684e2942fea1b6b2ebd 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -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),
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index dd3665c8ccf48a8a0b1ba2c06400fe50999ea240..092f991d7a1b6aab8482d50848fb9fb96c377509 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -2324,15 +2324,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
@@ -12414,7 +12414,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:
@@ -13594,7 +13595,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;
@@ -13624,14 +13626,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;
@@ -13658,7 +13660,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);
@@ -13682,7 +13684,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;
@@ -13758,6 +13761,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. */
@@ -13770,7 +13775,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;
}
@@ -13948,7 +13953,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;
@@ -14008,7 +14013,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,
@@ -14175,7 +14180,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;
@@ -14209,7 +14214,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. */
@@ -14244,7 +14249,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 `;'. */
@@ -14258,7 +14263,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);
@@ -43815,7 +43820,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,
@@ -49300,6 +49305,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. */
@@ -49605,58 +49619,73 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
break;
case PRAGMA_IVDEP:
+ case PRAGMA_UNROLL:
+ case PRAGMA_NOVECTOR:
{
- if (context == pragma_external)
+ bool ivdep;
+ unsigned short unroll = 0;
+ bool novector = false;
+ const char *pragma_str;
+
+ switch (id)
{
- error_at (pragma_tok->location,
- "%<#pragma GCC ivdep%> must be inside a function");
+ case PRAGMA_IVDEP:
+ pragma_str = "ivdep";
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:
+ pragma_str = "unroll";
+ break;
+ case PRAGMA_NOVECTOR:
+ pragma_str = "novector";
+ break;
+ default:
+ gcc_unreachable ();
+ }
- case PRAGMA_UNROLL:
- {
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
@@ -49665,7 +49694,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;
}
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2345a18becc1160b9d12f3d88cccb66c8917373c..7b0d01a90e3c4012ec603ebe04cbbb31a7dd1570 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -19036,7 +19036,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);
{
@@ -19073,6 +19073,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);
@@ -19083,7 +19084,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 ();
@@ -19096,7 +19098,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));
@@ -19114,7 +19116,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:
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8fb47fd179eb2af2e82bf31d188023e9b9d41de9..b79975109c22ebcfcb060b4f20f32f69f3c3c444 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -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;
}
@@ -1325,7 +1337,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);
@@ -1345,6 +1357,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));
}
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 3040a9bdea65d27f8d20572b4ed37375f5fe949b..baac6643d1abbf33d592e68aca49ac83e3c29188 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -24349,6 +24349,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}
diff --git a/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc b/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8c6ff22fcaabaa97516be72b77acbd44df86b1d2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc
@@ -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" } } */
diff --git a/gcc/testsuite/g++.dg/vect/vect.exp b/gcc/testsuite/g++.dg/vect/vect.exp
index df273233f47a788024bbe61128eaa96b639cb3b8..fc77120a83173c65ad147e8bb7c29ac82f06bb6d 100644
--- a/gcc/testsuite/g++.dg/vect/vect.exp
+++ b/gcc/testsuite/g++.dg/vect/vect.exp
@@ -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
[-- Attachment #2: rb17578.patch --]
[-- Type: application/octet-stream, Size: 21761 bytes --]
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8398223311194837441107cb335d497ff5f5ec1c..bece7bff1f01a23cfc94386fd3295a0be8c462fe 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5377,6 +5377,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)
@@ -7286,7 +7287,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);
@@ -7609,16 +7610,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);
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index af6e30f511e142c7a594e742d128b2bf0aa8fb8d..5b735b27e6f5bc6b439ae64665902f4f1ca76f95 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4846,7 +4846,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
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 91cf943f11089c0e6bcbe8377daa4e016f956d56..fce49c796199c2c65cd70684e2942fea1b6b2ebd 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -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),
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index dd3665c8ccf48a8a0b1ba2c06400fe50999ea240..092f991d7a1b6aab8482d50848fb9fb96c377509 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -2324,15 +2324,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
@@ -12414,7 +12414,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:
@@ -13594,7 +13595,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;
@@ -13624,14 +13626,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;
@@ -13658,7 +13660,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);
@@ -13682,7 +13684,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;
@@ -13758,6 +13761,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. */
@@ -13770,7 +13775,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;
}
@@ -13948,7 +13953,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;
@@ -14008,7 +14013,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,
@@ -14175,7 +14180,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;
@@ -14209,7 +14214,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. */
@@ -14244,7 +14249,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 `;'. */
@@ -14258,7 +14263,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);
@@ -43815,7 +43820,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,
@@ -49300,6 +49305,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. */
@@ -49605,58 +49619,73 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
break;
case PRAGMA_IVDEP:
+ case PRAGMA_UNROLL:
+ case PRAGMA_NOVECTOR:
{
- if (context == pragma_external)
+ bool ivdep;
+ unsigned short unroll = 0;
+ bool novector = false;
+ const char *pragma_str;
+
+ switch (id)
{
- error_at (pragma_tok->location,
- "%<#pragma GCC ivdep%> must be inside a function");
+ case PRAGMA_IVDEP:
+ pragma_str = "ivdep";
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:
+ pragma_str = "unroll";
+ break;
+ case PRAGMA_NOVECTOR:
+ pragma_str = "novector";
+ break;
+ default:
+ gcc_unreachable ();
+ }
- case PRAGMA_UNROLL:
- {
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
@@ -49665,7 +49694,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;
}
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2345a18becc1160b9d12f3d88cccb66c8917373c..7b0d01a90e3c4012ec603ebe04cbbb31a7dd1570 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -19036,7 +19036,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);
{
@@ -19073,6 +19073,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);
@@ -19083,7 +19084,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 ();
@@ -19096,7 +19098,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));
@@ -19114,7 +19116,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:
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8fb47fd179eb2af2e82bf31d188023e9b9d41de9..b79975109c22ebcfcb060b4f20f32f69f3c3c444 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -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;
}
@@ -1325,7 +1337,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);
@@ -1345,6 +1357,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));
}
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 3040a9bdea65d27f8d20572b4ed37375f5fe949b..baac6643d1abbf33d592e68aca49ac83e3c29188 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -24349,6 +24349,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}
diff --git a/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc b/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8c6ff22fcaabaa97516be72b77acbd44df86b1d2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc
@@ -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" } } */
diff --git a/gcc/testsuite/g++.dg/vect/vect.exp b/gcc/testsuite/g++.dg/vect/vect.exp
index df273233f47a788024bbe61128eaa96b639cb3b8..fc77120a83173c65ad147e8bb7c29ac82f06bb6d 100644
--- a/gcc/testsuite/g++.dg/vect/vect.exp
+++ b/gcc/testsuite/g++.dg/vect/vect.exp
@@ -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
^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: [PATCH 2/2][frontend]: Add novector C pragma
2023-07-19 15:16 ` [PATCH 2/2][frontend]: Add novector C pragma Tamar Christina
@ 2023-07-26 19:35 ` Tamar Christina
2023-08-02 9:44 ` Tamar Christina
0 siblings, 1 reply; 8+ messages in thread
From: Tamar Christina @ 2023-07-26 19:35 UTC (permalink / raw)
To: Tamar Christina, gcc-patches; +Cc: nd, joseph
[-- Attachment #1: Type: text/plain, Size: 11886 bytes --]
Hi, This is a respin of the patch taking in the feedback received from the C++ part.
Simultaneously it's also a ping 😊
----
Hi All,
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.
Bootstrapped Regtested on aarch64-none-linux-gnu and no issues.
Ok for master?
Thanks,
Tamar
gcc/c-family/ChangeLog:
* c-pragma.h (enum pragma_kind): Add PRAGMA_NOVECTOR.
* c-pragma.cc (init_pragma): Use it.
gcc/c/ChangeLog:
* c-parser.cc (c_parser_while_statement, c_parser_do_statement,
c_parser_for_statement, c_parser_statement_after_labels,
c_parse_pragma_novector, c_parser_pragma): Wire through novector and
default to false.
gcc/testsuite/ChangeLog:
* gcc.dg/vect/vect-novector-pragma.c: New test.
--- inline copy of patch ---
diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index 9cc95ab3ee376628dbef2485b84e6008210fa8fc..99cf2e8bd1c05537c198470f1aaa0a5a9da4e576 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -87,6 +87,7 @@ enum pragma_kind {
PRAGMA_GCC_PCH_PREPROCESS,
PRAGMA_IVDEP,
PRAGMA_UNROLL,
+ PRAGMA_NOVECTOR,
PRAGMA_FIRST_EXTERNAL
};
diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc
index 0d2b333cebbed32423d5dc6fd2a3ac0ce0bf8b94..848a850b8e123ff1c6ae1ec4b7f8ccbd599b1a88 100644
--- a/gcc/c-family/c-pragma.cc
+++ b/gcc/c-family/c-pragma.cc
@@ -1862,6 +1862,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", "novector", PRAGMA_NOVECTOR,
+ false, false);
+
#ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION
c_register_pragma_with_expansion (0, "pack", handle_pragma_pack);
#else
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 24a6eb6e4596f32c477e3f1c3f98b9792f7bc92c..74f3cbb0d61b5f4c0eb300672f495dde3f1517f7 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -1572,9 +1572,11 @@ 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 *);
-static void c_parser_do_statement (c_parser *, bool, unsigned short);
-static void c_parser_for_statement (c_parser *, bool, unsigned short, 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 tree c_parser_asm_statement (c_parser *);
static tree c_parser_asm_operands (c_parser *);
static tree c_parser_asm_goto_operands (c_parser *);
@@ -6644,13 +6646,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, if_p);
+ c_parser_while_statement (parser, false, 0, false, if_p);
break;
case RID_DO:
- c_parser_do_statement (parser, false, 0);
+ c_parser_do_statement (parser, false, 0, false);
break;
case RID_FOR:
- c_parser_for_statement (parser, false, 0, if_p);
+ c_parser_for_statement (parser, false, 0, false, if_p);
break;
case RID_GOTO:
c_parser_consume_token (parser);
@@ -7146,7 +7148,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 *if_p)
+ bool novector, bool *if_p)
{
tree block, cond, body;
unsigned char save_in_statement;
@@ -7168,6 +7170,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 (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);
save_in_statement = in_statement;
in_statement = IN_ITERATION_STMT;
@@ -7199,7 +7206,8 @@ 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)
+c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll,
+ bool novector)
{
tree block, cond, body;
unsigned char save_in_statement;
@@ -7228,6 +7236,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 (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);
if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
c_parser_skip_to_end_of_block_or_statement (parser);
@@ -7296,7 +7309,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 *if_p)
+ bool novector, bool *if_p)
{
tree block, cond, incr, body;
unsigned char save_in_statement;
@@ -7452,6 +7465,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 (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);
}
/* Parse the increment expression (the third expression in a
for-statement). In the case of a foreach-statement, this is
@@ -13037,6 +13055,16 @@ c_parse_pragma_ivdep (c_parser *parser)
return true;
}
+/* Parse a pragma GCC novector. */
+
+static bool
+c_parse_pragma_novector (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
@@ -13261,38 +13289,51 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
case PRAGMA_OMP_ORDERED:
return c_parser_omp_ordered (parser, context, if_p);
+ case PRAGMA_NOVECTOR:
+ case PRAGMA_UNROLL:
case PRAGMA_IVDEP:
{
- 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))
+ bool novector = false;
+ unsigned short unroll = 0;
+ bool ivdep = false;
+
+ switch (id)
{
- c_parser_error (parser, "for, while or do statement expected");
- return false;
+ case PRAGMA_NOVECTOR:
+ novector = c_parse_pragma_novector (parser);
+ break;
+ case PRAGMA_UNROLL:
+ unroll = c_parser_pragma_unroll (parser);
+ break;
+ case PRAGMA_IVDEP:
+ ivdep = c_parse_pragma_ivdep (parser);
+ break;
+ default:
+ gcc_unreachable ();
}
- 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 true;
- 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;
+ c_token *tok = c_parser_peek_token (parser);
+ bool has_more = tok->type == CPP_PRAGMA;
+ while (has_more)
+ {
+ switch (tok->pragma_kind)
+ {
+ case PRAGMA_IVDEP:
+ ivdep = c_parse_pragma_ivdep (parser);
+ break;
+ case PRAGMA_UNROLL:
+ unroll = c_parser_pragma_unroll (parser);
+ break;
+ case PRAGMA_NOVECTOR:
+ novector = c_parse_pragma_novector (parser);
+ break;
+ default:
+ has_more = false;
+ break;
+ }
+ tok = c_parser_peek_token (parser);
+ has_more = has_more && tok->type == CPP_PRAGMA;
+ }
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))
@@ -13301,11 +13342,11 @@ 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, if_p);
+ c_parser_for_statement (parser, ivdep, unroll, novector, if_p);
else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
- c_parser_while_statement (parser, ivdep, unroll, if_p);
+ c_parser_while_statement (parser, ivdep, unroll, novector, if_p);
else
- c_parser_do_statement (parser, ivdep, unroll);
+ c_parser_do_statement (parser, ivdep, unroll, novector);
}
return true;
diff --git a/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c b/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c
new file mode 100644
index 0000000000000000000000000000000000000000..3c0b8f5d2acbd276280785e8d0cbe1f7cd650266
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+
+void f1 (int * restrict a, int * restrict b, int n)
+{
+#pragma GCC novector
+ for (int i = 0; i < (n & -8); i++)
+ a[i] += b[i];
+}
+
+void f2 (int * restrict a, int * restrict b, int n)
+{
+#pragma GCC novector
+#pragma GCC ivdep
+#pragma GCC unroll 2
+ for (int i = 0; i < (n & -8); i++)
+ a[i] += b[i];
+}
+
+void f3 (int * restrict a, int * restrict b, int n)
+{
+#pragma GCC ivdep
+#pragma GCC novector
+#pragma GCC unroll 2
+ for (int i = 0; i < (n & -8); i++)
+ a[i] += b[i];
+}
+
+void f4 (int * restrict a, int * restrict b, int n)
+{
+#pragma GCC ivdep
+#pragma GCC unroll 2
+#pragma GCC novector
+ for (int i = 0; i < (n & -8); i++)
+ a[i] += b[i];
+}
+
+void f5 (int * restrict a, int * restrict b, int n)
+{
+ int i = 0;
+#pragma GCC novector
+ do
+ {
+ a[i] += b[i];
+ i++;
+ }
+ while (i < (n & -8));
+}
+
+void f6 (int * restrict a, int * restrict b, int n)
+{
+ int i = 0;
+#pragma GCC novector
+ while (i < (n & -8))
+ {
+ a[i] += b[i];
+ i++;
+ }
+}
+
+/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */
[-- Attachment #2: rb17579.patch --]
[-- Type: application/octet-stream, Size: 10276 bytes --]
diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index 9cc95ab3ee376628dbef2485b84e6008210fa8fc..99cf2e8bd1c05537c198470f1aaa0a5a9da4e576 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -87,6 +87,7 @@ enum pragma_kind {
PRAGMA_GCC_PCH_PREPROCESS,
PRAGMA_IVDEP,
PRAGMA_UNROLL,
+ PRAGMA_NOVECTOR,
PRAGMA_FIRST_EXTERNAL
};
diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc
index 0d2b333cebbed32423d5dc6fd2a3ac0ce0bf8b94..848a850b8e123ff1c6ae1ec4b7f8ccbd599b1a88 100644
--- a/gcc/c-family/c-pragma.cc
+++ b/gcc/c-family/c-pragma.cc
@@ -1862,6 +1862,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", "novector", PRAGMA_NOVECTOR,
+ false, false);
+
#ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION
c_register_pragma_with_expansion (0, "pack", handle_pragma_pack);
#else
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 24a6eb6e4596f32c477e3f1c3f98b9792f7bc92c..74f3cbb0d61b5f4c0eb300672f495dde3f1517f7 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -1572,9 +1572,11 @@ 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 *);
-static void c_parser_do_statement (c_parser *, bool, unsigned short);
-static void c_parser_for_statement (c_parser *, bool, unsigned short, 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 tree c_parser_asm_statement (c_parser *);
static tree c_parser_asm_operands (c_parser *);
static tree c_parser_asm_goto_operands (c_parser *);
@@ -6644,13 +6646,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, if_p);
+ c_parser_while_statement (parser, false, 0, false, if_p);
break;
case RID_DO:
- c_parser_do_statement (parser, false, 0);
+ c_parser_do_statement (parser, false, 0, false);
break;
case RID_FOR:
- c_parser_for_statement (parser, false, 0, if_p);
+ c_parser_for_statement (parser, false, 0, false, if_p);
break;
case RID_GOTO:
c_parser_consume_token (parser);
@@ -7146,7 +7148,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 *if_p)
+ bool novector, bool *if_p)
{
tree block, cond, body;
unsigned char save_in_statement;
@@ -7168,6 +7170,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 (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);
save_in_statement = in_statement;
in_statement = IN_ITERATION_STMT;
@@ -7199,7 +7206,8 @@ 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)
+c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll,
+ bool novector)
{
tree block, cond, body;
unsigned char save_in_statement;
@@ -7228,6 +7236,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 (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);
if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
c_parser_skip_to_end_of_block_or_statement (parser);
@@ -7296,7 +7309,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 *if_p)
+ bool novector, bool *if_p)
{
tree block, cond, incr, body;
unsigned char save_in_statement;
@@ -7452,6 +7465,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 (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);
}
/* Parse the increment expression (the third expression in a
for-statement). In the case of a foreach-statement, this is
@@ -13037,6 +13055,16 @@ c_parse_pragma_ivdep (c_parser *parser)
return true;
}
+/* Parse a pragma GCC novector. */
+
+static bool
+c_parse_pragma_novector (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
@@ -13261,38 +13289,51 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
case PRAGMA_OMP_ORDERED:
return c_parser_omp_ordered (parser, context, if_p);
+ case PRAGMA_NOVECTOR:
+ case PRAGMA_UNROLL:
case PRAGMA_IVDEP:
{
- 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))
+ bool novector = false;
+ unsigned short unroll = 0;
+ bool ivdep = false;
+
+ switch (id)
{
- c_parser_error (parser, "for, while or do statement expected");
- return false;
+ case PRAGMA_NOVECTOR:
+ novector = c_parse_pragma_novector (parser);
+ break;
+ case PRAGMA_UNROLL:
+ unroll = c_parser_pragma_unroll (parser);
+ break;
+ case PRAGMA_IVDEP:
+ ivdep = c_parse_pragma_ivdep (parser);
+ break;
+ default:
+ gcc_unreachable ();
}
- 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 true;
- 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;
+ c_token *tok = c_parser_peek_token (parser);
+ bool has_more = tok->type == CPP_PRAGMA;
+ while (has_more)
+ {
+ switch (tok->pragma_kind)
+ {
+ case PRAGMA_IVDEP:
+ ivdep = c_parse_pragma_ivdep (parser);
+ break;
+ case PRAGMA_UNROLL:
+ unroll = c_parser_pragma_unroll (parser);
+ break;
+ case PRAGMA_NOVECTOR:
+ novector = c_parse_pragma_novector (parser);
+ break;
+ default:
+ has_more = false;
+ break;
+ }
+ tok = c_parser_peek_token (parser);
+ has_more = has_more && tok->type == CPP_PRAGMA;
+ }
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))
@@ -13301,11 +13342,11 @@ 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, if_p);
+ c_parser_for_statement (parser, ivdep, unroll, novector, if_p);
else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
- c_parser_while_statement (parser, ivdep, unroll, if_p);
+ c_parser_while_statement (parser, ivdep, unroll, novector, if_p);
else
- c_parser_do_statement (parser, ivdep, unroll);
+ c_parser_do_statement (parser, ivdep, unroll, novector);
}
return true;
diff --git a/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c b/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c
new file mode 100644
index 0000000000000000000000000000000000000000..3c0b8f5d2acbd276280785e8d0cbe1f7cd650266
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_int } */
+
+void f1 (int * restrict a, int * restrict b, int n)
+{
+#pragma GCC novector
+ for (int i = 0; i < (n & -8); i++)
+ a[i] += b[i];
+}
+
+void f2 (int * restrict a, int * restrict b, int n)
+{
+#pragma GCC novector
+#pragma GCC ivdep
+#pragma GCC unroll 2
+ for (int i = 0; i < (n & -8); i++)
+ a[i] += b[i];
+}
+
+void f3 (int * restrict a, int * restrict b, int n)
+{
+#pragma GCC ivdep
+#pragma GCC novector
+#pragma GCC unroll 2
+ for (int i = 0; i < (n & -8); i++)
+ a[i] += b[i];
+}
+
+void f4 (int * restrict a, int * restrict b, int n)
+{
+#pragma GCC ivdep
+#pragma GCC unroll 2
+#pragma GCC novector
+ for (int i = 0; i < (n & -8); i++)
+ a[i] += b[i];
+}
+
+void f5 (int * restrict a, int * restrict b, int n)
+{
+ int i = 0;
+#pragma GCC novector
+ do
+ {
+ a[i] += b[i];
+ i++;
+ }
+ while (i < (n & -8));
+}
+
+void f6 (int * restrict a, int * restrict b, int n)
+{
+ int i = 0;
+#pragma GCC novector
+ while (i < (n & -8))
+ {
+ a[i] += b[i];
+ i++;
+ }
+}
+
+/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2][frontend] Add novector C++ pragma
2023-07-26 19:32 ` Tamar Christina
@ 2023-07-26 20:52 ` Jason Merrill
0 siblings, 0 replies; 8+ messages in thread
From: Jason Merrill @ 2023-07-26 20:52 UTC (permalink / raw)
To: Tamar Christina, gcc-patches; +Cc: nd, nathan
On 7/26/23 15:32, Tamar Christina wrote:
>>> +
>>> + cp_token *tok = pragma_tok;
>>> +
>>> + do
>>> {
>>> - tok = cp_lexer_consume_token (parser->lexer);
>>> - ivdep = cp_parser_pragma_ivdep (parser, tok);
>>> - tok = cp_lexer_peek_token (the_parser->lexer);
>>> + 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);
>>> + tok = cp_lexer_peek_token (the_parser->lexer);
>>> + break;
>>> + }
>>> + case PRAGMA_UNROLL:
>>> + {
>>> + if (tok != pragma_tok)
>>> + tok = cp_lexer_consume_token (parser->lexer);
>>> + unroll = cp_parser_pragma_unroll (parser, tok);
>>> + tok = cp_lexer_peek_token (the_parser->lexer);
>>> + break;
>>> + }
>>> + case PRAGMA_NOVECTOR:
>>> + {
>>> + if (tok != pragma_tok)
>>> + tok = cp_lexer_consume_token (parser->lexer);
>>> + novector = cp_parser_pragma_novector (parser, tok);
>>> + tok = cp_lexer_peek_token (the_parser->lexer);
>>> + break;
>>> + }
>>> + default:
>>> + gcc_unreachable ();
>>
>> This unreachable seems to assert that if a pragma follows one of these
>> pragmas, it must be another one of these pragmas? That seems wrong;
>> instead of hitting gcc_unreachable() in that case we should fall through to the
>> diagnostic below.
>>
>
> Ah, good should. Since it has to exit two levels I had to introduce a bool
> for controlling the loop iterations. New patch below.
>
> Bootstrapped Regtested on aarch64-none-linux-gnu and no issues.
>
> Ok for master?
OK.
> Thanks,
> Tamar
>
> 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.
>
> --- inline copy of patch ---
>
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 8398223311194837441107cb335d497ff5f5ec1c..bece7bff1f01a23cfc94386fd3295a0be8c462fe 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -5377,6 +5377,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)
> @@ -7286,7 +7287,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);
> @@ -7609,16 +7610,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);
> diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
> index af6e30f511e142c7a594e742d128b2bf0aa8fb8d..5b735b27e6f5bc6b439ae64665902f4f1ca76f95 100644
> --- a/gcc/cp/init.cc
> +++ b/gcc/cp/init.cc
> @@ -4846,7 +4846,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
> diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
> index 91cf943f11089c0e6bcbe8377daa4e016f956d56..fce49c796199c2c65cd70684e2942fea1b6b2ebd 100644
> --- a/gcc/cp/method.cc
> +++ b/gcc/cp/method.cc
> @@ -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),
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index dd3665c8ccf48a8a0b1ba2c06400fe50999ea240..092f991d7a1b6aab8482d50848fb9fb96c377509 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -2324,15 +2324,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
> @@ -12414,7 +12414,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:
> @@ -13594,7 +13595,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;
> @@ -13624,14 +13626,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;
> @@ -13658,7 +13660,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);
>
> @@ -13682,7 +13684,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;
> @@ -13758,6 +13761,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. */
> @@ -13770,7 +13775,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;
> }
> @@ -13948,7 +13953,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;
> @@ -14008,7 +14013,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,
> @@ -14175,7 +14180,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;
> @@ -14209,7 +14214,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. */
> @@ -14244,7 +14249,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 `;'. */
> @@ -14258,7 +14263,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);
> @@ -43815,7 +43820,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,
> @@ -49300,6 +49305,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. */
>
> @@ -49605,58 +49619,73 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
> break;
>
> case PRAGMA_IVDEP:
> + case PRAGMA_UNROLL:
> + case PRAGMA_NOVECTOR:
> {
> - if (context == pragma_external)
> + bool ivdep;
> + unsigned short unroll = 0;
> + bool novector = false;
> + const char *pragma_str;
> +
> + switch (id)
> {
> - error_at (pragma_tok->location,
> - "%<#pragma GCC ivdep%> must be inside a function");
> + case PRAGMA_IVDEP:
> + pragma_str = "ivdep";
> 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:
> + pragma_str = "unroll";
> + break;
> + case PRAGMA_NOVECTOR:
> + pragma_str = "novector";
> + break;
> + default:
> + gcc_unreachable ();
> + }
>
> - case PRAGMA_UNROLL:
> - {
> 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
> @@ -49665,7 +49694,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;
> }
>
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 2345a18becc1160b9d12f3d88cccb66c8917373c..7b0d01a90e3c4012ec603ebe04cbbb31a7dd1570 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -19036,7 +19036,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);
> {
> @@ -19073,6 +19073,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);
> @@ -19083,7 +19084,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 ();
> @@ -19096,7 +19098,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));
> @@ -19114,7 +19116,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:
> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> index 8fb47fd179eb2af2e82bf31d188023e9b9d41de9..b79975109c22ebcfcb060b4f20f32f69f3c3c444 100644
> --- a/gcc/cp/semantics.cc
> +++ b/gcc/cp/semantics.cc
> @@ -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;
> }
>
> @@ -1325,7 +1337,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);
> @@ -1345,6 +1357,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));
> }
>
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index 3040a9bdea65d27f8d20572b4ed37375f5fe949b..baac6643d1abbf33d592e68aca49ac83e3c29188 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -24349,6 +24349,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}
>
> diff --git a/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc b/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc
> new file mode 100644
> index 0000000000000000000000000000000000000000..8c6ff22fcaabaa97516be72b77acbd44df86b1d2
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc
> @@ -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" } } */
> diff --git a/gcc/testsuite/g++.dg/vect/vect.exp b/gcc/testsuite/g++.dg/vect/vect.exp
> index df273233f47a788024bbe61128eaa96b639cb3b8..fc77120a83173c65ad147e8bb7c29ac82f06bb6d 100644
> --- a/gcc/testsuite/g++.dg/vect/vect.exp
> +++ b/gcc/testsuite/g++.dg/vect/vect.exp
> @@ -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
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: [PATCH 2/2][frontend]: Add novector C pragma
2023-07-26 19:35 ` Tamar Christina
@ 2023-08-02 9:44 ` Tamar Christina
2023-08-02 17:54 ` Joseph Myers
0 siblings, 1 reply; 8+ messages in thread
From: Tamar Christina @ 2023-08-02 9:44 UTC (permalink / raw)
To: gcc-patches; +Cc: nd, joseph
Ping.
> -----Original Message-----
> From: Tamar Christina <Tamar.Christina@arm.com>
> Sent: Wednesday, July 26, 2023 8:35 PM
> To: Tamar Christina <Tamar.Christina@arm.com>; gcc-patches@gcc.gnu.org
> Cc: nd <nd@arm.com>; joseph@codesourcery.com
> Subject: RE: [PATCH 2/2][frontend]: Add novector C pragma
>
> Hi, This is a respin of the patch taking in the feedback received from the C++
> part.
>
> Simultaneously it's also a ping 😊
>
> ----
>
> Hi All,
>
> 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.
>
> Bootstrapped Regtested on aarch64-none-linux-gnu and no issues.
>
> Ok for master?
>
> Thanks,
> Tamar
>
> gcc/c-family/ChangeLog:
>
> * c-pragma.h (enum pragma_kind): Add PRAGMA_NOVECTOR.
> * c-pragma.cc (init_pragma): Use it.
>
> gcc/c/ChangeLog:
>
> * c-parser.cc (c_parser_while_statement, c_parser_do_statement,
> c_parser_for_statement, c_parser_statement_after_labels,
> c_parse_pragma_novector, c_parser_pragma): Wire through novector
> and
> default to false.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.dg/vect/vect-novector-pragma.c: New test.
>
> --- inline copy of patch ---
>
> diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index
> 9cc95ab3ee376628dbef2485b84e6008210fa8fc..99cf2e8bd1c05537c1984
> 70f1aaa0a5a9da4e576 100644
> --- a/gcc/c-family/c-pragma.h
> +++ b/gcc/c-family/c-pragma.h
> @@ -87,6 +87,7 @@ enum pragma_kind {
> PRAGMA_GCC_PCH_PREPROCESS,
> PRAGMA_IVDEP,
> PRAGMA_UNROLL,
> + PRAGMA_NOVECTOR,
>
> PRAGMA_FIRST_EXTERNAL
> };
> diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc index
> 0d2b333cebbed32423d5dc6fd2a3ac0ce0bf8b94..848a850b8e123ff1c6ae1e
> c4b7f8ccbd599b1a88 100644
> --- a/gcc/c-family/c-pragma.cc
> +++ b/gcc/c-family/c-pragma.cc
> @@ -1862,6 +1862,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", "novector",
> PRAGMA_NOVECTOR,
> + false, false);
> +
> #ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION
> c_register_pragma_with_expansion (0, "pack", handle_pragma_pack); #else
> diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index
> 24a6eb6e4596f32c477e3f1c3f98b9792f7bc92c..74f3cbb0d61b5f4c0eb300
> 672f495dde3f1517f7 100644
> --- a/gcc/c/c-parser.cc
> +++ b/gcc/c/c-parser.cc
> @@ -1572,9 +1572,11 @@ 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 *); -static
> void c_parser_do_statement (c_parser *, bool, unsigned short); -static void
> c_parser_for_statement (c_parser *, bool, unsigned short, 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 tree c_parser_asm_statement (c_parser *); static tree
> c_parser_asm_operands (c_parser *); static tree
> c_parser_asm_goto_operands (c_parser *); @@ -6644,13 +6646,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, if_p);
> + c_parser_while_statement (parser, false, 0, false, if_p);
> break;
> case RID_DO:
> - c_parser_do_statement (parser, false, 0);
> + c_parser_do_statement (parser, false, 0, false);
> break;
> case RID_FOR:
> - c_parser_for_statement (parser, false, 0, if_p);
> + c_parser_for_statement (parser, false, 0, false, if_p);
> break;
> case RID_GOTO:
> c_parser_consume_token (parser);
> @@ -7146,7 +7148,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 *if_p)
> + bool novector, bool *if_p)
> {
> tree block, cond, body;
> unsigned char save_in_statement;
> @@ -7168,6 +7170,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 (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);
> save_in_statement = in_statement;
> in_statement = IN_ITERATION_STMT;
>
> @@ -7199,7 +7206,8 @@ 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)
> +c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll,
> + bool novector)
> {
> tree block, cond, body;
> unsigned char save_in_statement;
> @@ -7228,6 +7236,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 (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);
> if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
> c_parser_skip_to_end_of_block_or_statement (parser);
>
> @@ -7296,7 +7309,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 *if_p)
> + bool novector, bool *if_p)
> {
> tree block, cond, incr, body;
> unsigned char save_in_statement;
> @@ -7452,6 +7465,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 (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);
> }
> /* Parse the increment expression (the third expression in a
> for-statement). In the case of a foreach-statement, this is @@ -
> 13037,6 +13055,16 @@ c_parse_pragma_ivdep (c_parser *parser)
> return true;
> }
>
> +/* Parse a pragma GCC novector. */
> +
> +static bool
> +c_parse_pragma_novector (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
> @@ -13261,38 +13289,51 @@ c_parser_pragma (c_parser *parser, enum
> pragma_context context, bool *if_p)
> case PRAGMA_OMP_ORDERED:
> return c_parser_omp_ordered (parser, context, if_p);
>
> + case PRAGMA_NOVECTOR:
> + case PRAGMA_UNROLL:
> case PRAGMA_IVDEP:
> {
> - 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))
> + bool novector = false;
> + unsigned short unroll = 0;
> + bool ivdep = false;
> +
> + switch (id)
> {
> - c_parser_error (parser, "for, while or do statement expected");
> - return false;
> + case PRAGMA_NOVECTOR:
> + novector = c_parse_pragma_novector (parser);
> + break;
> + case PRAGMA_UNROLL:
> + unroll = c_parser_pragma_unroll (parser);
> + break;
> + case PRAGMA_IVDEP:
> + ivdep = c_parse_pragma_ivdep (parser);
> + break;
> + default:
> + gcc_unreachable ();
> }
> - 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 true;
>
> - 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;
> + c_token *tok = c_parser_peek_token (parser);
> + bool has_more = tok->type == CPP_PRAGMA;
> + while (has_more)
> + {
> + switch (tok->pragma_kind)
> + {
> + case PRAGMA_IVDEP:
> + ivdep = c_parse_pragma_ivdep (parser);
> + break;
> + case PRAGMA_UNROLL:
> + unroll = c_parser_pragma_unroll (parser);
> + break;
> + case PRAGMA_NOVECTOR:
> + novector = c_parse_pragma_novector (parser);
> + break;
> + default:
> + has_more = false;
> + break;
> + }
> + tok = c_parser_peek_token (parser);
> + has_more = has_more && tok->type == CPP_PRAGMA;
> + }
> 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)) @@ -
> 13301,11 +13342,11 @@ 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, if_p);
> + c_parser_for_statement (parser, ivdep, unroll, novector, if_p);
> else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
> - c_parser_while_statement (parser, ivdep, unroll, if_p);
> + c_parser_while_statement (parser, ivdep, unroll, novector, if_p);
> else
> - c_parser_do_statement (parser, ivdep, unroll);
> + c_parser_do_statement (parser, ivdep, unroll, novector);
> }
> return true;
>
> diff --git a/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c
> b/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..3c0b8f5d2acbd27628
> 0785e8d0cbe1f7cd650266
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c
> @@ -0,0 +1,61 @@
> +/* { dg-do compile } */
> +/* { dg-require-effective-target vect_int } */
> +
> +void f1 (int * restrict a, int * restrict b, int n) { #pragma GCC
> +novector
> + for (int i = 0; i < (n & -8); i++)
> + a[i] += b[i];
> +}
> +
> +void f2 (int * restrict a, int * restrict b, int n) { #pragma GCC
> +novector #pragma GCC ivdep #pragma GCC unroll 2
> + for (int i = 0; i < (n & -8); i++)
> + a[i] += b[i];
> +}
> +
> +void f3 (int * restrict a, int * restrict b, int n) { #pragma GCC ivdep
> +#pragma GCC novector #pragma GCC unroll 2
> + for (int i = 0; i < (n & -8); i++)
> + a[i] += b[i];
> +}
> +
> +void f4 (int * restrict a, int * restrict b, int n) { #pragma GCC ivdep
> +#pragma GCC unroll 2 #pragma GCC novector
> + for (int i = 0; i < (n & -8); i++)
> + a[i] += b[i];
> +}
> +
> +void f5 (int * restrict a, int * restrict b, int n) {
> + int i = 0;
> +#pragma GCC novector
> + do
> + {
> + a[i] += b[i];
> + i++;
> + }
> + while (i < (n & -8));
> +}
> +
> +void f6 (int * restrict a, int * restrict b, int n) {
> + int i = 0;
> +#pragma GCC novector
> + while (i < (n & -8))
> + {
> + a[i] += b[i];
> + i++;
> + }
> +}
> +
> +/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */
^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: [PATCH 2/2][frontend]: Add novector C pragma
2023-08-02 9:44 ` Tamar Christina
@ 2023-08-02 17:54 ` Joseph Myers
0 siblings, 0 replies; 8+ messages in thread
From: Joseph Myers @ 2023-08-02 17:54 UTC (permalink / raw)
To: Tamar Christina; +Cc: gcc-patches, nd
[-- Attachment #1: Type: text/plain, Size: 576 bytes --]
On Wed, 2 Aug 2023, Tamar Christina via Gcc-patches wrote:
> Ping.
>
> > -----Original Message-----
> > From: Tamar Christina <Tamar.Christina@arm.com>
> > Sent: Wednesday, July 26, 2023 8:35 PM
> > To: Tamar Christina <Tamar.Christina@arm.com>; gcc-patches@gcc.gnu.org
> > Cc: nd <nd@arm.com>; joseph@codesourcery.com
> > Subject: RE: [PATCH 2/2][frontend]: Add novector C pragma
> >
> > Hi, This is a respin of the patch taking in the feedback received from the C++
> > part.
> >
> > Simultaneously it's also a ping 😊
OK.
--
Joseph S. Myers
joseph@codesourcery.com
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2023-08-02 17:54 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-19 15:15 [PATCH 1/2][frontend] Add novector C++ pragma Tamar Christina
2023-07-19 15:16 ` [PATCH 2/2][frontend]: Add novector C pragma Tamar Christina
2023-07-26 19:35 ` Tamar Christina
2023-08-02 9:44 ` Tamar Christina
2023-08-02 17:54 ` Joseph Myers
2023-07-25 20:53 ` [PATCH 1/2][frontend] Add novector C++ pragma Jason Merrill
2023-07-26 19:32 ` Tamar Christina
2023-07-26 20:52 ` Jason Merrill
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).