openmp, c++: Fix up OpenMP/OpenACC handling in C++ modules [PR119102]

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  <jakub@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.
This commit is contained in:
Jakub Jelinek 2025-03-05 07:47:52 +01:00 committed by Jakub Jelinek
parent b85b405ed3
commit ddeb70548c
10 changed files with 197 additions and 12 deletions

View file

@ -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_streamed)
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, cpp_reader *reader, const char *dialect
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_config &config)
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;
}

View file

@ -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;
}

View file

@ -0,0 +1,11 @@
// { dg-additional-options "-fmodules-ts -fopenacc" }
// { dg-require-effective-target pthread }
import foo;
unsigned ary[64];
int main ()
{
frob (ary);
}

View file

@ -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" }

View file

@ -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;
}

View file

@ -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);
}

View file

@ -0,0 +1,11 @@
// { dg-additional-options "-fmodules-ts -fopenmp" }
// { dg-require-effective-target pthread }
import foo;
unsigned ary[64];
int main ()
{
frob (ary);
}

View file

@ -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" }

View file

@ -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
;

View file

@ -0,0 +1,9 @@
// PR c++/119102
// { dg-additional-options "-fmodules-ts" }
import "pr119102_a.H";
int
main ()
{
}