Skip to content

Commit 03b5f8f

Browse files
[flang][OpenMP]Add parsing and semantics support for ATOMIC COMPARE (#117032)
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.
1 parent b587b91 commit 03b5f8f

File tree

12 files changed

+238
-2
lines changed

12 files changed

+238
-2
lines changed

flang/include/flang/Parser/dump-parse-tree.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,8 @@ class ParseTreeDumper {
489489
NODE(parser, OmpAtomicCapture)
490490
NODE(OmpAtomicCapture, Stmt1)
491491
NODE(OmpAtomicCapture, Stmt2)
492+
NODE(parser, OmpAtomicCompare)
493+
NODE(parser, OmpAtomicCompareIfStmt)
492494
NODE(parser, OmpAtomicRead)
493495
NODE(parser, OmpAtomicUpdate)
494496
NODE(parser, OmpAtomicWrite)

flang/include/flang/Parser/parse-tree.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4225,6 +4225,20 @@ struct OmpAtomicCapture {
42254225
t;
42264226
};
42274227

4228+
struct OmpAtomicCompareIfStmt {
4229+
UNION_CLASS_BOILERPLATE(OmpAtomicCompareIfStmt);
4230+
std::variant<common::Indirection<IfStmt>, common::Indirection<IfConstruct>> u;
4231+
};
4232+
4233+
// ATOMIC COMPARE (OpenMP 5.1, OPenMP 5.2 spec: 15.8.4)
4234+
struct OmpAtomicCompare {
4235+
TUPLE_CLASS_BOILERPLATE(OmpAtomicCompare);
4236+
CharBlock source;
4237+
std::tuple<OmpAtomicClauseList, Verbatim, OmpAtomicClauseList,
4238+
OmpAtomicCompareIfStmt, std::optional<OmpEndAtomic>>
4239+
t;
4240+
};
4241+
42284242
// ATOMIC
42294243
struct OmpAtomic {
42304244
TUPLE_CLASS_BOILERPLATE(OmpAtomic);
@@ -4237,11 +4251,11 @@ struct OmpAtomic {
42374251
// 2.17.7 atomic ->
42384252
// ATOMIC [atomic-clause-list] atomic-construct [atomic-clause-list] |
42394253
// ATOMIC [atomic-clause-list]
4240-
// atomic-construct -> READ | WRITE | UPDATE | CAPTURE
4254+
// atomic-construct -> READ | WRITE | UPDATE | CAPTURE | COMPARE
42414255
struct OpenMPAtomicConstruct {
42424256
UNION_CLASS_BOILERPLATE(OpenMPAtomicConstruct);
42434257
std::variant<OmpAtomicRead, OmpAtomicWrite, OmpAtomicCapture, OmpAtomicUpdate,
4244-
OmpAtomic>
4258+
OmpAtomicCompare, OmpAtomic>
42454259
u;
42464260
};
42474261

flang/lib/Lower/OpenMP/OpenMP.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2810,6 +2810,10 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
28102810
parser::OmpAtomicClauseList>(
28112811
converter, atomicCapture, loc);
28122812
},
2813+
[&](const parser::OmpAtomicCompare &atomicCompare) {
2814+
mlir::Location loc = converter.genLocation(atomicCompare.source);
2815+
TODO(loc, "OpenMP atomic compare");
2816+
},
28132817
},
28142818
atomicConstruct.u);
28152819
}

flang/lib/Parser/openmp-parsers.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,17 @@ TYPE_PARSER("ATOMIC" >>
825825
Parser<OmpAtomicClauseList>{} / endOmpLine, statement(assignmentStmt),
826826
statement(assignmentStmt), Parser<OmpEndAtomic>{} / endOmpLine)))
827827

