c++: Further #pragma GCC unroll C++ fix [PR112795]
When committing the #pragma GCC unroll patch, I found I forgot one spot for diagnosting the invalid unrolls - if #pragma GCC unroll argument is dependent and the pragma is before a range for loop, the unroll tree (now, before one converted form ushort) is saved into RANGE_FOR_UNROLL and tsubst_stmt was RECURing on it, but didn't diagnose if it was invalid and so we ICEd later in the middle-end when ANNOTATE_EXPR had unexpected argument. The following patch fixes that. So that the diagnostics isn't done in 3 different places, the patch introduces a new function that both cp_parser_pragma_unroll and instantiation of ANNOTATE_EXPR and RANGE_FOR_STMT can use. 2023-12-05 Jakub Jelinek <jakub@redhat.com> PR c++/112795 * cp-tree.h (cp_check_pragma_unroll): Declare. * semantics.cc (cp_check_pragma_unroll): New function. * parser.cc (cp_parser_pragma_unroll): Use cp_check_pragma_unroll. * pt.cc (tsubst_expr) <case ANNOTATE_EXPR>: Likewise. (tsubst_stmt) <case RANGE_FOR_STMT>: Likwsie. * g++.dg/ext/unroll-2.C: Use { target c++11 } instead of dg-skip-if for -std=gnu++98. * g++.dg/ext/unroll-3.C: Likewise. * g++.dg/ext/unroll-7.C: New test. * g++.dg/ext/unroll-8.C: New test.
This commit is contained in:
parent
58d5546af9
commit
59be79fd59
8 changed files with 175 additions and 56 deletions
|
@ -7918,6 +7918,7 @@ extern tree most_general_lambda (tree);
|
|||
extern tree finish_omp_target (location_t, tree, tree, bool);
|
||||
extern void finish_omp_target_clauses (location_t, tree, tree *);
|
||||
extern void maybe_warn_unparenthesized_assignment (tree, tsubst_flags_t);
|
||||
extern tree cp_check_pragma_unroll (location_t, tree);
|
||||
|
||||
/* in tree.cc */
|
||||
extern int cp_tree_operand_length (const_tree);
|
||||
|
|
|
@ -50261,27 +50261,7 @@ cp_parser_pragma_unroll (cp_parser *parser, cp_token *pragma_tok)
|
|||
{
|
||||
location_t location = cp_lexer_peek_token (parser->lexer)->location;
|
||||
tree unroll = cp_parser_constant_expression (parser);
|
||||
unroll = fold_non_dependent_expr (unroll);
|
||||
HOST_WIDE_INT lunroll = 0;
|
||||
if (type_dependent_expression_p (unroll))
|
||||
;
|
||||
else if (!INTEGRAL_TYPE_P (TREE_TYPE (unroll))
|
||||
|| (!value_dependent_expression_p (unroll)
|
||||
&& (!tree_fits_shwi_p (unroll)
|
||||
|| (lunroll = tree_to_shwi (unroll)) < 0
|
||||
|| lunroll >= USHRT_MAX)))
|
||||
{
|
||||
error_at (location, "%<#pragma GCC unroll%> requires an"
|
||||
" assignment-expression that evaluates to a non-negative"
|
||||
" integral constant less than %u", USHRT_MAX);
|
||||
unroll = NULL_TREE;
|
||||
}
|
||||
else if (TREE_CODE (unroll) == INTEGER_CST)
|
||||
{
|
||||
unroll = fold_convert (integer_type_node, unroll);
|
||||
if (integer_zerop (unroll))
|
||||
unroll = integer_one_node;
|
||||
}
|
||||
unroll = cp_check_pragma_unroll (location, fold_non_dependent_expr (unroll));
|
||||
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
|
||||
return unroll;
|
||||
}
|
||||
|
|
42
gcc/cp/pt.cc
42
gcc/cp/pt.cc
|
@ -18407,22 +18407,24 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
complain, in_decl, decomp);
|
||||
}
|
||||
|
||||
tree unroll = RECUR (RANGE_FOR_UNROLL (t));
|
||||
if (unroll)
|
||||
unroll
|
||||
= cp_check_pragma_unroll (EXPR_LOCATION (RANGE_FOR_UNROLL (t)),
|
||||
unroll);
|
||||
if (processing_template_decl)
|
||||
{
|
||||
RANGE_FOR_IVDEP (stmt) = RANGE_FOR_IVDEP (t);
|
||||
RANGE_FOR_UNROLL (stmt) = RANGE_FOR_UNROLL (t);
|
||||
RANGE_FOR_UNROLL (stmt) = unroll;
|
||||
RANGE_FOR_NOVECTOR (stmt) = RANGE_FOR_NOVECTOR (t);
|
||||
finish_range_for_decl (stmt, decl, expr);
|
||||
if (decomp && decl != error_mark_node)
|
||||
cp_finish_decomp (decl, decomp);
|
||||
}
|
||||
else
|
||||
{
|
||||
tree unroll = RECUR (RANGE_FOR_UNROLL (t));
|
||||
stmt = cp_convert_range_for (stmt, decl, expr, decomp,
|
||||
RANGE_FOR_IVDEP (t), unroll,
|
||||
RANGE_FOR_NOVECTOR (t));
|
||||
}
|
||||
stmt = cp_convert_range_for (stmt, decl, expr, decomp,
|
||||
RANGE_FOR_IVDEP (t), unroll,
|
||||
RANGE_FOR_NOVECTOR (t));
|
||||
|
||||
bool prev = note_iteration_stmt_body_start ();
|
||||
RECUR (RANGE_FOR_BODY (t));
|
||||
|
@ -21506,30 +21508,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
tree op3 = RECUR (TREE_OPERAND (t, 2));
|
||||
if (TREE_CODE (op2) == INTEGER_CST
|
||||
&& wi::to_widest (op2) == (int) annot_expr_unroll_kind)
|
||||
{
|
||||
HOST_WIDE_INT lunroll;
|
||||
if (type_dependent_expression_p (op3))
|
||||
;
|
||||
else if (!INTEGRAL_TYPE_P (TREE_TYPE (op3))
|
||||
|| (!value_dependent_expression_p (op3)
|
||||
&& (!tree_fits_shwi_p (op3)
|
||||
|| (lunroll = tree_to_shwi (op3)) < 0
|
||||
|| lunroll >= USHRT_MAX)))
|
||||
{
|
||||
error_at (EXPR_LOCATION (TREE_OPERAND (t, 2)),
|
||||
"%<#pragma GCC unroll%> requires an "
|
||||
"assignment-expression that evaluates to a "
|
||||
"non-negative integral constant less than %u",
|
||||
USHRT_MAX);
|
||||
op3 = integer_one_node;
|
||||
}
|
||||
else if (TREE_CODE (op3) == INTEGER_CST)
|
||||
{
|
||||
op3 = fold_convert (integer_type_node, op3);
|
||||
if (integer_zerop (op3))
|
||||
op3 = integer_one_node;
|
||||
}
|
||||
}
|
||||
op3 = cp_check_pragma_unroll (EXPR_LOCATION (TREE_OPERAND (t, 2)),
|
||||
op3);
|
||||
RETURN (build3_loc (EXPR_LOCATION (t), ANNOTATE_EXPR,
|
||||
TREE_TYPE (op1), op1, op2, op3));
|
||||
}
|
||||
|
|
|
@ -13016,4 +13016,33 @@ cp_build_bit_cast (location_t loc, tree type, tree arg,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Diagnose invalid #pragma GCC unroll argument and adjust
|
||||
it if needed. */
|
||||
|
||||
tree
|
||||
cp_check_pragma_unroll (location_t loc, tree unroll)
|
||||
{
|
||||
HOST_WIDE_INT lunroll = 0;
|
||||
if (type_dependent_expression_p (unroll))
|
||||
;
|
||||
else if (!INTEGRAL_TYPE_P (TREE_TYPE (unroll))
|
||||
|| (!value_dependent_expression_p (unroll)
|
||||
&& (!tree_fits_shwi_p (unroll)
|
||||
|| (lunroll = tree_to_shwi (unroll)) < 0
|
||||
|| lunroll >= USHRT_MAX)))
|
||||
{
|
||||
error_at (loc, "%<#pragma GCC unroll%> requires an"
|
||||
" assignment-expression that evaluates to a non-negative"
|
||||
" integral constant less than %u", USHRT_MAX);
|
||||
unroll = integer_one_node;
|
||||
}
|
||||
else if (TREE_CODE (unroll) == INTEGER_CST)
|
||||
{
|
||||
unroll = fold_convert (integer_type_node, unroll);
|
||||
if (integer_zerop (unroll))
|
||||
unroll = integer_one_node;
|
||||
}
|
||||
return unroll;
|
||||
}
|
||||
|
||||
#include "gt-cp-semantics.h"
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// { dg-do compile }
|
||||
// { dg-do compile { target c++11 } }
|
||||
// { dg-options "-O2 -fdump-tree-cunrolli-details" }
|
||||
// { dg-skip-if "range for" { *-*-* } { "-std=gnu++98" } { "" } }
|
||||
|
||||
void
|
||||
foo (int (&a)[8], int *b, int *c)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// { dg-do compile }
|
||||
// { dg-do compile { target c++11 } }
|
||||
// { dg-options "-O2 -fdump-tree-cunrolli-details" }
|
||||
// { dg-skip-if "range for" { *-*-* } { "-std=gnu++98" } { "" } }
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
|
|
45
gcc/testsuite/g++.dg/ext/unroll-7.C
Normal file
45
gcc/testsuite/g++.dg/ext/unroll-7.C
Normal file
|
@ -0,0 +1,45 @@
|
|||
// PR c++/112795
|
||||
// { dg-do compile { target c++11 } }
|
||||
// { dg-options "-O2 -fdump-tree-cunrolli-details" }
|
||||
|
||||
void baz (int);
|
||||
constexpr int n = 3;
|
||||
constexpr int m = 7;
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
foo (int (&a)[3], T b)
|
||||
{
|
||||
#pragma GCC unroll(n)
|
||||
for (auto i : a)
|
||||
baz (i);
|
||||
#pragma GCC unroll(m)
|
||||
for (auto i : b)
|
||||
baz (i);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
void
|
||||
bar (int (&a)[N])
|
||||
{
|
||||
#pragma GCC unroll(N)
|
||||
for (auto i : a)
|
||||
baz (i);
|
||||
}
|
||||
|
||||
void
|
||||
qux ()
|
||||
{
|
||||
int a[3] = { 1, 2, 3 };
|
||||
int b[7] = { 4, 5, 6, 7, 8, 9, 10 };
|
||||
int c[6] = { 11, 12, 13, 14, 15, 16 };
|
||||
int d[10] = { 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 };
|
||||
foo <int (&)[7]> (a, b);
|
||||
bar <6> (c);
|
||||
bar <10> (d);
|
||||
}
|
||||
|
||||
// { dg-final { scan-tree-dump "loop with 3 iterations completely unrolled" "cunrolli" } }
|
||||
// { dg-final { scan-tree-dump "loop with 6 iterations completely unrolled" "cunrolli" } }
|
||||
// { dg-final { scan-tree-dump "loop with 7 iterations completely unrolled" "cunrolli" } }
|
||||
// { dg-final { scan-tree-dump "loop with 10 iterations completely unrolled" "cunrolli" } }
|
86
gcc/testsuite/g++.dg/ext/unroll-8.C
Normal file
86
gcc/testsuite/g++.dg/ext/unroll-8.C
Normal file
|
@ -0,0 +1,86 @@
|
|||
// PR c++/112795
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
void
|
||||
foo (int (&a)[3])
|
||||
{
|
||||
#pragma GCC unroll 1.0f // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" }
|
||||
for (auto i : a)
|
||||
;
|
||||
#pragma GCC unroll 0xffffffffffffffffULL // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" }
|
||||
for (auto i : a)
|
||||
;
|
||||
#pragma GCC unroll -42 // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" }
|
||||
for (auto i : a)
|
||||
;
|
||||
}
|
||||
|
||||
template <int N, typename U>
|
||||
void
|
||||
bar (U a)
|
||||
{
|
||||
#pragma GCC unroll 1.0f // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" }
|
||||
for (auto i : a)
|
||||
;
|
||||
#pragma GCC unroll 0xffffffffffffffffULL // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" }
|
||||
for (auto i : a)
|
||||
;
|
||||
#pragma GCC unroll -42 // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" }
|
||||
for (auto i : a)
|
||||
;
|
||||
}
|
||||
|
||||
template <typename T, int N, typename U>
|
||||
void
|
||||
baz (U a)
|
||||
{
|
||||
#pragma GCC unroll (N + 1.0f) // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" }
|
||||
for (auto i : a)
|
||||
;
|
||||
#pragma GCC unroll (N + 0xffffffffffffffffULL)
|
||||
for (auto i : a)
|
||||
;
|
||||
#pragma GCC unroll (N - 42)
|
||||
for (auto i : a)
|
||||
;
|
||||
#pragma GCC unroll ((T) 1.0f)
|
||||
for (auto i : a)
|
||||
;
|
||||
#pragma GCC unroll ((T) 0xffffffffffffffffULL)
|
||||
for (auto i : a)
|
||||
;
|
||||
#pragma GCC unroll ((T) -42)
|
||||
for (auto i : a)
|
||||
;
|
||||
}
|
||||
|
||||
template <typename T, int N, typename U>
|
||||
void
|
||||
qux (U a)
|
||||
{
|
||||
#pragma GCC unroll (N + 1.0f) // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" }
|
||||
for (auto i : a)
|
||||
;
|
||||
#pragma GCC unroll (N + 0xffffffffffffffffULL)// { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" }
|
||||
for (auto i : a)
|
||||
;
|
||||
#pragma GCC unroll (N - 42) // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" }
|
||||
for (auto i : a)
|
||||
;
|
||||
#pragma GCC unroll ((T) 1.0f) // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" }
|
||||
for (auto i : a)
|
||||
;
|
||||
#pragma GCC unroll ((T) 0xffffffffffffffffULL)// { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" }
|
||||
for (auto i : a)
|
||||
;
|
||||
#pragma GCC unroll ((T) -42) // { dg-error "'#pragma GCC unroll' requires an assignment-expression that evaluates to a non-negative integral constant less than" }
|
||||
for (auto i : a)
|
||||
;
|
||||
}
|
||||
|
||||
void
|
||||
corge ()
|
||||
{
|
||||
int a[3] = { 1, 2, 3 };
|
||||
qux <float, 0, int (&)[3]> (a);
|
||||
}
|
Loading…
Add table
Reference in a new issue