Hi!

modules.cc has apparently support for extensions and attempts to ensure
that if a module is compiled with those extensions enabled, sources which
use the module are compiled with the same extensions.
The only extension supported is SE_OPENMP right now.
And the use of the extension is keyed on streaming out or in OMP_CLAUSE
tree.
This is undesirable for several reasons.
OMP_CLAUSE is the only tree which can appear in the IL even without
-fopenmp/-fopenmp-simd/-fopenacc (when simd ("notinbranch") or
simd ("inbranch") attributes are used), and it can appear also in all
the 3 modes mentioned above.  On the other side, with the exception of
arguments of attributes added e.g. for declare simd where no harm should
be done if -fopenmp/-fopenmp-simd isn't enabled later on, OMP_CLAUSE appears
in OMP_*_CLAUSES of OpenMP/OpenACC construct trees.  And those construct
trees often have no clauses at all, so keying the extension on OMP_CLAUSE
doesn't catch many cases that should be caught.
Furthermore, for OpenMP we have 2 modes, -fopenmp-simd which parses some
OpenMP but constructs from that mostly OMP_SIMD and a few other cases,
and -fopenmp which includes that and far more on top of that; and there is
also -fopenacc.

So, this patch stops setting/requesting the extension on OMP_CLAUSE,
introduces 3 extensions rather than one (SE_OPENMP_SIMD, SE_OPENMP and
SE_OPENACC) and keyes those on OpenMP constructs from the -fopenmp-simd
subset, other OpenMP constructs and OpenACC constructs.

2025-03-05  Jakub Jelinek  <ja...@redhat.com>

        PR c++/119102
gcc/cp/
        * module.cc (enum streamed_extensions): Add SE_OPENMP_SIMD
        and SE_OPENACC, change value of SE_OPENMP and SE_BITS.
        (CASE_OMP_SIMD_CODE, CASE_OMP_CODE, CASE_OACC_CODE): Define.
        (trees_out::start): Don't set SE_OPENMP extension for OMP_CLAUSE.
        Set SE_OPENMP_SIMD extension for CASE_OMP_SIMD_CODE, SE_OPENMP
        for CASE_OMP_CODE and SE_OPENACC for CASE_OACC_CODE.
        (trees_in::start): Don't fail for OMP_CLAUSE with missing
        SE_OPENMP extension.  Do fail for CASE_OMP_SIMD_CODE and missing
        SE_OPENMP_SIMD extension, or CASE_OMP_CODE and missing SE_OPENMP
        extension, or CASE_OACC_CODE and missing SE_OPENACC extension.
        (module_state::write_readme): Write all of SE_OPENMP_SIMD, SE_OPENMP
        and SE_OPENACC extensions.
        (module_state::read_config): Diagnose missing -fopenmp, -fopenmp-simd
        and/or -fopenacc depending on extensions used.
gcc/testsuite/
        * g++.dg/modules/pr119102_a.H: New test.
        * g++.dg/modules/pr119102_b.C: New test.
        * g++.dg/modules/omp-3_a.C: New test.
        * g++.dg/modules/omp-3_b.C: New test.
        * g++.dg/modules/omp-3_c.C: New test.
        * g++.dg/modules/omp-3_d.C: New test.
        * g++.dg/modules/oacc-1_a.C: New test.
        * g++.dg/modules/oacc-1_b.C: New test.
        * g++.dg/modules/oacc-1_c.C: New test.

--- gcc/cp/module.cc.jj 2025-03-03 17:36:37.263748933 +0100
+++ gcc/cp/module.cc    2025-03-04 17:52:16.439987517 +0100
@@ -3613,8 +3613,10 @@ void slurping::release_macros ()
 /* Flags for extensions that end up being streamed.  */
 
 enum streamed_extensions {
-  SE_OPENMP = 1 << 0,
-  SE_BITS = 1
+  SE_OPENMP_SIMD = 1 << 0,
+  SE_OPENMP = 1 << 1,
+  SE_OPENACC = 1 << 2,
+  SE_BITS = 3
 };
 
 /* Counter indices.  */
@@ -5276,6 +5278,53 @@ trees_in::tree_list (bool has_purpose)
 
   return res;
 }