828+
TYPE_PARSER(construct<OmpAtomicCompareIfStmt>(indirect(Parser<IfStmt>{})) ||
829+
construct<OmpAtomicCompareIfStmt>(indirect(Parser<IfConstruct>{})))
830+
831+
// OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] COMPARE [MEMORY-ORDER-CLAUSE-LIST]
832+
TYPE_PARSER("ATOMIC" >>
833+
sourced(construct<OmpAtomicCompare>(
834+
Parser<OmpAtomicClauseList>{} / maybe(","_tok), verbatim("COMPARE"_tok),
835+
Parser<OmpAtomicClauseList>{} / endOmpLine,
836+
Parser<OmpAtomicCompareIfStmt>{},
837+
maybe(Parser<OmpEndAtomic>{} / endOmpLine))))
838+
828839
// OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] UPDATE [MEMORY-ORDER-CLAUSE-LIST]
829840
TYPE_PARSER("ATOMIC" >>
830841
sourced(construct<OmpAtomicUpdate>(
@@ -847,6 +858,7 @@ TYPE_PARSER("ATOMIC" >>
847858
// Atomic Construct
848859
TYPE_PARSER(construct<OpenMPAtomicConstruct>(Parser<OmpAtomicRead>{}) ||
849860
construct<OpenMPAtomicConstruct>(Parser<OmpAtomicCapture>{}) ||
861+
construct<OpenMPAtomicConstruct>(Parser<OmpAtomicCompare>{}) ||
850862
construct<OpenMPAtomicConstruct>(Parser<OmpAtomicWrite>{}) ||
851863
construct<OpenMPAtomicConstruct>(Parser<OmpAtomicUpdate>{}) ||
852864
construct<OpenMPAtomicConstruct>(Parser<OmpAtomic>{}))

flang/lib/Parser/unparse.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2437,6 +2437,16 @@ class UnparseVisitor {
24372437
Word("!$OMP END ATOMIC\n");
24382438
EndOpenMP();
24392439
}
2440+
void Unparse(const OmpAtomicCompare &x) {
2441+
BeginOpenMP();
2442+
Word("!$OMP ATOMIC");
2443+
Walk(std::get<0>(x.t));
2444+
Word(" COMPARE");
2445+
Walk(std::get<2>(x.t));
2446+
Put("\n");
2447+
EndOpenMP();
2448+
Walk(std::get<OmpAtomicCompareIfStmt>(x.t));
2449+
}
24402450
void Unparse(const OmpAtomicRead &x) {
24412451
BeginOpenMP();
24422452
Word("!$OMP ATOMIC");

flang/lib/Semantics/check-omp-structure.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,6 +2413,23 @@ void OmpStructureChecker::CheckAtomicUpdateStmt(
24132413
ErrIfAllocatableVariable(var);
24142414
}
24152415

2416+
void OmpStructureChecker::CheckAtomicCompareConstruct(
2417+
const parser::OmpAtomicCompare &atomicCompareConstruct) {
2418+
2419+
// TODO: Check that the if-stmt is `if (var == expr) var = new`
2420+
// [with or without then/end-do]
2421+
2422+
unsigned version{context_.langOptions().OpenMPVersion};
2423+
if (version < 51) {
2424+
context_.Say(atomicCompareConstruct.source,
2425+
"%s construct not allowed in %s, %s"_err_en_US,
2426+
atomicCompareConstruct.source, ThisVersion(version), TryVersion(51));
2427+
}
2428+
2429+
// TODO: More work needed here. Some of the Update restrictions need to
2430+
// be added, but Update isn't the same either.
2431+
}
2432+
24162433
// TODO: Allow cond-update-stmt once compare clause is supported.
24172434
void OmpStructureChecker::CheckAtomicCaptureConstruct(
24182435
const parser::OmpAtomicCapture &atomicCaptureConstruct) {
@@ -2558,6 +2575,16 @@ void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
25582575
&std::get<0>(atomicCapture.t), &std::get<2>(atomicCapture.t));
25592576
CheckAtomicCaptureConstruct(atomicCapture);
25602577
},
2578+
[&](const parser::OmpAtomicCompare &atomicCompare) {
2579+
const auto &dir{std::get<parser::Verbatim>(atomicCompare.t)};
2580+
PushContextAndClauseSets(
2581+
dir.source, llvm::omp::Directive::OMPD_atomic);
2582+
CheckAtomicMemoryOrderClause(
2583+
&std::get<0>(atomicCompare.t), &std::get<2>(atomicCompare.t));
2584+
CheckHintClause<const parser::OmpAtomicClauseList>(
2585+
&std::get<0>(atomicCompare.t), &std::get<2>(atomicCompare.t));
2586+
CheckAtomicCompareConstruct(atomicCompare);
2587+
},
25612588
},
25622589
x.u);
25632590
}

flang/lib/Semantics/check-omp-structure.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ class OmpStructureChecker
209209
void CheckAtomicCaptureStmt(const parser::AssignmentStmt &);
210210
void CheckAtomicWriteStmt(const parser::AssignmentStmt &);
211211
void CheckAtomicCaptureConstruct(const parser::OmpAtomicCapture &);
212+
void CheckAtomicCompareConstruct(const parser::OmpAtomicCompare &);
212213
void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &);
213214
void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
214215
void CheckSIMDNest(const parser::OpenMPConstruct &x);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -fopenmp-version=51 -o - %s 2>&1 | FileCheck %s
2+
3+
! CHECK: not yet implemented: OpenMP atomic compare
4+
program p
5+
integer :: x
6+
logical :: r
7+
!$omp atomic compare
8+
if (x .eq. 0) then
9+
x = 2
10+
end if
11+
end program p
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
! RUN: not %flang_fc1 -fopenmp-version=51 -fopenmp %s 2>&1 | FileCheck %s
2+
! OpenMP version for documentation purposes only - it isn't used until Sema.
3+
! This is testing for Parser errors that bail out before Sema.
4+
program main
5+
implicit none
6+
integer :: i, j = 10
7+
logical :: r
8+
9+
!CHECK: error: expected OpenMP construct
10+
!$omp atomic compare write
11+
r = i .eq. j + 1
12+
13+
!CHECK: error: expected end of line
14+
!$omp atomic compare num_threads(4)
15+
r = i .eq. j
16+
end program main

