diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index fef80816c5f..795152c9ad2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 1049a75b384..732d2a919eb 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -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; } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 924a20973b4..5765982277e 100644 --- a/gcc/cp/pt.cc +++ b/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)); } diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index cbabfad5e26..6634acfda3f 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -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" diff --git a/gcc/testsuite/g++.dg/ext/unroll-2.C b/gcc/testsuite/g++.dg/ext/unroll-2.C index f9ec892dbdd..dfbe4ef91e2 100644 --- a/gcc/testsuite/g++.dg/ext/unroll-2.C +++ b/gcc/testsuite/g++.dg/ext/unroll-2.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" } { "" } } void foo (int (&a)[8], int *b, int *c) diff --git a/gcc/testsuite/g++.dg/ext/unroll-3.C b/gcc/testsuite/g++.dg/ext/unroll-3.C index dda94c56af2..007a5b2eb52 100644 --- a/gcc/testsuite/g++.dg/ext/unroll-3.C +++ b/gcc/testsuite/g++.dg/ext/unroll-3.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 void diff --git a/gcc/testsuite/g++.dg/ext/unroll-7.C b/gcc/testsuite/g++.dg/ext/unroll-7.C new file mode 100644 index 00000000000..d0630104988 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/unroll-7.C @@ -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 +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 +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 (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" } } diff --git a/gcc/testsuite/g++.dg/ext/unroll-8.C b/gcc/testsuite/g++.dg/ext/unroll-8.C new file mode 100644 index 00000000000..935ada24fbf --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/unroll-8.C @@ -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 +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 +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 +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 (a); +}