-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[flang][OpenMP]Add parsing and semantics support for ATOMIC COMPARE #117032
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
Conversation
This adds a minimalistic implementation of parsing and semantics for the ATOMIC COMPARE feature from OpenMP 5.1. There is no lowering, just a TODO for that part. Some of the Semantics is also just a comment explaining that more is needed.
@llvm/pr-subscribers-flang-parser @llvm/pr-subscribers-flang-semantics Author: Mats Petersson (Leporacanthicus) ChangesThis adds a minimalistic implementation of parsing and semantics for the ATOMIC COMPARE feature from OpenMP 5.1. There is no lowering, just a TODO for that part. Some of the Semantics is also just a comment explaining that more is needed. Full diff: https://github.com/llvm/llvm-project/pull/117032.diff 11 Files Affected:
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 63fddc424182b2..a31dd82e266b7e 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -484,6 +484,7 @@ class ParseTreeDumper {
NODE(parser, OmpAtomicCapture)
NODE(OmpAtomicCapture, Stmt1)
NODE(OmpAtomicCapture, Stmt2)
+ NODE(parser, OmpAtomicCompare)
NODE(parser, OmpAtomicRead)
NODE(parser, OmpAtomicUpdate)
NODE(parser, OmpAtomicWrite)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 22b7f9acd1af52..a8a23d1a16938b 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4126,6 +4126,15 @@ struct OmpAtomicCapture {
t;
};
+// ATOMCI COMPARE (OpenMP 5.1, Spec: 15.8.4)
+struct OmpAtomicCompare {
+ TUPLE_CLASS_BOILERPLATE(OmpAtomicCompare);
+ CharBlock source;
+ std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
+ Statement<AssignmentStmt>, std::optional<OmpEndAtomic>>
+ t;
+};
+
// ATOMIC
struct OmpAtomic {
TUPLE_CLASS_BOILERPLATE(OmpAtomic);
@@ -4138,11 +4147,11 @@ struct OmpAtomic {
// 2.17.7 atomic ->
// ATOMIC [atomic-clause-list] atomic-construct [atomic-clause-list] |
// ATOMIC [atomic-clause-list]
-// atomic-construct -> READ | WRITE | UPDATE | CAPTURE
+// atomic-construct -> READ | WRITE | UPDATE | CAPTURE | COMPARE
struct OpenMPAtomicConstruct {
UNION_CLASS_BOILERPLATE(OpenMPAtomicConstruct);
std::variant<OmpAtomicRead, OmpAtomicWrite, OmpAtomicCapture, OmpAtomicUpdate,
- OmpAtomic>
+ OmpAtomicCompare, OmpAtomic>
u;
};
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index a2779213a1a15a..80a17e97ee67f3 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2896,6 +2896,10 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
parser::OmpAtomicClauseList>(
converter, atomicCapture, loc);
},
+ [&](const parser::OmpAtomicCompare &atomicCompare) {
+ mlir::Location loc = converter.genLocation(atomicCompare.source);
+ TODO(loc, "OpenMP atomic compare");
+ },
},
atomicConstruct.u);
}
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 630acf9a6b256c..6d19d13f181e11 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -912,6 +912,12 @@ TYPE_PARSER("ATOMIC" >>
Parser<OmpAtomicClauseList>{} / endOmpLine, statement(assignmentStmt),
statement(assignmentStmt), Parser<OmpEndAtomic>{} / endOmpLine)))
+TYPE_PARSER("ATOMIC" >>
+ sourced(construct<OmpAtomicCompare>(
+ Parser<OmpAtomicClauseList>{} / maybe(","_tok), verbatim("COMPARE"_tok),
+ Parser<OmpAtomicClauseList>{} / endOmpLine, statement(assignmentStmt),
+ maybe(Parser<OmpEndAtomic>{} / endOmpLine))))
+
// OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] UPDATE [MEMORY-ORDER-CLAUSE-LIST]
TYPE_PARSER("ATOMIC" >>
sourced(construct<OmpAtomicUpdate>(
@@ -934,6 +940,7 @@ TYPE_PARSER("ATOMIC" >>
// Atomic Construct
TYPE_PARSER(construct<OpenMPAtomicConstruct>(Parser<OmpAtomicRead>{}) ||
construct<OpenMPAtomicConstruct>(Parser<OmpAtomicCapture>{}) ||
+ construct<OpenMPAtomicConstruct>(Parser<OmpAtomicCompare>{}) ||
construct<OpenMPAtomicConstruct>(Parser<OmpAtomicWrite>{}) ||
construct<OpenMPAtomicConstruct>(Parser<OmpAtomicUpdate>{}) ||
construct<OpenMPAtomicConstruct>(Parser<OmpAtomic>{}))
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 4d6aaceb69c185..c1ffb44385f04c 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2520,6 +2520,16 @@ class UnparseVisitor {
Word("!$OMP END ATOMIC\n");
EndOpenMP();
}
+ void Unparse(const OmpAtomicCompare &x) {
+ BeginOpenMP();
+ Word("!$OMP ATOMIC");
+ Walk(std::get<0>(x.t));
+ Word(" COMPARE");
+ Walk(std::get<2>(x.t));
+ Put("\n");
+ EndOpenMP();
+ Walk(std::get<Statement<AssignmentStmt>>(x.t));
+ }
void Unparse(const OmpAtomicRead &x) {
BeginOpenMP();
Word("!$OMP ATOMIC");
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 9cac652216fcf2..90e8e99043ff5d 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -2408,6 +2408,24 @@ void OmpStructureChecker::CheckAtomicUpdateStmt(
ErrIfAllocatableVariable(var);
}
+void OmpStructureChecker::CheckAtomicCompareConstruct(
+ const parser::OmpAtomicCompare &atomicCompareConstruct) {
+
+ CheckAtomicWriteStmt(std::get<parser::Statement<parser::AssignmentStmt>>(
+ atomicCompareConstruct.t)
+ .statement);
+
+ unsigned version{context_.langOptions().OpenMPVersion};
+ if (version < 51) {
+ context_.Say(atomicCompareConstruct.source,
+ "%s construct not allowed in %s, %s"_err_en_US,
+ atomicCompareConstruct.source, ThisVersion(version), TryVersion(51));
+ }
+
+ // TODO: More work needed here. Some of the Update restrictions need to
+ // be added, but Update isn't the same either.
+}
+
// TODO: Allow cond-update-stmt once compare clause is supported.
void OmpStructureChecker::CheckAtomicCaptureConstruct(
const parser::OmpAtomicCapture &atomicCaptureConstruct) {
@@ -2553,6 +2571,16 @@ void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
&std::get<0>(atomicCapture.t), &std::get<2>(atomicCapture.t));
CheckAtomicCaptureConstruct(atomicCapture);
},
+ [&](const parser::OmpAtomicCompare &atomicCompare) {
+ const auto &dir{std::get<parser::Verbatim>(atomicCompare.t)};
+ PushContextAndClauseSets(
+ dir.source, llvm::omp::Directive::OMPD_atomic);
+ CheckAtomicMemoryOrderClause(
+ &std::get<0>(atomicCompare.t), &std::get<2>(atomicCompare.t));
+ CheckHintClause<const parser::OmpAtomicClauseList>(
+ &std::get<0>(atomicCompare.t), &std::get<2>(atomicCompare.t));
+ CheckAtomicCompareConstruct(atomicCompare);
+ },
},
x.u);
}
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index df21ebac0f6d76..6b4fb51c2d99cc 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -213,6 +213,7 @@ class OmpStructureChecker
void CheckAtomicCaptureStmt(const parser::AssignmentStmt &);
void CheckAtomicWriteStmt(const parser::AssignmentStmt &);
void CheckAtomicCaptureConstruct(const parser::OmpAtomicCapture &);
+ void CheckAtomicCompareConstruct(const parser::OmpAtomicCompare &);
void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &);
void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
void CheckSIMDNest(const parser::OpenMPConstruct &x);
diff --git a/flang/test/Parser/OpenMP/atomic-compare.f90 b/flang/test/Parser/OpenMP/atomic-compare.f90
new file mode 100644
index 00000000000000..5cd02698ff4823
--- /dev/null
+++ b/flang/test/Parser/OpenMP/atomic-compare.f90
@@ -0,0 +1,16 @@
+! RUN: not %flang_fc1 -fopenmp-version=51 -fopenmp %s 2>&1 | FileCheck %s
+! OpenMP version for documentation purposes only - it isn't used until Sema.
+! This is testing for Parser errors that bail out before Sema.
+program main
+ implicit none
+ integer :: i, j = 10
+ logical :: r
+
+ !CHECK: error: expected OpenMP construct
+ !$omp atomic compare write
+ r = i .eq. j + 1
+
+ !CHECK: error: expected end of line
+ !$omp atomic compare num_threads(4)
+ r = i .eq. j
+end program main
diff --git a/flang/test/Parser/OpenMP/atomic-unparse.f90 b/flang/test/Parser/OpenMP/atomic-unparse.f90
index f9d8ec5d5c6813..a7b4d673bc3c6d 100644
--- a/flang/test/Parser/OpenMP/atomic-unparse.f90
+++ b/flang/test/Parser/OpenMP/atomic-unparse.f90
@@ -3,6 +3,7 @@
program main
implicit none
integer :: i, j = 10
+ logical :: k
!READ
!$omp atomic read
i = j
@@ -121,6 +122,30 @@ program main
i = j
!$omp end atomic
+!COMPARE
+!$omp atomic compare
+ r = i .eq. j
+!$omp atomic seq_cst compare
+ r = i .eq. j
+!$omp atomic compare seq_cst
+ r = i .eq. j
+!$omp atomic release compare
+ r = i .eq. j
+!$omp atomic compare release
+ r = i .eq. j
+!$omp atomic acq_rel compare
+ r = i .eq. j
+!$omp atomic compare acq_rel
+ r = i .eq. j
+!$omp atomic acquire compare
+ r = i .eq. j
+!$omp atomic compare acquire
+ r = i .eq. j
+!$omp atomic relaxed compare
+ r = i .eq. j
+!$omp atomic compare relaxed
+ r = i .eq. j
+
!ATOMIC
!$omp atomic
i = j
@@ -205,6 +230,20 @@ end program main
!CHECK: !$OMP ATOMIC CAPTURE RELAXED
!CHECK: !$OMP END ATOMIC
+!COMPARE
+
+!CHECK: !$OMP ATOMIC COMPARE
+!CHECK: !$OMP ATOMIC SEQ_CST COMPARE
+!CHECK: !$OMP ATOMIC COMPARE SEQ_CST
+!CHECK: !$OMP ATOMIC RELEASE COMPARE
+!CHECK: !$OMP ATOMIC COMPARE RELEASE
+!CHECK: !$OMP ATOMIC ACQ_REL COMPARE
+!CHECK: !$OMP ATOMIC COMPARE ACQ_REL
+!CHECK: !$OMP ATOMIC ACQUIRE COMPARE
+!CHECK: !$OMP ATOMIC COMPARE ACQUIRE
+!CHECK: !$OMP ATOMIC RELAXED COMPARE
+!CHECK: !$OMP ATOMIC COMPARE RELAXED
+
!ATOMIC
!CHECK: !$OMP ATOMIC
!CHECK: !$OMP ATOMIC SEQ_CST
diff --git a/flang/test/Semantics/OpenMP/atomic-compare.f90 b/flang/test/Semantics/OpenMP/atomic-compare.f90
new file mode 100644
index 00000000000000..624624a8ecc4a3
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/atomic-compare.f90
@@ -0,0 +1,76 @@
+! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=51
+ use omp_lib
+ implicit none
+ ! Check atomic compare. This combines elements from multiple other "atomic*.f90", as
+ ! to avoid having several files with just a few lines in them. atomic compare needs
+ ! higher openmp version than the others, so need a separate file.
+
+
+ real a, b
+ logical r
+ a = 1.0
+ b = 2.0
+ !$omp parallel num_threads(4)
+ ! First a few things that should compile without error.
+ !$omp atomic seq_cst, compare
+ r = b .ne. a
+
+ !$omp atomic seq_cst compare
+ r = a .ge. b
+ !$omp end atomic
+
+ !$omp atomic compare acquire hint(OMP_LOCK_HINT_CONTENDED)
+ r = a .lt. b
+
+ !$omp atomic release hint(OMP_LOCK_HINT_UNCONTENDED) compare
+ r = a .gt. b
+
+ !$omp atomic compare seq_cst
+ r = b .ne. a
+
+ !$omp atomic hint(1) acq_rel compare
+ r = b .eq. a
+ !$omp end atomic
+
+ ! Check for error conidtions:
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
+ !ERROR: At most one SEQ_CST clause can appear on the COMPARE directive
+ !$omp atomic seq_cst seq_cst compare
+ r = a .le. b
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
+ !ERROR: At most one SEQ_CST clause can appear on the COMPARE directive
+ !$omp atomic compare seq_cst seq_cst
+ r = b .gt. a
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
+ !ERROR: At most one SEQ_CST clause can appear on the COMPARE directive
+ !$omp atomic seq_cst compare seq_cst
+ r = b .ge. b
+
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
+ !ERROR: At most one ACQUIRE clause can appear on the COMPARE directive
+ !$omp atomic acquire acquire compare
+ r = a .le. b
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
+ !ERROR: At most one ACQUIRE clause can appear on the COMPARE directive
+ !$omp atomic compare acquire acquire
+ r = b .gt. a
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
+ !ERROR: At most one ACQUIRE clause can appear on the COMPARE directive
+ !$omp atomic acquire compare acquire
+ r = b .ge. b
+
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
+ !ERROR: At most one RELAXED clause can appear on the COMPARE directive
+ !$omp atomic relaxed relaxed compare
+ r = a .le. b
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
+ !ERROR: At most one RELAXED clause can appear on the COMPARE directive
+ !$omp atomic compare relaxed relaxed
+ r = b .gt. a
+ !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
+ !ERROR: At most one RELAXED clause can appear on the COMPARE directive
+ !$omp atomic relaxed compare relaxed
+ r = b .ge. b
+
+ !$omp end parallel
+end
diff --git a/flang/test/Semantics/OpenMP/atomic.f90 b/flang/test/Semantics/OpenMP/atomic.f90
index 44f06b7460bf10..0e100871ea9b48 100644
--- a/flang/test/Semantics/OpenMP/atomic.f90
+++ b/flang/test/Semantics/OpenMP/atomic.f90
@@ -35,6 +35,7 @@
a = a + 1
!ERROR: expected 'UPDATE'
!ERROR: expected 'WRITE'
+ !ERROR: expected 'COMPARE'
!ERROR: expected 'CAPTURE'
!ERROR: expected 'READ'
!$omp atomic num_threads(4)
@@ -49,6 +50,7 @@
!ERROR: expected 'UPDATE'
!ERROR: expected 'WRITE'
+ !ERROR: expected 'COMPARE'
!ERROR: expected 'CAPTURE'
!ERROR: expected 'READ'
!$omp atomic num_threads write
|
I'm not sure if this is "enough", or I need to do all of the Semantics checks for "right type of expression", "only calling min or max", and such things [and possible other bits and pieces]. I just realized I didn't add the test in lowering, that checks for "Not yet implemented". I have it in another directory at the moment. I will definitely fix this before submitting ;) I'll be away from computers for a few days, so any comments welcome, but don't expect replies until Tuesday. |
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.
LGTM with the test for the TODO message added.
I don't think we have to implement all of the semantic checks now. It is useful just to be able to parse it correctly and inform the user that this feature is not yet supported.
@@ -4126,6 +4126,15 @@ struct OmpAtomicCapture { | |||
t; | |||
}; | |||
|
|||
// ATOMCI COMPARE (OpenMP 5.1, Spec: 15.8.4) |
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.
// ATOMCI COMPARE (OpenMP 5.1, Spec: 15.8.4) | |
// ATOMIC COMPARE (OpenMP 5.1, Spec: 15.8.4) |
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.
Fixed.
@@ -3,6 +3,7 @@ | |||
program main | |||
implicit none | |||
integer :: i, j = 10 | |||
logical :: k |
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.
Nit: is this used?
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.
No, it should have been "r", but given the below comments, we need another variable, I think.
!$omp atomic compare | ||
r = i .eq. j | ||
!$omp atomic seq_cst compare | ||
r = i .eq. j | ||
!$omp atomic compare seq_cst | ||
r = i .eq. j | ||
!$omp atomic release compare | ||
r = i .eq. j | ||
!$omp atomic compare release | ||
r = i .eq. j | ||
!$omp atomic acq_rel compare | ||
r = i .eq. j | ||
!$omp atomic compare acq_rel | ||
r = i .eq. j | ||
!$omp atomic acquire compare | ||
r = i .eq. j | ||
!$omp atomic compare acquire | ||
r = i .eq. j | ||
!$omp atomic relaxed compare | ||
r = i .eq. j | ||
!$omp atomic compare relaxed | ||
r = i .eq. j |
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.
The 5.1 standard specifies the format as follows. You will have to update the tests.
if (x == e) then
x = d
end if
if (x == e) x = d
In 5.2 standard these are described as conditional-update-atomic
.
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.
Fixed.
* Accept only if statements, rather than an assignment statement. * Modify tests to match the if-statment required. * Add test to check for the TODO in lowering.
if (b .eq. a) b = c | ||
!$omp end atomic | ||
|
||
! Check for error conidtions: |
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.
Typo: conidtions -> conditions
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.
Doh, just pushed a fix for the openmp_flags, missed this. Will update in a bit, but want to see if it passes tests first! :)
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.
Well, test didn't work, so needed a change anyway! :) Fingers crossed I figured out what is needed now... 🤞
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.
flang/lib/Parser/openmp-parsers.cpp
Outdated
@@ -10,6 +10,7 @@ | |||
// See OpenMP-4.5-grammar.txt for documentation. | |||
|
|||
#include "basic-parsers.h" | |||
#include "debug-parser.h" |
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.
Is this needed here?
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.
No, it's a leftover from debugging. Fixed now.
This adds a minimalistic implementation of parsing and semantics for the ATOMIC COMPARE feature from OpenMP 5.1.
There is no lowering, just a TODO for that part. Some of the Semantics is also just a comment explaining that more is needed.