-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[Flang][OpenMP] Add -fopenmp-default-none command line flag #120287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-flang-semantics @llvm/pr-subscribers-clang-driver Author: Michael Klemm (mjklemm) ChangesThis PR adds the Full diff: https://github.com/llvm/llvm-project/pull/120287.diff 7 Files Affected:
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index bed2a56b003512..acbe93fe72a24e 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3596,6 +3596,9 @@ def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>,
Flags<[NoArgumentUnused]>,
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
HelpText<"Parse OpenMP pragmas and generate parallel code.">;
+def fopenmp_default_none : Flag<["-"], "fopenmp-default-none">, Group<f_Group>,
+ Visibility<[FlangOption, FC1Option]>,
+ HelpText<"Add DEFAULT(NONE) to all OpenMP directives that allow data-sharing clauses.">;
def fno_openmp : Flag<["-"], "fno-openmp">, Group<f_Group>,
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
Flags<[NoArgumentUnused]>;
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index c98fdbd157bac8..521ae90e0bd164 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -855,6 +855,9 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
// is experimental.
D.Diag(diag::warn_openmp_experimental);
+ if (Args.hasArg((options::OPT_fopenmp_default_none)))
+ CmdArgs.push_back("-fopenmp-default-none");
+
// FIXME: Clang supports a whole bunch more flags here.
break;
default:
diff --git a/flang/include/flang/Common/Fortran-features.h b/flang/include/flang/Common/Fortran-features.h
index b04f6117ae9656..218e05e53aee01 100644
--- a/flang/include/flang/Common/Fortran-features.h
+++ b/flang/include/flang/Common/Fortran-features.h
@@ -54,7 +54,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
PolymorphicActualAllocatableOrPointerToMonomorphicDummy, RelaxedPureDummy,
UndefinableAsynchronousOrVolatileActual, AutomaticInMainProgram, PrintCptr,
SavedLocalInSpecExpr, PrintNamelist, AssumedRankPassedToNonAssumedRank,
- IgnoreIrrelevantAttributes)
+ IgnoreIrrelevantAttributes, OpenMPDefaultNone)
// Portability and suspicious usage warnings
ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
diff --git a/flang/lib/Common/Fortran-features.cpp b/flang/lib/Common/Fortran-features.cpp
index c86432874b8d83..c6f818478b065c 100644
--- a/flang/lib/Common/Fortran-features.cpp
+++ b/flang/lib/Common/Fortran-features.cpp
@@ -17,6 +17,7 @@ LanguageFeatureControl::LanguageFeatureControl() {
disable_.set(LanguageFeature::OldDebugLines);
disable_.set(LanguageFeature::OpenACC);
disable_.set(LanguageFeature::OpenMP);
+ disable_.set(LanguageFeature::OpenMPDefaultNone);
disable_.set(LanguageFeature::CUDA); // !@cuf
disable_.set(LanguageFeature::CudaManaged);
disable_.set(LanguageFeature::CudaUnified);
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 648b88e84051c2..648ad224a26f66 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -1023,6 +1023,10 @@ static bool parseOpenMPArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
res.getLangOpts().OpenMPVersion, diags)) {
res.getLangOpts().OpenMPVersion = Version;
}
+ if (args.hasArg(clang::driver::options::OPT_fopenmp_default_none)) {
+ res.getFrontendOpts().features.Enable(
+ Fortran::common::LanguageFeature::OpenMPDefaultNone);
+ }
if (args.hasArg(clang::driver::options::OPT_fopenmp_force_usm)) {
res.getLangOpts().OpenMPForceUSM = 1;
}
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 39478b58a9070d..9cefc36d987b15 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -2268,6 +2268,11 @@ void OmpAttributeVisitor::CreateImplicitSymbols(
void OmpAttributeVisitor::Post(const parser::Name &name) {
auto *symbol{name.symbol};
+ // if -fopenmp-default-none was given on the command line, act as if
+ // DEFAULT(NONE) was present at the directive.
+ bool HaveOpenMPDefaultNone = context_.languageFeatures().IsEnabled(
+ common::LanguageFeature::OpenMPDefaultNone);
+
if (symbol && !dirContext_.empty() && GetContext().withinConstruct) {
if (IsPrivatizable(symbol) && !IsObjectWithDSA(*symbol)) {
// TODO: create a separate function to go through the rules for
@@ -2276,7 +2281,8 @@ void OmpAttributeVisitor::Post(const parser::Name &name) {
if (Symbol * found{currScope().FindSymbol(name.source)}) {
if (symbol != found) {
name.symbol = found; // adjust the symbol within region
- } else if (GetContext().defaultDSA == Symbol::Flag::OmpNone &&
+ } else if ((HaveOpenMPDefaultNone ||
+ GetContext().defaultDSA == Symbol::Flag::OmpNone) &&
!symbol->test(Symbol::Flag::OmpThreadprivate) &&
// Exclude indices of sequential loops that are privatised in
// the scope of the parallel region, and not in this scope.
diff --git a/flang/test/Semantics/OpenMP/resolve07.f90 b/flang/test/Semantics/OpenMP/resolve07.f90
new file mode 100644
index 00000000000000..4a898903fae431
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/resolve07.f90
@@ -0,0 +1,34 @@
+! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-default-none
+
+
+! Test that -fopenmp-default-none shows the same errors as DEFAULT(NONE)
+subroutine default_none()
+ integer a(3)
+ integer, parameter :: D=10
+ A = 1
+ B = 2
+ !$omp parallel private(c)
+ !ERROR: The DEFAULT(NONE) clause requires that 'a' must be listed in a data-sharing attribute clause
+ A(1:2) = 3
+ !ERROR: The DEFAULT(NONE) clause requires that 'b' must be listed in a data-sharing attribute clause
+ B = 4
+ C = 5 + D
+ !$omp end parallel
+end subroutine default_none
+
+! Test that indices of sequential loops are privatised and hence do not error
+! for -fopenmp-default-none.
+subroutine default_none_seq_loop
+ integer :: i
+
+ !$omp parallel do
+ do i = 1, 10
+ do j = 1, 20
+ enddo
+ enddo
+end subroutine
+
+program mm
+ call default_none()
+ call default_none_seq_loop()
+end
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the whole, this looks reasonable.
@@ -3596,6 +3596,9 @@ def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, | |||
Flags<[NoArgumentUnused]>, | |||
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, | |||
HelpText<"Parse OpenMP pragmas and generate parallel code.">; | |||
def fopenmp_default_none : Flag<["-"], "fopenmp-default-none">, Group<f_Group>, | |||
Visibility<[FlangOption, FC1Option]>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mind moving this to later in this file? Maybe so it is before def fopenmp_use_tls
. There is a loose ordering of options here with the "top-level" fopenmp
options first and some more specific ones later. This file is already huge and somewhat disorganized, so it would be good to keep what organization there is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. I have seen that there seems to be a bit of chaos (or: I did not the see the order :-)) in the order of the CLI options. Maybe it warrants an NFC PR that puts the options in some better order.
@@ -2276,7 +2281,8 @@ void OmpAttributeVisitor::Post(const parser::Name &name) { | |||
if (Symbol * found{currScope().FindSymbol(name.source)}) { | |||
if (symbol != found) { | |||
name.symbol = found; // adjust the symbol within region | |||
} else if (GetContext().defaultDSA == Symbol::Flag::OmpNone && | |||
} else if ((HaveOpenMPDefaultNone || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would HaveOpenMPDefaultNone
be set for those constructs where data-sharing is not allowed as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I understand the code, this is the place where all the handling of the implicit and explicit data-sharing checks are happening. So, this should happen for all directives that allow for having data-sharing attribute clauses.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this code used to be entered only if defaultDSA
is set to None
. And this setting is explicitly done in resolve-directives while going through the OmpDefaultClause
in
void OmpAttributeVisitor::Post(const parser::OmpDefaultClause &x) { |
HaveOpenMPDefaultNone
flag is set just based on the command line flag setting. We probably have to enable this flag only when datasharing clauses are supported.
To give an example where this will fire incorrectly.
subroutine sb1(arr, n)
integer :: n
integer :: arr(n)
!$omp workshare
arr = n
!$omp end workshare
end subroutine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is exactly what this option is supposed to do. If I misread your comment, please bear with me and explain. For
subroutine sb1(arr, n)
integer :: n
integer :: arr(n)
!$omp workshare
arr = n
!$omp end workshare
end subroutine
The -fopenmp-default-none
acts as if the developer has written this:
subroutine sb1(arr, n)
integer :: n
integer :: arr(n)
!$omp workshare default(none)
arr = n
!$omp end workshare
end subroutine
So, for both the error would be the same:
error: Semantic errors in /net/home/micha/projects/llvm/tmp/datasharing.f90
/net/home/micha/projects/llvm/tmp/datasharing.f90:16:5: error: The DEFAULT(NONE) clause requires that 'arr' must be listed in a data-sharing attribute clause
arr = n
^^^
/net/home/micha/projects/llvm/tmp/datasharing.f90:16:11: error: The DEFAULT(NONE) clause requires that 'n' must be listed in a data-sharing attribute clause
arr = n
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean workshare
does not support a data-sharing clause. I thought the intent of the patch was to only apply this flag to constructs where data-sharing clauses are allowed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is probably a bug here since resolve-directives happens before check-omp-structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh boy... Yes, I do not like these 20th century features. :-) Thanks for catching this!
def fopenmp_default_none : Flag<["-"], "fopenmp-default-none">, Group<f_Group>, | ||
Visibility<[FlangOption, FC1Option]>, | ||
HelpText<"Add DEFAULT(NONE) to all OpenMP directives that allow data-sharing clauses.">; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be a useful flag. Is there a precedent in other compiler?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not aware that GFortran or IFX would have that. And I always sort of was annoyed by that. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be a lot of work to add this flag for clang as well? It seems like the behaviour would be equally useful there and I would prefer us to keep flags available for both compilers where it makes sense.
In terms of implementation it looks like there's already a clang-tidy pass for it so you could check what they are doing for inspiration?
If it's a lot of work we can add a TODO somewhere (I guess in a comment in the tablegen file) to remind us that we could conceptually enable this flag for clang too so as not to hold up this patch.
I will ask one of the Clang adepts in the team to provide a PR or extend this one. I think it should be fairly easy to do that there as well.
Let me check this out and I'll either add the TODO or extent this PR (or have a second one for Clang) |
Is NONE special enough to have a dedicated option, or could we have |
I have thought about this, but that's going to be dangerous. I intended this option to be solely for detecting potential races through unintended sharing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LG, except for the issue raised by @kiranchandramohan, to skip constructs that don't support data-sharing clauses.
@@ -855,6 +855,9 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, | |||
// is experimental. | |||
D.Diag(diag::warn_openmp_experimental); | |||
|
|||
if (Args.hasArg((options::OPT_fopenmp_default_none))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (Args.hasArg((options::OPT_fopenmp_default_none))) | |
if (Args.hasArg(options::OPT_fopenmp_default_none)) |
nit: extra parentheses
call default_none() | ||
call default_none_seq_loop() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to add a test for a construct that doesn't support data-sharing clauses, such as workshare
, to make sure no error is reported.
This PR adds the
-fopenmp-default-none
command line flag to the Flang compiler. Similarly, to-fimplicit-none
it provides error checking for OpenMP directives by behaving as ifDEFAULT(NONE)
was specified at all directives that support data-sharing attribute clauses.