+
+#define CASE_OMP_SIMD_CODE \
+    case OMP_SIMD:                     \
+    case OMP_STRUCTURED_BLOCK:         \
+    case OMP_LOOP:                     \
+    case OMP_ORDERED:                  \
+    case OMP_TILE:                     \
+    case OMP_UNROLL
+#define CASE_OMP_CODE \
+    case OMP_PARALLEL:                 \
+    case OMP_TASK:                     \
+    case OMP_FOR:                      \
+    case OMP_DISTRIBUTE:               \
+    case OMP_TASKLOOP:                 \
+    case OMP_TEAMS:                    \
+    case OMP_TARGET_DATA:              \
+    case OMP_TARGET:                   \
+    case OMP_SECTIONS:                 \
+    case OMP_CRITICAL:                 \
+    case OMP_SINGLE:                   \
+    case OMP_SCOPE:                    \
+    case OMP_TASKGROUP:                        \
+    case OMP_MASKED:                   \
+    case OMP_DISPATCH:                 \
+    case OMP_INTEROP:                  \
+    case OMP_MASTER:                   \
+    case OMP_TARGET_UPDATE:            \
+    case OMP_TARGET_ENTER_DATA:                \
+    case OMP_TARGET_EXIT_DATA:         \
+    case OMP_METADIRECTIVE:            \
+    case OMP_ATOMIC:                   \
+    case OMP_ATOMIC_READ:              \
+    case OMP_ATOMIC_CAPTURE_OLD:       \
+    case OMP_ATOMIC_CAPTURE_NEW
+#define CASE_OACC_CODE \
+    case OACC_PARALLEL:                        \
+    case OACC_KERNELS:                 \
+    case OACC_SERIAL:                  \
+    case OACC_DATA:                    \
+    case OACC_HOST_DATA:               \
+    case OACC_LOOP:                    \
+    case OACC_CACHE:                   \
+    case OACC_DECLARE:                 \
+    case OACC_ENTER_DATA:              \
+    case OACC_EXIT_DATA:               \
+    case OACC_UPDATE
+
 /* Start tree write.  Write information to allocate the receiving
    node.  */
 