flang/test/Parser/OpenMP/atomic-unparse.f90

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
program main
44
implicit none
55
integer :: i, j = 10
6+
integer :: k
67
!READ
78
!$omp atomic read
89
i = j
@@ -121,6 +122,49 @@ program main
121122
i = j
122123
!$omp end atomic
123124

125+
!COMPARE
126+
!$omp atomic compare
127+
if (k == i) k = j
128+
!$omp atomic seq_cst compare
129+
if (k == j) then
130+
k = i
131+
end if
132+
!$omp atomic compare seq_cst
133+
if (k .eq. j) then
134+
k = i
135+
end if
136+
!$omp atomic release compare
137+
if (i .eq. j) k = i
138+
!$omp atomic compare release
139+
if (i .eq. j) then
140+
i = k
141+
end if
142+
!$omp atomic acq_rel compare
143+
if (k .eq. j) then
144+
j = i
145+
end if
146+
!$omp atomic compare acq_rel
147+
if (i .eq. j) then
148+
i = k
149+
end if
150+
!$omp atomic acquire compare
151+
if (i .eq. j + 1) then
152+
i = j
153+
end if
154+
155+
!$omp atomic compare acquire
156+
if (i .eq. j) then
157+
i = k
158+
end if
159+
!$omp atomic relaxed compare
160+
if (i .eq. j) then
161+
i = k
162+
end if
163+
!$omp atomic compare relaxed
164+
if (i .eq. k) then
165+
i = j
166+
end if
167+
124168
!ATOMIC
125169
!$omp atomic
126170
i = j
@@ -205,6 +249,20 @@ end program main
205249
!CHECK: !$OMP ATOMIC CAPTURE RELAXED
206250
!CHECK: !$OMP END ATOMIC
207251

