]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Further #pragma GCC unroll C++ fix [PR112795]
authorJakub Jelinek <jakub@redhat.com>
Tue, 5 Dec 2023 21:54:08 +0000 (22:54 +0100)
committerJakub Jelinek <jakub@redhat.com>
Tue, 5 Dec 2023 21:54:08 +0000 (22:54 +0100)
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.

gcc/cp/cp-tree.h
gcc/cp/parser.cc
gcc/cp/pt.cc
gcc/cp/semantics.cc
gcc/testsuite/g++.dg/ext/unroll-2.C
gcc/testsuite/g++.dg/ext/unroll-3.C
gcc/testsuite/g++.dg/ext/unroll-7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/unroll-8.C [new file with mode: 0644]

index fef80816c5f6712b5583f4326bece80a10209e9e..795152c9ad2f87978c9d40e3f721255e25226815 100644 (file)
@@ -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);
index 1049a75b384f664dae8399143a1b9b771a4f9884..732d2a919ebde0e1d9765b0dd570fe256c6d682f 100644 (file)
@@ -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;
 }
index 924a20973b4043abbf11305b6813e021c6c56010..5765982277e28e4736bfd7e72a5f2597d499e049 100644 (file)
@@ -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));
       }
index cbabfad5e264f81da93a8407bfc4ac8b25b9e8d4..6634acfda3fb1949d99b191aa2f177259d07f8ad 100644 (file)
@@ -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"
index f9ec892dbddfd3f390495fab445982f4e95b7c4b..dfbe4ef91e25731ad0260780cd533030c1cbbdb3 100644 (file)
@@ -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)
index dda94c56af22e2e96e84331df4a1cf94c59cb12c..007a5b2eb525df6355b7b577899950780a522f45 100644 (file)
@@ -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
diff --git a/gcc/testsuite/g++.dg/ext/unroll-7.C b/gcc/testsuite/g++.dg/ext/unroll-7.C
new file mode 100644 (file)
index 0000000..d063010
--- /dev/null
@@ -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" } }
diff --git a/gcc/testsuite/g++.dg/ext/unroll-8.C b/gcc/testsuite/g++.dg/ext/unroll-8.C
new file mode 100644 (file)
index 0000000..935ada2
--- /dev/null
@@ -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);
+}