@@ -5311,10 +5360,21 @@ trees_out::start (tree t, bool code_stre
       break;
 
     case OMP_CLAUSE:
-      state->extensions |= SE_OPENMP;
       u (OMP_CLAUSE_CODE (t));
       break;
 
+    CASE_OMP_SIMD_CODE:
+      state->extensions |= SE_OPENMP_SIMD;
+      break;
+
+    CASE_OMP_CODE:
+      state->extensions |= SE_OPENMP;
+      break;
+
+    CASE_OACC_CODE:
+      state->extensions |= SE_OPENACC;
+      break;
+
     case STRING_CST:
       str (TREE_STRING_POINTER (t), TREE_STRING_LENGTH (t));
       break;
@@ -5383,13 +5443,25 @@ trees_in::start (unsigned code)
       break;
 
     case OMP_CLAUSE:
-      {
-       if (!(state->extensions & SE_OPENMP))
-         goto fail;
+      t = build_omp_clause (UNKNOWN_LOCATION, omp_clause_code (u ()));
+      break;
 
-       unsigned omp_code = u ();
-       t = build_omp_clause (UNKNOWN_LOCATION, omp_clause_code (omp_code));
-      }
+    CASE_OMP_SIMD_CODE:
+      if (!(state->extensions & SE_OPENMP_SIMD))
+       goto fail;
+      t = make_node (tree_code (code));
+      break;
+
+    CASE_OMP_CODE:
+      if (!(state->extensions & SE_OPENMP))
+       goto fail;
+      t = make_node (tree_code (code));
+      break;
+
+    CASE_OACC_CODE:
+      if (!(state->extensions & SE_OPENACC))
+       goto fail;
+      t = make_node (tree_code (code));
       break;
 
     case STRING_CST:
@@ -15402,8 +15474,13 @@ module_state::write_readme (elf_out *to,
   readme.printf ("source: %s", main_input_filename);
   readme.printf ("dialect: %s", dialect);
   if (extensions)
-    readme.printf ("extensions: %s",
-                  extensions & SE_OPENMP ? "-fopenmp" : "");
+    readme.printf ("extensions: %s%s%s",
+                  extensions & SE_OPENMP ? "-fopenmp"
+                  : extensions & SE_OPENMP_SIMD ? "-fopenmp-simd" : "",
+                  (extensions & SE_OPENACC)
+                  && (extensions & (SE_OPENMP | SE_OPENMP_SIMD))
+                  ? " " : "",
+                  extensions & SE_OPENACC ? "-fopenacc" : "");
 
   /* The following fields could be expected to change between
      otherwise identical compilations.  Consider a distributed build
@@ -19166,12 +19243,22 @@ module_state::read_config (module_state_
      too.  */
   {
     unsigned ext = cfg.u ();
-    unsigned allowed = (flag_openmp ? SE_OPENMP : 0);
+    unsigned allowed = (flag_openmp ? SE_OPENMP | SE_OPENMP_SIMD : 0);
+    if (flag_openmp_simd)
+      allowed |= SE_OPENMP_SIMD;
+    if (flag_openacc)
+      allowed |= SE_OPENACC;
 
     if (unsigned bad = ext & ~allowed)
       {
        if (bad & SE_OPENMP)
          error_at (loc, "module contains OpenMP, use %<-fopenmp%> to enable");
+       else if (bad & SE_OPENMP_SIMD)
+         error_at (loc, "module contains OpenMP, use %<-fopenmp%> or "
+                        "%<-fopenmp-simd%> to enable");
+       if (bad & SE_OPENACC)
+         error_at (loc, "module contains OpenACC, use %<-fopenacc%> to "
+                        "enable");
        cfg.set_overrun ();
        goto done;
       }
--- gcc/testsuite/g++.dg/modules/pr119102_a.H.jj        2025-03-04 
17:58:56.669389212 +0100
+++ gcc/testsuite/g++.dg/modules/pr119102_a.H   2025-03-04 17:58:48.221507257 
+0100
@@ -0,0 +1,9 @@
+// PR c++/119102
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+int foo (int)
+#if defined __x86_64__ || defined __aarch64__
+__attribute__((simd ("notinbranch")))
+#endif
+;
--- gcc/testsuite/g++.dg/modules/pr119102_b.C.jj        2025-03-04 
17:59:31.234906196 +0100
+++ gcc/testsuite/g++.dg/modules/pr119102_b.C   2025-03-04 17:59:26.480972633 
+0100
@@ -0,0 +1,9 @@
+// PR c++/119102
+// { dg-additional-options "-fmodules-ts" }
+
+import "pr119102_a.H";
+
+int
+main ()
+{
+}
--- gcc/testsuite/g++.dg/modules/omp-3_a.C.jj   2025-03-04 18:28:22.694702204 
+0100
+++ gcc/testsuite/g++.dg/modules/omp-3_a.C      2025-03-04 18:29:13.524991414 
+0100
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts -fopenmp-simd" }
+// { dg-require-effective-target pthread }
+
+export module foo;
+// { dg-module-cmi foo { target pthread } }
+
+export inline void frob (unsigned (&ary)[64])
+{
+  int sum = 0;
+
+#pragma omp simd safelen(16) aligned (ary : 16)
+  for (unsigned ix = 0; ix < 64; ix++)
+    ary[ix] *= 2;
+}
--- gcc/testsuite/g++.dg/modules/omp-3_b.C.jj   2025-03-04 18:28:26.447649726 
+0100
+++ gcc/testsuite/g++.dg/modules/omp-3_b.C      2025-03-04 18:29:36.630668318 
+0100
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts -fopenmp-simd" }
+// { dg-require-effective-target pthread }
+
+import foo;
+
+unsigned ary[64];
+
+int main ()
+{
+  frob (ary);
+}
--- gcc/testsuite/g++.dg/modules/omp-3_c.C.jj   2025-03-04 18:28:30.428594057 
+0100
+++ gcc/testsuite/g++.dg/modules/omp-3_c.C      2025-03-04 18:43:53.955666435 
+0100
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts -fopenmp" }
+// { dg-require-effective-target pthread }
+
+import foo;
+
+unsigned ary[64];
+
+int main ()
+{
+  frob (ary);
+}
--- gcc/testsuite/g++.dg/modules/omp-3_d.C.jj   2025-03-04 18:43:59.424589869 
+0100
+++ gcc/testsuite/g++.dg/modules/omp-3_d.C      2025-03-04 18:44:37.401058197 
+0100
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts" }
+// { dg-require-effective-target pthread }
+
+import foo;
+
+// { dg-regexp "In module imported at \[^\n]*omp-3_d.C:4:1:\nfoo: error: 
module contains OpenMP, use '-fopenmp' or '-fopenmp-simd' to enable\n" }
+// { dg-prune-output "failed to read" }
+// { dg-prune-output "fatal error:" }
+// { dg-prune-output "compilation terminated" }
--- gcc/testsuite/g++.dg/modules/oacc-1_a.C.jj  2025-03-04 18:45:22.097432445 
+0100
+++ gcc/testsuite/g++.dg/modules/oacc-1_a.C     2025-03-04 18:50:18.536284123 
+0100
@@ -0,0 +1,15 @@
+// { dg-additional-options "-fmodules-ts -fopenacc" }
+// { dg-require-effective-target pthread }
+
+export module foo;
+// { dg-module-cmi foo { target pthread } }
+
+export inline void frob (unsigned (&ary)[64])
+{
+  int sum, i;
+#pragma acc parallel
+#pragma acc loop gang worker vector reduction (+:sum)
+  for (i = 0; i < 64; i++)
+    sum += ary[i];
+  ary[0] += sum;
+}
--- gcc/testsuite/g++.dg/modules/oacc-1_b.C.jj  2025-03-04 18:48:24.387880885 
+0100
+++ gcc/testsuite/g++.dg/modules/oacc-1_b.C     2025-03-04 18:48:38.816679049 
+0100
@@ -0,0 +1,11 @@
+// { dg-additional-options "-fmodules-ts -fopenacc" }
+// { dg-require-effective-target pthread }
+
+import foo;
+
+unsigned ary[64];
+
+int main ()
+{
+  frob (ary);
+}
--- gcc/testsuite/g++.dg/modules/oacc-1_c.C.jj  2025-03-04 18:48:44.342601750 
+0100
+++ gcc/testsuite/g++.dg/modules/oacc-1_c.C     2025-03-04 18:49:01.724358608 
+0100
@@ -0,0 +1,9 @@
+// { dg-additional-options "-fmodules-ts" }
+// { dg-require-effective-target pthread }
+
+import foo;
+
+// { dg-regexp "In module imported at \[^\n]*oacc-1_c.C:4:1:\nfoo: error: 
module contains OpenACC, use '-fopenacc' to enable\n" }
+// { dg-prune-output "failed to read" }
+// { dg-prune-output "fatal error:" }
+// { dg-prune-output "compilation terminated" }

        Jakub

Reply via email to