Skip to content

[flang][OpenMP][Semantics] Don't allow reduction of derived type components #125480

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

Merged
merged 4 commits into from
Feb 6, 2025

Conversation

tblah
Copy link
Contributor

@tblah tblah commented Feb 3, 2025

Before this patch, reduction of derived type components crashed the compiler when trying to create the omp.declare_reduction.

In OpenMP 3.1 the standard says "a list item that appears in a reduction clause must be a named variable of intrinsic type" (page 106). As I understand it, a derived type component is not a variable.

OpenMP 4.0 added declare reduction, partly so that users could define their own reductions on derived types. The above wording was removed from the standard but derived type components were never explicitly allowed.

OpenMP 5.0 added "A variable that is part of another variable, with the exception of array elements, cannot appear in17 a reduction clause".

All standard versions also require the reduction argument to be "definable", which roughly means that it is a variable. A
derived type component is more like an expression.

Fixes #125445

…onents

Before this patch, reduction of derived type components crashed the
compiler when trying to create the omp.declare_reduction.

In OpenMP 3.1 the standard says "a list item that appears in a reduction
clause must be a named variable of intrinsic type" (page 106). As I
understand it, a derived type component is not a variable.

OpenMP 4.0 added declare reduction, partly so that users could define
their own reductions on derived types. The above wording was removed
from the standard but derived type components were never explicitly
allowed.

OpenMP 5.0 added "A variable that is part of another variable, with
the exception of array elements, cannot appear in17 a reduction
clause".

As we do not currently support derived type components, and these are
only implicitly permitted in OpenMP 4.x, I think it is better to
disallow them in semantics rather than only printing a TODO for openmp
4.x. This is also what gfortran and classic-flang do.

Fixes llvm#125445
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:openmp flang:semantics labels Feb 3, 2025
@tblah tblah changed the title [flang][OpenMP][Semantics] Don't allow reduction of derived type comp… [flang][OpenMP][Semantics] Don't allow reduction of derived type components Feb 3, 2025
@llvmbot
Copy link
Member

llvmbot commented Feb 3, 2025

@llvm/pr-subscribers-flang-fir-hlfir
@llvm/pr-subscribers-flang-openmp

@llvm/pr-subscribers-flang-semantics

Author: Tom Eccles (tblah)

Changes

Before this patch, reduction of derived type components crashed the compiler when trying to create the omp.declare_reduction.

In OpenMP 3.1 the standard says "a list item that appears in a reduction clause must be a named variable of intrinsic type" (page 106). As I understand it, a derived type component is not a variable.

OpenMP 4.0 added declare reduction, partly so that users could define their own reductions on derived types. The above wording was removed from the standard but derived type components were never explicitly allowed.

OpenMP 5.0 added "A variable that is part of another variable, with the exception of array elements, cannot appear in17 a reduction clause".

As we do not currently support derived type components, and these are only implicitly permitted in OpenMP 4.x, I think it is better to disallow them in semantics rather than only printing a TODO for openmp 4.x. This is also what gfortran and classic-flang do.

Fixes #125445


Full diff: https://github.com/llvm/llvm-project/pull/125480.diff

2 Files Affected:

  • (modified) flang/lib/Semantics/check-omp-structure.cpp (+6-2)
  • (added) flang/test/Semantics/OpenMP/reduction-derived-component.f90 (+10)
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 035064ecf3a46e..ad36ce2bde0db9 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -3224,9 +3224,13 @@ void OmpStructureChecker::CheckReductionObjects(
     }
   }
 
