1 | //===-- lib/Parser/openacc-parsers.cpp ------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // Top-level grammar specification for OpenACC 3.3. |
10 | |
11 | #include "basic-parsers.h" |
12 | #include "expr-parsers.h" |
13 | #include "misc-parsers.h" |
14 | #include "stmt-parser.h" |
15 | #include "token-parsers.h" |
16 | #include "type-parser-implementation.h" |
17 | #include "flang/Parser/parse-tree.h" |
18 | |
19 | // OpenACC Directives and Clauses |
20 | namespace Fortran::parser { |
21 | |
22 | // Only need to handle ! line comments because prescanning normalizes the |
23 | // other types of line comments from fixed form. |
24 | constexpr auto startAccLine{skipStuffBeforeStatement >> |
25 | withMessage( |
26 | "expected OpenACC directive sentinel: !$ACC, C$ACC, or *$ACC"_err_en_US , |
27 | "!$ACC "_sptok )}; |
28 | constexpr auto endAccLine{space >> |
29 | recovery( |
30 | withMessage("expected end of OpenACC directive"_err_en_US , endOfLine), |
31 | SkipTo<'\n'>{} || ok)}; |
32 | |
33 | // Autogenerated clauses parser. Information is taken from ACC.td and the |
34 | // parser is generated by tablegen. |
35 | // Scalar value parsers are provided by Flang directly. Specific value parsers |
36 | // are provided below. |
37 | #define GEN_FLANG_CLAUSES_PARSER |
38 | #include "llvm/Frontend/OpenACC/ACC.inc" |
39 | |
40 | TYPE_PARSER( |
41 | construct<AccObject>(designator) || construct<AccObject>("/" >> name / "/" )) |
42 | |
43 | TYPE_PARSER(construct<AccObjectList>(nonemptyList(Parser<AccObject>{}))) |
44 | |
45 | TYPE_PARSER(construct<AccObjectListWithModifier>( |
46 | maybe(Parser<AccDataModifier>{}), Parser<AccObjectList>{})) |
47 | |
48 | TYPE_PARSER(construct<AccObjectListWithReduction>( |
49 | Parser<ReductionOperator>{} / ":" , Parser<AccObjectList>{})) |
50 | |
51 | // 2.16 (3249) wait-argument is: |
52 | // [devnum : int-expr :] [queues :] int-expr-list |
53 | TYPE_PARSER(construct<AccWaitArgument>(maybe("DEVNUM:" >> scalarIntExpr / ":" ), |
54 | "QUEUES:" >> nonemptyList(scalarIntExpr) || nonemptyList(scalarIntExpr))) |
55 | |
56 | // 2.9 (1984-1986) size-expr is one of: |
57 | // * (represented as an empty std::optional<ScalarIntExpr>) |
58 | // int-expr |
59 | TYPE_PARSER(construct<AccSizeExpr>(scalarIntExpr) || |
60 | construct<AccSizeExpr>("*" >> construct<std::optional<ScalarIntExpr>>())) |
61 | TYPE_PARSER(construct<AccSizeExprList>(nonemptyList(Parser<AccSizeExpr>{}))) |
62 | |
63 | TYPE_PARSER(sourced(construct<AccDeviceTypeExpr>( |
64 | first("*" >> pure(Fortran::common::OpenACCDeviceType::Star), |
65 | "DEFAULT" >> pure(Fortran::common::OpenACCDeviceType::Default), |
66 | "NVIDIA" >> pure(Fortran::common::OpenACCDeviceType::Nvidia), |
67 | "ACC_DEVICE_NVIDIA" >> pure(Fortran::common::OpenACCDeviceType::Nvidia), |
68 | "RADEON" >> pure(Fortran::common::OpenACCDeviceType::Radeon), |
69 | "HOST" >> pure(Fortran::common::OpenACCDeviceType::Host), |
70 | "MULTICORE" >> pure(Fortran::common::OpenACCDeviceType::Multicore))))) |
71 | |
72 | TYPE_PARSER( |
73 | construct<AccDeviceTypeExprList>(nonemptyList(Parser<AccDeviceTypeExpr>{}))) |
74 | |
75 | // tile size is one of: |
76 | // * (represented as an empty std::optional<ScalarIntExpr>) |
77 | // constant-int-expr |
78 | TYPE_PARSER(construct<AccTileExpr>(scalarIntConstantExpr) || |
79 | construct<AccTileExpr>( |
80 | "*" >> construct<std::optional<ScalarIntConstantExpr>>())) |
81 | TYPE_PARSER(construct<AccTileExprList>(nonemptyList(Parser<AccTileExpr>{}))) |
82 | |
83 | // 2.9 (1979-1982) gang-arg is one of : |
84 | // [num:]int-expr |
85 | // dim:int-expr |
86 | // static:size-expr |
87 | TYPE_PARSER(construct<AccGangArg>(construct<AccGangArg::Static>( |
88 | "STATIC: " >> Parser<AccSizeExpr>{})) || |
89 | construct<AccGangArg>( |
90 | construct<AccGangArg::Dim>("DIM: " >> scalarIntExpr)) || |
91 | construct<AccGangArg>( |
92 | construct<AccGangArg::Num>(maybe("NUM: "_tok ) >> scalarIntExpr))) |
93 | |
94 | // 2.9 gang-arg-list |
95 | TYPE_PARSER( |
96 | construct<AccGangArgList>(many(maybe(","_tok ) >> Parser<AccGangArg>{}))) |
97 | |
98 | // 2.9.1 collapse |
99 | TYPE_PARSER(construct<AccCollapseArg>( |
100 | "FORCE:"_tok >> pure(true) || pure(false), scalarIntConstantExpr)) |
101 | |
102 | // 2.5.15 Reduction, F'2023 R1131, and CUF reduction-op |
103 | // Operator for reduction |
104 | TYPE_PARSER(sourced(construct<ReductionOperator>( |
105 | first("+" >> pure(ReductionOperator::Operator::Plus), |
106 | "*" >> pure(ReductionOperator::Operator::Multiply), |
107 | "MAX" >> pure(ReductionOperator::Operator::Max), |
108 | "MIN" >> pure(ReductionOperator::Operator::Min), |
109 | "IAND" >> pure(ReductionOperator::Operator::Iand), |
110 | "IOR" >> pure(ReductionOperator::Operator::Ior), |
111 | "IEOR" >> pure(ReductionOperator::Operator::Ieor), |
112 | ".AND." >> pure(ReductionOperator::Operator::And), |
113 | ".OR." >> pure(ReductionOperator::Operator::Or), |
114 | ".EQV." >> pure(ReductionOperator::Operator::Eqv), |
115 | ".NEQV." >> pure(ReductionOperator::Operator::Neqv))))) |
116 | |
117 | // 2.15.1 Bind clause |
118 | TYPE_PARSER(sourced(construct<AccBindClause>(name)) || |
119 | sourced(construct<AccBindClause>(scalarDefaultCharExpr))) |
120 | |
121 | // 2.5.16 Default clause |
122 | TYPE_PARSER(construct<AccDefaultClause>( |
123 | first("NONE" >> pure(llvm::acc::DefaultValue::ACC_Default_none), |
124 | "PRESENT" >> pure(llvm::acc::DefaultValue::ACC_Default_present)))) |
125 | |
126 | // SELF clause is either a simple optional condition for compute construct |
127 | // or a synonym of the HOST clause for the update directive 2.14.4 holding |
128 | // an object list. |
129 | TYPE_PARSER( |
130 | construct<AccSelfClause>(Parser<AccObjectList>{}) / lookAhead(")"_tok ) || |
131 | construct<AccSelfClause>(scalarLogicalExpr / lookAhead(")"_tok )) || |
132 | construct<AccSelfClause>( |
133 | recovery(fail<std::optional<ScalarLogicalExpr>>( |
134 | "logical expression or object list expected"_err_en_US ), |
135 | SkipTo<')'>{} >> pure<std::optional<ScalarLogicalExpr>>()))) |
136 | |
137 | // Modifier for copyin, copyout, cache and create |
138 | TYPE_PARSER(construct<AccDataModifier>( |
139 | first("ZERO:" >> pure(AccDataModifier::Modifier::Zero), |
140 | "READONLY:" >> pure(AccDataModifier::Modifier::ReadOnly)))) |
141 | |
142 | // Combined directives |
143 | TYPE_PARSER(sourced(construct<AccCombinedDirective>( |
144 | first("KERNELS LOOP" >> pure(llvm::acc::Directive::ACCD_kernels_loop), |
145 | "PARALLEL LOOP" >> pure(llvm::acc::Directive::ACCD_parallel_loop), |
146 | "SERIAL LOOP" >> pure(llvm::acc::Directive::ACCD_serial_loop))))) |
147 | |
148 | // Block directives |
149 | TYPE_PARSER(sourced(construct<AccBlockDirective>( |
150 | first("DATA" >> pure(llvm::acc::Directive::ACCD_data), |
151 | "HOST_DATA" >> pure(llvm::acc::Directive::ACCD_host_data), |
152 | "KERNELS" >> pure(llvm::acc::Directive::ACCD_kernels), |
153 | "PARALLEL" >> pure(llvm::acc::Directive::ACCD_parallel), |
154 | "SERIAL" >> pure(llvm::acc::Directive::ACCD_serial))))) |
155 | |
156 | // Standalone directives |
157 | TYPE_PARSER(sourced(construct<AccStandaloneDirective>( |
158 | first("ENTER DATA" >> pure(llvm::acc::Directive::ACCD_enter_data), |
159 | "EXIT DATA" >> pure(llvm::acc::Directive::ACCD_exit_data), |
160 | "INIT" >> pure(llvm::acc::Directive::ACCD_init), |
161 | "SHUTDOWN" >> pure(llvm::acc::Directive::ACCD_shutdown), |
162 | "SET" >> pure(llvm::acc::Directive::ACCD_set), |
163 | "UPDATE" >> pure(llvm::acc::Directive::ACCD_update))))) |
164 | |
165 | // Loop directives |
166 | TYPE_PARSER(sourced(construct<AccLoopDirective>( |
167 | first("LOOP" >> pure(llvm::acc::Directive::ACCD_loop))))) |
168 | |
169 | TYPE_PARSER(construct<AccBeginLoopDirective>( |
170 | sourced(Parser<AccLoopDirective>{}), Parser<AccClauseList>{})) |
171 | |
172 | TYPE_PARSER(construct<AccEndLoop>("END LOOP"_tok )) |
173 | |
174 | TYPE_PARSER(construct<OpenACCLoopConstruct>( |
175 | sourced(Parser<AccBeginLoopDirective>{} / endAccLine), |
176 | maybe(Parser<DoConstruct>{}), |
177 | maybe(startAccLine >> Parser<AccEndLoop>{} / endAccLine))) |
178 | |
179 | // 2.15.1 Routine directive |
180 | TYPE_PARSER(sourced(construct<OpenACCRoutineConstruct>(verbatim("ROUTINE"_tok ), |
181 | maybe(parenthesized(name)), Parser<AccClauseList>{}))) |
182 | |
183 | // 2.10 Cache directive |
184 | TYPE_PARSER(sourced( |
185 | construct<OpenACCCacheConstruct>(sourced(construct<Verbatim>("CACHE"_tok )), |
186 | parenthesized(Parser<AccObjectListWithModifier>{})))) |
187 | |
188 | // 2.11 Combined constructs |
189 | TYPE_PARSER(construct<AccBeginCombinedDirective>( |
190 | sourced(Parser<AccCombinedDirective>{}), Parser<AccClauseList>{})) |
191 | |
192 | // 2.12 Atomic constructs |
193 | TYPE_PARSER(construct<AccEndAtomic>(startAccLine >> "END ATOMIC"_tok )) |
194 | |
195 | TYPE_PARSER("ATOMIC" >> construct<AccAtomicRead>(verbatim("READ"_tok ), |
196 | Parser<AccClauseList>{} / endAccLine, |
197 | statement(assignmentStmt), |
198 | maybe(Parser<AccEndAtomic>{} / endAccLine))) |
199 | |
200 | TYPE_PARSER("ATOMIC" >> construct<AccAtomicWrite>(verbatim("WRITE"_tok ), |
201 | Parser<AccClauseList>{} / endAccLine, |
202 | statement(assignmentStmt), |
203 | maybe(Parser<AccEndAtomic>{} / endAccLine))) |
204 | |
205 | TYPE_PARSER("ATOMIC" >> |
206 | construct<AccAtomicUpdate>(maybe(verbatim("UPDATE"_tok )), |
207 | Parser<AccClauseList>{} / endAccLine, statement(assignmentStmt), |
208 | maybe(Parser<AccEndAtomic>{} / endAccLine))) |
209 | |
210 | TYPE_PARSER("ATOMIC" >> |
211 | construct<AccAtomicCapture>(verbatim("CAPTURE"_tok ), |
212 | Parser<AccClauseList>{} / endAccLine, statement(assignmentStmt), |
213 | statement(assignmentStmt), Parser<AccEndAtomic>{} / endAccLine)) |
214 | |
215 | TYPE_PARSER( |
216 | sourced(construct<OpenACCAtomicConstruct>(Parser<AccAtomicRead>{})) || |
217 | sourced(construct<OpenACCAtomicConstruct>(Parser<AccAtomicCapture>{})) || |
218 | sourced(construct<OpenACCAtomicConstruct>(Parser<AccAtomicWrite>{})) || |
219 | sourced(construct<OpenACCAtomicConstruct>(Parser<AccAtomicUpdate>{}))) |
220 | |
221 | // 2.13 Declare constructs |
222 | TYPE_PARSER(sourced(construct<AccDeclarativeDirective>( |
223 | first("DECLARE" >> pure(llvm::acc::Directive::ACCD_declare))))) |
224 | |
225 | // [Clause, [Clause], ...] |
226 | TYPE_PARSER(sourced(construct<AccClauseList>( |
227 | many(maybe(","_tok ) >> sourced(Parser<AccClause>{}))))) |
228 | |
229 | // 2.16.3 Wait directive |
230 | TYPE_PARSER(sourced(construct<OpenACCWaitConstruct>( |
231 | sourced(construct<Verbatim>("WAIT"_tok )), |
232 | maybe(parenthesized(Parser<AccWaitArgument>{})), Parser<AccClauseList>{}))) |
233 | |
234 | // Block Constructs |
235 | TYPE_PARSER(sourced(construct<AccBeginBlockDirective>( |
236 | sourced(Parser<AccBlockDirective>{}), Parser<AccClauseList>{}))) |
237 | |
238 | TYPE_PARSER(startAccLine >> sourced(construct<AccEndBlockDirective>("END"_tok >> |
239 | recovery(sourced(Parser<AccBlockDirective>{}), |
240 | construct<AccBlockDirective>(pure( |
241 | llvm::acc::Directive::ACCD_data)))))) |
242 | |
243 | TYPE_PARSER(construct<OpenACCBlockConstruct>( |
244 | Parser<AccBeginBlockDirective>{} / endAccLine, block, |
245 | // NB, This allows mismatched directives, but semantics checks that they |
246 | // match. |
247 | recovery(withMessage("expected OpenACC end block directive"_err_en_US , |
248 | attempt(Parser<AccEndBlockDirective>{} / endAccLine)), |
249 | construct<AccEndBlockDirective>(construct<AccBlockDirective>( |
250 | pure(llvm::acc::Directive::ACCD_data)))))) |
251 | |
252 | // Standalone constructs |
253 | TYPE_PARSER(construct<OpenACCStandaloneConstruct>( |
254 | sourced(Parser<AccStandaloneDirective>{}), Parser<AccClauseList>{})) |
255 | |
256 | // Standalone declarative constructs |
257 | TYPE_PARSER(construct<OpenACCStandaloneDeclarativeConstruct>( |
258 | sourced(Parser<AccDeclarativeDirective>{}), Parser<AccClauseList>{})) |
259 | |
260 | TYPE_PARSER(startAccLine >> |
261 | withMessage("expected OpenACC directive"_err_en_US , |
262 | first(sourced(construct<OpenACCDeclarativeConstruct>( |
263 | Parser<OpenACCStandaloneDeclarativeConstruct>{})), |
264 | sourced(construct<OpenACCDeclarativeConstruct>( |
265 | Parser<OpenACCRoutineConstruct>{}))))) |
266 | |
267 | TYPE_PARSER(sourced(construct<OpenACCEndConstruct>( |
268 | "END"_tok >> "LOOP"_tok >> pure(llvm::acc::Directive::ACCD_loop)))) |
269 | |
270 | // OpenACC constructs |
271 | TYPE_CONTEXT_PARSER("OpenACC construct"_en_US , |
272 | startAccLine >> |
273 | withMessage("expected OpenACC directive"_err_en_US , |
274 | // Combined constructs before block constructs so we try to match |
275 | // the longest possible match first. |
276 | first( |
277 | construct<OpenACCConstruct>(Parser<OpenACCCombinedConstruct>{}), |
278 | construct<OpenACCConstruct>(Parser<OpenACCBlockConstruct>{}), |
279 | construct<OpenACCConstruct>(Parser<OpenACCLoopConstruct>{}), |
280 | construct<OpenACCConstruct>( |
281 | Parser<OpenACCStandaloneConstruct>{}), |
282 | construct<OpenACCConstruct>(Parser<OpenACCCacheConstruct>{}), |
283 | construct<OpenACCConstruct>(Parser<OpenACCWaitConstruct>{}), |
284 | construct<OpenACCConstruct>(Parser<OpenACCAtomicConstruct>{}), |
285 | construct<OpenACCConstruct>(Parser<OpenACCEndConstruct>{})))) |
286 | |
287 | TYPE_PARSER(startAccLine >> |
288 | sourced(construct<AccEndCombinedDirective>(sourced("END"_tok >> |
289 | construct<AccCombinedDirective>("KERNELS"_tok >> maybe("LOOP"_tok ) >> |
290 | pure(llvm::acc::Directive::ACCD_kernels_loop) || |
291 | "PARALLEL"_tok >> maybe("LOOP"_tok ) >> |
292 | pure(llvm::acc::Directive::ACCD_parallel_loop) || |
293 | "SERIAL"_tok >> maybe("LOOP"_tok ) >> |
294 | pure(llvm::acc::Directive::ACCD_serial_loop)))))) |
295 | |
296 | TYPE_PARSER(construct<OpenACCCombinedConstruct>( |
297 | sourced(Parser<AccBeginCombinedDirective>{} / endAccLine), |
298 | maybe(Parser<DoConstruct>{}), |
299 | maybe(Parser<AccEndCombinedDirective>{} / endAccLine))) |
300 | |
301 | } // namespace Fortran::parser |
302 | |