252+
!COMPARE
253+
254+
!CHECK: !$OMP ATOMIC COMPARE
255+
!CHECK: !$OMP ATOMIC SEQ_CST COMPARE
256+
!CHECK: !$OMP ATOMIC COMPARE SEQ_CST
257+
!CHECK: !$OMP ATOMIC RELEASE COMPARE
258+
!CHECK: !$OMP ATOMIC COMPARE RELEASE
259+
!CHECK: !$OMP ATOMIC ACQ_REL COMPARE
260+
!CHECK: !$OMP ATOMIC COMPARE ACQ_REL
261+
!CHECK: !$OMP ATOMIC ACQUIRE COMPARE
262+
!CHECK: !$OMP ATOMIC COMPARE ACQUIRE
263+
!CHECK: !$OMP ATOMIC RELAXED COMPARE
264+
!CHECK: !$OMP ATOMIC COMPARE RELAXED
265+
208266
!ATOMIC
209267
!CHECK: !$OMP ATOMIC
210268
!CHECK: !$OMP ATOMIC SEQ_CST
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
! REQUIRES: openmp_runtime
2+
! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags -fopenmp-version=51
3+
use omp_lib
4+
implicit none
5+
! Check atomic compare. This combines elements from multiple other "atomic*.f90", as
6+
! to avoid having several files with just a few lines in them. atomic compare needs
7+
! higher openmp version than the others, so need a separate file.
8+
9+
10+
real a, b, c
11+
a = 1.0
12+
b = 2.0
13+
c = 3.0
14+
!$omp parallel num_threads(4)
15+
! First a few things that should compile without error.
16+
!$omp atomic seq_cst, compare
17+
if (b .eq. a) then
18+
b = c
19+
end if
20+
21+
!$omp atomic seq_cst compare
22+
if (a .eq. b) a = c
23+
!$omp end atomic
24+
25+
!$omp atomic compare acquire hint(OMP_LOCK_HINT_CONTENDED)
26+
if (b .eq. a) b = c
27+
28+
!$omp atomic release hint(OMP_LOCK_HINT_UNCONTENDED) compare
29+
if (b .eq. a) b = c
30+
31+
!$omp atomic compare seq_cst
32+
if (b .eq. c) b = a
33+
34+
!$omp atomic hint(1) acq_rel compare
35+
if (b .eq. a) b = c
36+
!$omp end atomic
37+
38+
! Check for error conditions:
39+
!ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
40+
!ERROR: At most one SEQ_CST clause can appear on the COMPARE directive
41+
!$omp atomic seq_cst seq_cst compare
42+
if (b .eq. c) b = a
43+
!ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
44+
!ERROR: At most one SEQ_CST clause can appear on the COMPARE directive
45+
!$omp atomic compare seq_cst seq_cst
46+
if (b .eq. c) b = a
47+
!ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
48+
!ERROR: At most one SEQ_CST clause can appear on the COMPARE directive
49+
!$omp atomic seq_cst compare seq_cst
50+
if (b .eq. c) b = a
51+
52+
!ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
53+
!ERROR: At most one ACQUIRE clause can appear on the COMPARE directive
54+
!$omp atomic acquire acquire compare
55+
if (b .eq. c) b = a
56+
!ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
57+
!ERROR: At most one ACQUIRE clause can appear on the COMPARE directive
58+
!$omp atomic compare acquire acquire
59+
if (b .eq. c) b = a
60+
!ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
61+
!ERROR: At most one ACQUIRE clause can appear on the COMPARE directive
62+
!$omp atomic acquire compare acquire
63+
if (b .eq. c) b = a
64+
65+
!ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
66+
!ERROR: At most one RELAXED clause can appear on the COMPARE directive
67+
!$omp atomic relaxed relaxed compare
68+
if (b .eq. c) b = a
69+
!ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
70+
!ERROR: At most one RELAXED clause can appear on the COMPARE directive
71+
!$omp atomic compare relaxed relaxed
72+
if (b .eq. c) b = a
73+
!ERROR: More than one memory order clause not allowed on OpenMP Atomic construct
74+
!ERROR: At most one RELAXED clause can appear on the COMPARE directive
75+
!$omp atomic relaxed compare relaxed
76+
if (b .eq. c) b = a
77+
78+
!$omp end parallel
79+
end

flang/test/Semantics/OpenMP/atomic.f90

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
a = a + 1
3636
!ERROR: expected 'UPDATE'
3737
!ERROR: expected 'WRITE'
38+
!ERROR: expected 'COMPARE'
3839
!ERROR: expected 'CAPTURE'
3940
!ERROR: expected 'READ'
4041
!$omp atomic num_threads(4)
@@ -49,6 +50,7 @@
4950

5051
!ERROR: expected 'UPDATE'
5152
!ERROR: expected 'WRITE'
53+
!ERROR: expected 'COMPARE'
5254
!ERROR: expected 'CAPTURE'
5355
!ERROR: expected 'READ'
5456
!$omp atomic num_threads write

0 commit comments

Comments
 (0)