+  // Disallowed in standards before 4.0 and in 5.0 and later. Not explicitly
+  // allowed in 4.0. Keep this as an error until/unless structure component
+  // reduction is implemented.
+  // Object cannot be a part of another object (except array elements)
+  CheckStructureComponent(objects, clauseId);
+
   if (version >= 50) {
-    // Object cannot be a part of another object (except array elements)
-    CheckStructureComponent(objects, clauseId);
     // If object is an array section or element, the base expression must be
     // a language identifier.
     for (const parser::OmpObject &object : objects.v) {
diff --git a/flang/test/Semantics/OpenMP/reduction-derived-component.f90 b/flang/test/Semantics/OpenMP/reduction-derived-component.f90
new file mode 100644
index 00000000000000..87e5f1acda159b
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/reduction-derived-component.f90
@@ -0,0 +1,10 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+subroutine intrinsic_reduction
+  type local
+     integer alpha
+  end type local
+  type(local) a
+!ERROR: A variable that is part of another variable cannot appear on the REDUCTION clause
+!$omp parallel reduction(+:a%alpha)
+!$omp end parallel
+end subroutine intrinsic_reduction

@tblah tblah requested a review from luporl February 3, 2025 11:22
@kiranchandramohan
Copy link
Contributor

This is OK up to OpenMP 5.1.
A variable that is part of another variable, with the exception of array elements cannotappear in a reduction clause.

OpenMP 5.2 onwards has the following:
A list item that appears in a reduction clause must be definable.

Is it better to emit the semantics error for 5.1 and before and the lowering error for 5.2 and later standards?

@tblah
Copy link
Contributor Author

tblah commented Feb 3, 2025

This is OK up to OpenMP 5.1. A variable that is part of another variable, with the exception of array elements cannotappear in a reduction clause.

OpenMP 5.2 onwards has the following: A list item that appears in a reduction clause must be definable.

Is it better to emit the semantics error for 5.1 and before and the lowering error for 5.2 and later standards?

Well spotted. I will do that.

@tblah
Copy link
Contributor Author

tblah commented Feb 3, 2025

@kiranchandramohan I have added the TODO in lowering, but from the lowering error I wonder if we should really consider a derived type component as definable.

That wording is in all versions of the standard (IIRC). I previously assumed that it wasn't relevant here because CheckReductionObjects() already unconditionally calls CheckDefinableObjects().

The error in lowering is because that object cannot be looked up in the symbol table because a component of a derived type isn't a symbol with a definition. I think instance%component is an expression and so is not definable.

The wording in the Fortran standard is in section 3.47 of f2023. It says a definable object is capable of definition and permitted to become defined. Both of those conditions seem to require it to be a data object (3.42):

constant, variable, or subobject of a constant

I think a derived type member is not constant and not a variable (if it were a variable we would be able to look it up in the symbol table).

@kiranchandramohan
Copy link
Contributor

@kiranchandramohan I have added the TODO in lowering, but from the lowering error I wonder if we should really consider a derived type component as definable.

That wording is in all versions of the standard (IIRC). I previously assumed that it wasn't relevant here because CheckReductionObjects() already unconditionally calls CheckDefinableObjects().

The error in lowering is because that object cannot be looked up in the symbol table because a component of a derived type isn't a symbol with a definition. I think instance%component is an expression and so is not definable.

How does it work for array elements? Isn't there a similar issue?

The wording in the Fortran standard is in section 3.47 of f2023. It says a definable object is capable of definition and permitted to become defined. Both of those conditions seem to require it to be a data object (3.42):

constant, variable, or subobject of a constant

I think a derived type member is not constant and not a variable (if it were a variable we would be able to look it up in the symbol table).

Does this exclude array elements also?

@tblah
Copy link
Contributor Author

tblah commented Feb 4, 2025

How does it work for array elements? Isn't there a similar issue?

It seems we just do reduction on the whole array, ignoring the indexing.

Does this exclude array elements also?

I imagine it should do. gfortran and classic-flang don't allow it.

So does this sound okay to you:

  1. I change this patch to deny derived type components for all standard versions
  2. I do a followup patch denying array indexing

@kiranchandramohan
Copy link
Contributor

How does it work for array elements? Isn't there a similar issue?

It seems we just do reduction on the whole array, ignoring the indexing.

The following program seemed to work correctly with ifx.
I see that flang currently generates a combiner that does the reduction on the whole array but the final answer it computes is also correct.

program mn
  integer :: i
  integer :: arr(10)
  arr = 0
  !$omp parallel do reduction(+:arr(3))
  do i=1,10
    arr(3) = arr(3) + i
  end do
  !$omp end parallel do
  print *, arr
end program

Does this exclude array elements also?

I imagine it should do. gfortran and classic-flang don't allow it.

So does this sound okay to you:

  1. I change this patch to deny derived type components for all standard versions
  2. I do a followup patch denying array indexing

I am not 100% sure about this since previous versions explicitly allowed array elements. It might be worth asking a question to the OpenMP committee.

@kkwli
Copy link
Collaborator

kkwli commented Feb 4, 2025

I am not 100% sure about this since previous versions explicitly allowed array elements. It might be worth asking a question to the OpenMP committee.

OpenMP 6.0 clarifies that array elements are allowed on the clause.

"The list items that appear in a reduction clause or an induction clause may include array sections and array elements." (247:3-4)

@kiranchandramohan
Copy link
Contributor

I am not 100% sure about this since previous versions explicitly allowed array elements. It might be worth asking a question to the OpenMP committee.

OpenMP 6.0 clarifies that array elements are allowed on the clause.

"The list items that appear in a reduction clause or an induction clause may include array sections and array elements." (247:3-4)

Thanks @kkwli. Would you know why derived type members are not allowed?

@kkwli
Copy link
Collaborator

kkwli commented Feb 4, 2025

I am not 100% sure about this since previous versions explicitly allowed array elements. It might be worth asking a question to the OpenMP committee.

OpenMP 6.0 clarifies that array elements are allowed on the clause.
"The list items that appear in a reduction clause or an induction clause may include array sections and array elements." (247:3-4)

Thanks @kkwli. Would you know why derived type members are not allowed?

For the array elements, one can treat it as an array section with stride 1.

For derived type components, the spec does not have the semantic of subobject privatization yet. For example, if some components of a derived type is privatized, are other components in the same derived type shared? What if the whole derived type is accessed? We haven't figured out the details yet. That is one of the reasons why subobjects are disallowed on most of the data-sharing attribute clauses.

@tblah
Copy link
Contributor Author

tblah commented Feb 4, 2025

I have updated this to deny reduction of derived type components for all standard versions and updated the comment and description explaining the reasoning.

I have made no change to how array elements are handled. They will continue to be allowed.

@kiranchandramohan
Copy link
Contributor

For derived type components, the spec does not have the semantic of subobject privatization yet. For example, if some components of a derived type is privatized, are other components in the same derived type shared? What if the whole derived type is accessed? We haven't figured out the details yet. That is one of the reasons why subobjects are disallowed on most of the data-sharing attribute clauses.

Thanks @kkwli. Aren't these the same questions for arrays as well, Like, are the other elements of the same array shared, what if the whole array accessed?

Copy link
Contributor

@kiranchandramohan kiranchandramohan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG. Thanks.

@tblah tblah merged commit 39be2d0 into llvm:main Feb 6, 2025
8 checks passed
searlmc1 pushed a commit to ROCm/llvm-project that referenced this pull request Feb 7, 2025
…onents (llvm#125480)

Before this patch, reduction of derived type components crashed the
compiler when trying to create the omp.declare_reduction.

In OpenMP 3.1 the standard says "a list item that appears in a reduction
clause must be a named variable of intrinsic type" (page 106). As I
understand it, a derived type component is not a variable.

OpenMP 4.0 added declare reduction, partly so that users could define
their own reductions on derived types. The above wording was removed
from the standard but derived type components were never explicitly
allowed.

OpenMP 5.0 added "A variable that is part of another variable, with the
exception of array elements, cannot appear in17 a reduction clause".

All standard versions also require the reduction argument to be
"definable", which roughly means that it is a variable. A
derived type component is more like an expression.

Fixes llvm#125445
Icohedron pushed a commit to Icohedron/llvm-project that referenced this pull request Feb 11, 2025
…onents (llvm#125480)

Before this patch, reduction of derived type components crashed the
compiler when trying to create the omp.declare_reduction.

In OpenMP 3.1 the standard says "a list item that appears in a reduction
clause must be a named variable of intrinsic type" (page 106). As I
understand it, a derived type component is not a variable.

OpenMP 4.0 added declare reduction, partly so that users could define
their own reductions on derived types. The above wording was removed
from the standard but derived type components were never explicitly
allowed.

OpenMP 5.0 added "A variable that is part of another variable, with the
exception of array elements, cannot appear in17 a reduction clause".

All standard versions also require the reduction argument to be
"definable", which roughly means that it is a variable. A
derived type component is more like an expression.

Fixes llvm#125445
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:fir-hlfir flang:openmp flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Flang][OpenMP] Compilation abnormally terminates when list item described in reduction clause is a variable of derived type
4 participants