1 | //===--- ParseOpenACC.cpp - OpenACC-specific parsing support --------------===// |
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 | // This file implements the parsing logic for OpenACC language features. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "clang/Basic/OpenACCKinds.h" |
14 | #include "clang/Parse/ParseDiagnostic.h" |
15 | #include "clang/Parse/Parser.h" |
16 | #include "clang/Parse/RAIIObjectsForParser.h" |
17 | #include "llvm/ADT/StringRef.h" |
18 | #include "llvm/ADT/StringSwitch.h" |
19 | |
20 | using namespace clang; |
21 | using namespace llvm; |
22 | |
23 | namespace { |
24 | // An enum that contains the extended 'partial' parsed variants. This type |
25 | // should never escape the initial parse functionality, but is useful for |
26 | // simplifying the implementation. |
27 | enum class OpenACCDirectiveKindEx { |
28 | Invalid = static_cast<int>(OpenACCDirectiveKind::Invalid), |
29 | // 'enter data' and 'exit data' |
30 | Enter, |
31 | Exit, |
32 | }; |
33 | |
34 | // Translate single-token string representations to the OpenACC Directive Kind. |
35 | // This doesn't completely comprehend 'Compound Constructs' (as it just |
36 | // identifies the first token), and doesn't fully handle 'enter data', 'exit |
37 | // data', nor any of the 'atomic' variants, just the first token of each. So |
38 | // this should only be used by `ParseOpenACCDirectiveKind`. |
39 | OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) { |
40 | if (!Tok.is(K: tok::identifier)) |
41 | return OpenACCDirectiveKindEx::Invalid; |
42 | OpenACCDirectiveKind DirKind = |
43 | llvm::StringSwitch<OpenACCDirectiveKind>( |
44 | Tok.getIdentifierInfo()->getName()) |
45 | .Case(S: "parallel" , Value: OpenACCDirectiveKind::Parallel) |
46 | .Case(S: "serial" , Value: OpenACCDirectiveKind::Serial) |
47 | .Case(S: "kernels" , Value: OpenACCDirectiveKind::Kernels) |
48 | .Case(S: "data" , Value: OpenACCDirectiveKind::Data) |
49 | .Case(S: "host_data" , Value: OpenACCDirectiveKind::HostData) |
50 | .Case(S: "loop" , Value: OpenACCDirectiveKind::Loop) |
51 | .Case(S: "cache" , Value: OpenACCDirectiveKind::Cache) |
52 | .Case(S: "atomic" , Value: OpenACCDirectiveKind::Atomic) |
53 | .Case(S: "routine" , Value: OpenACCDirectiveKind::Routine) |
54 | .Case(S: "declare" , Value: OpenACCDirectiveKind::Declare) |
55 | .Case(S: "init" , Value: OpenACCDirectiveKind::Init) |
56 | .Case(S: "shutdown" , Value: OpenACCDirectiveKind::Shutdown) |
57 | .Case(S: "set" , Value: OpenACCDirectiveKind::Set) |
58 | .Case(S: "update" , Value: OpenACCDirectiveKind::Update) |
59 | .Case(S: "wait" , Value: OpenACCDirectiveKind::Wait) |
60 | .Default(Value: OpenACCDirectiveKind::Invalid); |
61 | |
62 | if (DirKind != OpenACCDirectiveKind::Invalid) |
63 | return static_cast<OpenACCDirectiveKindEx>(DirKind); |
64 | |
65 | return llvm::StringSwitch<OpenACCDirectiveKindEx>( |
66 | Tok.getIdentifierInfo()->getName()) |
67 | .Case(S: "enter" , Value: OpenACCDirectiveKindEx::Enter) |
68 | .Case(S: "exit" , Value: OpenACCDirectiveKindEx::Exit) |
69 | .Default(Value: OpenACCDirectiveKindEx::Invalid); |
70 | } |
71 | |
72 | // Translate single-token string representations to the OpenCC Clause Kind. |
73 | OpenACCClauseKind getOpenACCClauseKind(Token Tok) { |
74 | // auto is a keyword in some language modes, so make sure we parse it |
75 | // correctly. |
76 | if (Tok.is(K: tok::kw_auto)) |
77 | return OpenACCClauseKind::Auto; |
78 | |
79 | // default is a keyword, so make sure we parse it correctly. |
80 | if (Tok.is(K: tok::kw_default)) |
81 | return OpenACCClauseKind::Default; |
82 | |
83 | // if is also a keyword, make sure we parse it correctly. |
84 | if (Tok.is(K: tok::kw_if)) |
85 | return OpenACCClauseKind::If; |
86 | |
87 | if (!Tok.is(K: tok::identifier)) |
88 | return OpenACCClauseKind::Invalid; |
89 | |
90 | return llvm::StringSwitch<OpenACCClauseKind>( |
91 | Tok.getIdentifierInfo()->getName()) |
92 | .Case(S: "async" , Value: OpenACCClauseKind::Async) |
93 | .Case(S: "attach" , Value: OpenACCClauseKind::Attach) |
94 | .Case(S: "auto" , Value: OpenACCClauseKind::Auto) |
95 | .Case(S: "bind" , Value: OpenACCClauseKind::Bind) |
96 | .Case(S: "create" , Value: OpenACCClauseKind::Create) |
97 | .Case(S: "collapse" , Value: OpenACCClauseKind::Collapse) |
98 | .Case(S: "copy" , Value: OpenACCClauseKind::Copy) |
99 | .Case(S: "copyin" , Value: OpenACCClauseKind::CopyIn) |
100 | .Case(S: "copyout" , Value: OpenACCClauseKind::CopyOut) |
101 | .Case(S: "default" , Value: OpenACCClauseKind::Default) |
102 | .Case(S: "default_async" , Value: OpenACCClauseKind::DefaultAsync) |
103 | .Case(S: "delete" , Value: OpenACCClauseKind::Delete) |
104 | .Case(S: "detach" , Value: OpenACCClauseKind::Detach) |
105 | .Case(S: "device" , Value: OpenACCClauseKind::Device) |
106 | .Case(S: "device_num" , Value: OpenACCClauseKind::DeviceNum) |
107 | .Case(S: "device_resident" , Value: OpenACCClauseKind::DeviceResident) |
108 | .Case(S: "device_type" , Value: OpenACCClauseKind::DeviceType) |
109 | .Case(S: "deviceptr" , Value: OpenACCClauseKind::DevicePtr) |
110 | .Case(S: "dtype" , Value: OpenACCClauseKind::DType) |
111 | .Case(S: "finalize" , Value: OpenACCClauseKind::Finalize) |
112 | .Case(S: "firstprivate" , Value: OpenACCClauseKind::FirstPrivate) |
113 | .Case(S: "gang" , Value: OpenACCClauseKind::Gang) |
114 | .Case(S: "host" , Value: OpenACCClauseKind::Host) |
115 | .Case(S: "if" , Value: OpenACCClauseKind::If) |
116 | .Case(S: "if_present" , Value: OpenACCClauseKind::IfPresent) |
117 | .Case(S: "independent" , Value: OpenACCClauseKind::Independent) |
118 | .Case(S: "link" , Value: OpenACCClauseKind::Link) |
119 | .Case(S: "no_create" , Value: OpenACCClauseKind::NoCreate) |
120 | .Case(S: "num_gangs" , Value: OpenACCClauseKind::NumGangs) |
121 | .Case(S: "num_workers" , Value: OpenACCClauseKind::NumWorkers) |
122 | .Case(S: "nohost" , Value: OpenACCClauseKind::NoHost) |
123 | .Case(S: "present" , Value: OpenACCClauseKind::Present) |
124 | .Case(S: "private" , Value: OpenACCClauseKind::Private) |
125 | .Case(S: "reduction" , Value: OpenACCClauseKind::Reduction) |
126 | .Case(S: "self" , Value: OpenACCClauseKind::Self) |
127 | .Case(S: "seq" , Value: OpenACCClauseKind::Seq) |
128 | .Case(S: "tile" , Value: OpenACCClauseKind::Tile) |
129 | .Case(S: "use_device" , Value: OpenACCClauseKind::UseDevice) |
130 | .Case(S: "vector" , Value: OpenACCClauseKind::Vector) |
131 | .Case(S: "vector_length" , Value: OpenACCClauseKind::VectorLength) |
132 | .Case(S: "wait" , Value: OpenACCClauseKind::Wait) |
133 | .Case(S: "worker" , Value: OpenACCClauseKind::Worker) |
134 | .Default(Value: OpenACCClauseKind::Invalid); |
135 | } |
136 | |
137 | // Since 'atomic' is effectively a compound directive, this will decode the |
138 | // second part of the directive. |
139 | OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) { |
140 | if (!Tok.is(K: tok::identifier)) |
141 | return OpenACCAtomicKind::Invalid; |
142 | return llvm::StringSwitch<OpenACCAtomicKind>( |
143 | Tok.getIdentifierInfo()->getName()) |
144 | .Case(S: "read" , Value: OpenACCAtomicKind::Read) |
145 | .Case(S: "write" , Value: OpenACCAtomicKind::Write) |
146 | .Case(S: "update" , Value: OpenACCAtomicKind::Update) |
147 | .Case(S: "capture" , Value: OpenACCAtomicKind::Capture) |
148 | .Default(Value: OpenACCAtomicKind::Invalid); |
149 | } |
150 | |
151 | OpenACCDefaultClauseKind getOpenACCDefaultClauseKind(Token Tok) { |
152 | if (!Tok.is(K: tok::identifier)) |
153 | return OpenACCDefaultClauseKind::Invalid; |
154 | |
155 | return llvm::StringSwitch<OpenACCDefaultClauseKind>( |
156 | Tok.getIdentifierInfo()->getName()) |
157 | .Case(S: "none" , Value: OpenACCDefaultClauseKind::None) |
158 | .Case(S: "present" , Value: OpenACCDefaultClauseKind::Present) |
159 | .Default(Value: OpenACCDefaultClauseKind::Invalid); |
160 | } |
161 | |
162 | enum class OpenACCSpecialTokenKind { |
163 | ReadOnly, |
164 | DevNum, |
165 | Queues, |
166 | Zero, |
167 | Force, |
168 | Num, |
169 | Length, |
170 | Dim, |
171 | Static, |
172 | }; |
173 | |
174 | bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) { |
175 | if (Tok.is(K: tok::kw_static) && Kind == OpenACCSpecialTokenKind::Static) |
176 | return true; |
177 | |
178 | if (!Tok.is(K: tok::identifier)) |
179 | return false; |
180 | |
181 | switch (Kind) { |
182 | case OpenACCSpecialTokenKind::ReadOnly: |
183 | return Tok.getIdentifierInfo()->isStr(Str: "readonly" ); |
184 | case OpenACCSpecialTokenKind::DevNum: |
185 | return Tok.getIdentifierInfo()->isStr(Str: "devnum" ); |
186 | case OpenACCSpecialTokenKind::Queues: |
187 | return Tok.getIdentifierInfo()->isStr(Str: "queues" ); |
188 | case OpenACCSpecialTokenKind::Zero: |
189 | return Tok.getIdentifierInfo()->isStr(Str: "zero" ); |
190 | case OpenACCSpecialTokenKind::Force: |
191 | return Tok.getIdentifierInfo()->isStr(Str: "force" ); |
192 | case OpenACCSpecialTokenKind::Num: |
193 | return Tok.getIdentifierInfo()->isStr(Str: "num" ); |
194 | case OpenACCSpecialTokenKind::Length: |
195 | return Tok.getIdentifierInfo()->isStr(Str: "length" ); |
196 | case OpenACCSpecialTokenKind::Dim: |
197 | return Tok.getIdentifierInfo()->isStr(Str: "dim" ); |
198 | case OpenACCSpecialTokenKind::Static: |
199 | return Tok.getIdentifierInfo()->isStr(Str: "static" ); |
200 | } |
201 | llvm_unreachable("Unknown 'Kind' Passed" ); |
202 | } |
203 | |
204 | /// Used for cases where we have a token we want to check against an |
205 | /// 'identifier-like' token, but don't want to give awkward error messages in |
206 | /// cases where it is accidentially a keyword. |
207 | bool isTokenIdentifierOrKeyword(Parser &P, Token Tok) { |
208 | if (Tok.is(K: tok::identifier)) |
209 | return true; |
210 | |
211 | if (!Tok.isAnnotation() && Tok.getIdentifierInfo() && |
212 | Tok.getIdentifierInfo()->isKeyword(LangOpts: P.getLangOpts())) |
213 | return true; |
214 | |
215 | return false; |
216 | } |
217 | |
218 | /// Parses and consumes an identifer followed immediately by a single colon, and |
219 | /// diagnoses if it is not the 'special token' kind that we require. Used when |
220 | /// the tag is the only valid value. |
221 | /// Return 'true' if the special token was matched, false if no special token, |
222 | /// or an invalid special token was found. |
223 | template <typename DirOrClauseTy> |
224 | bool tryParseAndConsumeSpecialTokenKind(Parser &P, OpenACCSpecialTokenKind Kind, |
225 | DirOrClauseTy DirOrClause) { |
226 | Token IdentTok = P.getCurToken(); |
227 | // If this is an identifier-like thing followed by ':', it is one of the |
228 | // OpenACC 'special' name tags, so consume it. |
229 | if (isTokenIdentifierOrKeyword(P, Tok: IdentTok) && P.NextToken().is(K: tok::colon)) { |
230 | P.ConsumeToken(); |
231 | P.ConsumeToken(); |
232 | |
233 | if (!isOpenACCSpecialToken(Kind, Tok: IdentTok)) { |
234 | P.Diag(IdentTok, diag::err_acc_invalid_tag_kind) |
235 | << IdentTok.getIdentifierInfo() << DirOrClause |
236 | << std::is_same_v<DirOrClauseTy, OpenACCClauseKind>; |
237 | return false; |
238 | } |
239 | |
240 | return true; |
241 | } |
242 | |
243 | return false; |
244 | } |
245 | |
246 | bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) { |
247 | if (!Tok.is(K: tok::identifier)) |
248 | return false; |
249 | |
250 | switch (Kind) { |
251 | case OpenACCDirectiveKind::Parallel: |
252 | return Tok.getIdentifierInfo()->isStr(Str: "parallel" ); |
253 | case OpenACCDirectiveKind::Serial: |
254 | return Tok.getIdentifierInfo()->isStr(Str: "serial" ); |
255 | case OpenACCDirectiveKind::Kernels: |
256 | return Tok.getIdentifierInfo()->isStr(Str: "kernels" ); |
257 | case OpenACCDirectiveKind::Data: |
258 | return Tok.getIdentifierInfo()->isStr(Str: "data" ); |
259 | case OpenACCDirectiveKind::HostData: |
260 | return Tok.getIdentifierInfo()->isStr(Str: "host_data" ); |
261 | case OpenACCDirectiveKind::Loop: |
262 | return Tok.getIdentifierInfo()->isStr(Str: "loop" ); |
263 | case OpenACCDirectiveKind::Cache: |
264 | return Tok.getIdentifierInfo()->isStr(Str: "cache" ); |
265 | |
266 | case OpenACCDirectiveKind::ParallelLoop: |
267 | case OpenACCDirectiveKind::SerialLoop: |
268 | case OpenACCDirectiveKind::KernelsLoop: |
269 | case OpenACCDirectiveKind::EnterData: |
270 | case OpenACCDirectiveKind::ExitData: |
271 | return false; |
272 | |
273 | case OpenACCDirectiveKind::Atomic: |
274 | return Tok.getIdentifierInfo()->isStr(Str: "atomic" ); |
275 | case OpenACCDirectiveKind::Routine: |
276 | return Tok.getIdentifierInfo()->isStr(Str: "routine" ); |
277 | case OpenACCDirectiveKind::Declare: |
278 | return Tok.getIdentifierInfo()->isStr(Str: "declare" ); |
279 | case OpenACCDirectiveKind::Init: |
280 | return Tok.getIdentifierInfo()->isStr(Str: "init" ); |
281 | case OpenACCDirectiveKind::Shutdown: |
282 | return Tok.getIdentifierInfo()->isStr(Str: "shutdown" ); |
283 | case OpenACCDirectiveKind::Set: |
284 | return Tok.getIdentifierInfo()->isStr(Str: "set" ); |
285 | case OpenACCDirectiveKind::Update: |
286 | return Tok.getIdentifierInfo()->isStr(Str: "update" ); |
287 | case OpenACCDirectiveKind::Wait: |
288 | return Tok.getIdentifierInfo()->isStr(Str: "wait" ); |
289 | case OpenACCDirectiveKind::Invalid: |
290 | return false; |
291 | } |
292 | llvm_unreachable("Unknown 'Kind' Passed" ); |
293 | } |
294 | |
295 | OpenACCReductionOperator ParseReductionOperator(Parser &P) { |
296 | // If there is no colon, treat as if the reduction operator was missing, else |
297 | // we probably will not recover from it in the case where an expression starts |
298 | // with one of the operator tokens. |
299 | if (P.NextToken().isNot(K: tok::colon)) { |
300 | P.Diag(P.getCurToken(), diag::err_acc_expected_reduction_operator); |
301 | return OpenACCReductionOperator::Invalid; |
302 | } |
303 | Token ReductionKindTok = P.getCurToken(); |
304 | // Consume both the kind and the colon. |
305 | P.ConsumeToken(); |
306 | P.ConsumeToken(); |
307 | |
308 | switch (ReductionKindTok.getKind()) { |
309 | case tok::plus: |
310 | return OpenACCReductionOperator::Addition; |
311 | case tok::star: |
312 | return OpenACCReductionOperator::Multiplication; |
313 | case tok::amp: |
314 | return OpenACCReductionOperator::BitwiseAnd; |
315 | case tok::pipe: |
316 | return OpenACCReductionOperator::BitwiseOr; |
317 | case tok::caret: |
318 | return OpenACCReductionOperator::BitwiseXOr; |
319 | case tok::ampamp: |
320 | return OpenACCReductionOperator::And; |
321 | case tok::pipepipe: |
322 | return OpenACCReductionOperator::Or; |
323 | case tok::identifier: |
324 | if (ReductionKindTok.getIdentifierInfo()->isStr(Str: "max" )) |
325 | return OpenACCReductionOperator::Max; |
326 | if (ReductionKindTok.getIdentifierInfo()->isStr(Str: "min" )) |
327 | return OpenACCReductionOperator::Min; |
328 | LLVM_FALLTHROUGH; |
329 | default: |
330 | P.Diag(ReductionKindTok, diag::err_acc_invalid_reduction_operator); |
331 | return OpenACCReductionOperator::Invalid; |
332 | } |
333 | llvm_unreachable("Reduction op token kind not caught by 'default'?" ); |
334 | } |
335 | |
336 | /// Used for cases where we expect an identifier-like token, but don't want to |
337 | /// give awkward error messages in cases where it is accidentially a keyword. |
338 | bool expectIdentifierOrKeyword(Parser &P) { |
339 | Token Tok = P.getCurToken(); |
340 | |
341 | if (isTokenIdentifierOrKeyword(P, Tok)) |
342 | return false; |
343 | |
344 | P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier; |
345 | return true; |
346 | } |
347 | |
348 | OpenACCDirectiveKind |
349 | ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok, |
350 | OpenACCDirectiveKindEx ExtDirKind) { |
351 | Token SecondTok = P.getCurToken(); |
352 | |
353 | if (SecondTok.isAnnotation()) { |
354 | P.Diag(FirstTok, diag::err_acc_invalid_directive) |
355 | << 0 << FirstTok.getIdentifierInfo(); |
356 | return OpenACCDirectiveKind::Invalid; |
357 | } |
358 | |
359 | // Consume the second name anyway, this way we can continue on without making |
360 | // this oddly look like a clause. |
361 | P.ConsumeAnyToken(); |
362 | |
363 | if (!isOpenACCDirectiveKind(Kind: OpenACCDirectiveKind::Data, Tok: SecondTok)) { |
364 | if (!SecondTok.is(tok::identifier)) |
365 | P.Diag(SecondTok, diag::err_expected) << tok::identifier; |
366 | else |
367 | P.Diag(FirstTok, diag::err_acc_invalid_directive) |
368 | << 1 << FirstTok.getIdentifierInfo()->getName() |
369 | << SecondTok.getIdentifierInfo()->getName(); |
370 | return OpenACCDirectiveKind::Invalid; |
371 | } |
372 | |
373 | return ExtDirKind == OpenACCDirectiveKindEx::Enter |
374 | ? OpenACCDirectiveKind::EnterData |
375 | : OpenACCDirectiveKind::ExitData; |
376 | } |
377 | |
378 | OpenACCAtomicKind ParseOpenACCAtomicKind(Parser &P) { |
379 | Token AtomicClauseToken = P.getCurToken(); |
380 | |
381 | // #pragma acc atomic is equivilent to update: |
382 | if (AtomicClauseToken.isAnnotation()) |
383 | return OpenACCAtomicKind::Update; |
384 | |
385 | OpenACCAtomicKind AtomicKind = getOpenACCAtomicKind(Tok: AtomicClauseToken); |
386 | |
387 | // If we don't know what this is, treat it as 'nothing', and treat the rest of |
388 | // this as a clause list, which, despite being invalid, is likely what the |
389 | // user was trying to do. |
390 | if (AtomicKind == OpenACCAtomicKind::Invalid) |
391 | return OpenACCAtomicKind::Update; |
392 | |
393 | P.ConsumeToken(); |
394 | return AtomicKind; |
395 | } |
396 | |
397 | // Parse and consume the tokens for OpenACC Directive/Construct kinds. |
398 | OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) { |
399 | Token FirstTok = P.getCurToken(); |
400 | |
401 | // Just #pragma acc can get us immediately to the end, make sure we don't |
402 | // introspect on the spelling before then. |
403 | if (FirstTok.isNot(K: tok::identifier)) { |
404 | P.Diag(FirstTok, diag::err_acc_missing_directive); |
405 | |
406 | if (P.getCurToken().isNot(K: tok::annot_pragma_openacc_end)) |
407 | P.ConsumeAnyToken(); |
408 | |
409 | return OpenACCDirectiveKind::Invalid; |
410 | } |
411 | |
412 | P.ConsumeToken(); |
413 | |
414 | OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(Tok: FirstTok); |
415 | |
416 | // OpenACCDirectiveKindEx is meant to be an extended list |
417 | // over OpenACCDirectiveKind, so any value below Invalid is one of the |
418 | // OpenACCDirectiveKind values. This switch takes care of all of the extra |
419 | // parsing required for the Extended values. At the end of this block, |
420 | // ExDirKind can be assumed to be a valid OpenACCDirectiveKind, so we can |
421 | // immediately cast it and use it as that. |
422 | if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) { |
423 | switch (ExDirKind) { |
424 | case OpenACCDirectiveKindEx::Invalid: { |
425 | P.Diag(FirstTok, diag::err_acc_invalid_directive) |
426 | << 0 << FirstTok.getIdentifierInfo(); |
427 | return OpenACCDirectiveKind::Invalid; |
428 | } |
429 | case OpenACCDirectiveKindEx::Enter: |
430 | case OpenACCDirectiveKindEx::Exit: |
431 | return ParseOpenACCEnterExitDataDirective(P, FirstTok, ExtDirKind: ExDirKind); |
432 | } |
433 | } |
434 | |
435 | OpenACCDirectiveKind DirKind = static_cast<OpenACCDirectiveKind>(ExDirKind); |
436 | |
437 | // Combined Constructs allows parallel loop, serial loop, or kernels loop. Any |
438 | // other attempt at a combined construct will be diagnosed as an invalid |
439 | // clause. |
440 | Token SecondTok = P.getCurToken(); |
441 | if (!SecondTok.isAnnotation() && |
442 | isOpenACCDirectiveKind(Kind: OpenACCDirectiveKind::Loop, Tok: SecondTok)) { |
443 | switch (DirKind) { |
444 | default: |
445 | // Nothing to do except in the below cases, as they should be diagnosed as |
446 | // a clause. |
447 | break; |
448 | case OpenACCDirectiveKind::Parallel: |
449 | P.ConsumeToken(); |
450 | return OpenACCDirectiveKind::ParallelLoop; |
451 | case OpenACCDirectiveKind::Serial: |
452 | P.ConsumeToken(); |
453 | return OpenACCDirectiveKind::SerialLoop; |
454 | case OpenACCDirectiveKind::Kernels: |
455 | P.ConsumeToken(); |
456 | return OpenACCDirectiveKind::KernelsLoop; |
457 | } |
458 | } |
459 | |
460 | return DirKind; |
461 | } |
462 | |
463 | enum ClauseParensKind { |
464 | None, |
465 | Optional, |
466 | Required |
467 | }; |
468 | |
469 | ClauseParensKind getClauseParensKind(OpenACCDirectiveKind DirKind, |
470 | OpenACCClauseKind Kind) { |
471 | switch (Kind) { |
472 | case OpenACCClauseKind::Self: |
473 | return DirKind == OpenACCDirectiveKind::Update ? ClauseParensKind::Required |
474 | : ClauseParensKind::Optional; |
475 | case OpenACCClauseKind::Async: |
476 | case OpenACCClauseKind::Worker: |
477 | case OpenACCClauseKind::Vector: |
478 | case OpenACCClauseKind::Gang: |
479 | case OpenACCClauseKind::Wait: |
480 | return ClauseParensKind::Optional; |
481 | |
482 | case OpenACCClauseKind::Default: |
483 | case OpenACCClauseKind::If: |
484 | case OpenACCClauseKind::Create: |
485 | case OpenACCClauseKind::Copy: |
486 | case OpenACCClauseKind::CopyIn: |
487 | case OpenACCClauseKind::CopyOut: |
488 | case OpenACCClauseKind::UseDevice: |
489 | case OpenACCClauseKind::NoCreate: |
490 | case OpenACCClauseKind::Present: |
491 | case OpenACCClauseKind::DevicePtr: |
492 | case OpenACCClauseKind::Attach: |
493 | case OpenACCClauseKind::Detach: |
494 | case OpenACCClauseKind::Private: |
495 | case OpenACCClauseKind::FirstPrivate: |
496 | case OpenACCClauseKind::Delete: |
497 | case OpenACCClauseKind::DeviceResident: |
498 | case OpenACCClauseKind::Device: |
499 | case OpenACCClauseKind::Link: |
500 | case OpenACCClauseKind::Host: |
501 | case OpenACCClauseKind::Reduction: |
502 | case OpenACCClauseKind::Collapse: |
503 | case OpenACCClauseKind::Bind: |
504 | case OpenACCClauseKind::VectorLength: |
505 | case OpenACCClauseKind::NumGangs: |
506 | case OpenACCClauseKind::NumWorkers: |
507 | case OpenACCClauseKind::DeviceNum: |
508 | case OpenACCClauseKind::DefaultAsync: |
509 | case OpenACCClauseKind::DeviceType: |
510 | case OpenACCClauseKind::DType: |
511 | case OpenACCClauseKind::Tile: |
512 | return ClauseParensKind::Required; |
513 | |
514 | case OpenACCClauseKind::Auto: |
515 | case OpenACCClauseKind::Finalize: |
516 | case OpenACCClauseKind::IfPresent: |
517 | case OpenACCClauseKind::Independent: |
518 | case OpenACCClauseKind::Invalid: |
519 | case OpenACCClauseKind::NoHost: |
520 | case OpenACCClauseKind::Seq: |
521 | return ClauseParensKind::None; |
522 | } |
523 | llvm_unreachable("Unhandled clause kind" ); |
524 | } |
525 | |
526 | bool ClauseHasOptionalParens(OpenACCDirectiveKind DirKind, |
527 | OpenACCClauseKind Kind) { |
528 | return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Optional; |
529 | } |
530 | |
531 | bool ClauseHasRequiredParens(OpenACCDirectiveKind DirKind, |
532 | OpenACCClauseKind Kind) { |
533 | return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Required; |
534 | } |
535 | |
536 | ExprResult ParseOpenACCConditionalExpr(Parser &P) { |
537 | // FIXME: It isn't clear if the spec saying 'condition' means the same as |
538 | // it does in an if/while/etc (See ParseCXXCondition), however as it was |
539 | // written with Fortran/C in mind, we're going to assume it just means an |
540 | // 'expression evaluating to boolean'. |
541 | return P.getActions().CorrectDelayedTyposInExpr(ER: P.ParseExpression()); |
542 | } |
543 | |
544 | // Skip until we see the end of pragma token, but don't consume it. This is us |
545 | // just giving up on the rest of the pragma so we can continue executing. We |
546 | // have to do this because 'SkipUntil' considers paren balancing, which isn't |
547 | // what we want. |
548 | void SkipUntilEndOfDirective(Parser &P) { |
549 | while (P.getCurToken().isNot(K: tok::annot_pragma_openacc_end)) |
550 | P.ConsumeAnyToken(); |
551 | } |
552 | |
553 | } // namespace |
554 | |
555 | // OpenACC 3.3, section 1.7: |
556 | // To simplify the specification and convey appropriate constraint information, |
557 | // a pqr-list is a comma-separated list of pdr items. The one exception is a |
558 | // clause-list, which is a list of one or more clauses optionally separated by |
559 | // commas. |
560 | void Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) { |
561 | bool FirstClause = true; |
562 | while (getCurToken().isNot(K: tok::annot_pragma_openacc_end)) { |
563 | // Comma is optional in a clause-list. |
564 | if (!FirstClause && getCurToken().is(K: tok::comma)) |
565 | ConsumeToken(); |
566 | FirstClause = false; |
567 | |
568 | // Recovering from a bad clause is really difficult, so we just give up on |
569 | // error. |
570 | if (ParseOpenACCClause(DirKind)) { |
571 | SkipUntilEndOfDirective(P&: *this); |
572 | return; |
573 | } |
574 | } |
575 | } |
576 | |
577 | ExprResult Parser::ParseOpenACCIntExpr() { |
578 | // FIXME: this is required to be an integer expression (or dependent), so we |
579 | // should ensure that is the case by passing this to SEMA here. |
580 | return getActions().CorrectDelayedTyposInExpr(ER: ParseAssignmentExpression()); |
581 | } |
582 | |
583 | bool Parser::ParseOpenACCClauseVarList(OpenACCClauseKind Kind) { |
584 | // FIXME: Future clauses will require 'special word' parsing, check for one, |
585 | // then parse it based on whether it is a clause that requires a 'special |
586 | // word'. |
587 | (void)Kind; |
588 | |
589 | // If the var parsing fails, skip until the end of the directive as this is |
590 | // an expression and gets messy if we try to continue otherwise. |
591 | if (ParseOpenACCVar()) |
592 | return true; |
593 | |
594 | while (!getCurToken().isOneOf(K1: tok::r_paren, K2: tok::annot_pragma_openacc_end)) { |
595 | ExpectAndConsume(ExpectedTok: tok::comma); |
596 | |
597 | // If the var parsing fails, skip until the end of the directive as this is |
598 | // an expression and gets messy if we try to continue otherwise. |
599 | if (ParseOpenACCVar()) |
600 | return true; |
601 | } |
602 | return false; |
603 | } |
604 | |
605 | /// OpenACC 3.3 Section 2.4: |
606 | /// The argument to the device_type clause is a comma-separated list of one or |
607 | /// more device architecture name identifiers, or an asterisk. |
608 | /// |
609 | /// The syntax of the device_type clause is |
610 | /// device_type( * ) |
611 | /// device_type( device-type-list ) |
612 | /// |
613 | /// The device_type clause may be abbreviated to dtype. |
614 | bool Parser::ParseOpenACCDeviceTypeList() { |
615 | |
616 | if (expectIdentifierOrKeyword(P&: *this)) { |
617 | SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end, |
618 | Flags: Parser::StopBeforeMatch); |
619 | return false; |
620 | } |
621 | ConsumeToken(); |
622 | |
623 | while (!getCurToken().isOneOf(K1: tok::r_paren, K2: tok::annot_pragma_openacc_end)) { |
624 | ExpectAndConsume(ExpectedTok: tok::comma); |
625 | |
626 | if (expectIdentifierOrKeyword(P&: *this)) { |
627 | SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end, |
628 | Flags: Parser::StopBeforeMatch); |
629 | return false; |
630 | } |
631 | ConsumeToken(); |
632 | } |
633 | return false; |
634 | } |
635 | |
636 | /// OpenACC 3.3 Section 2.9: |
637 | /// size-expr is one of: |
638 | // * |
639 | // int-expr |
640 | // Note that this is specified under 'gang-arg-list', but also applies to 'tile' |
641 | // via reference. |
642 | bool Parser::ParseOpenACCSizeExpr() { |
643 | // FIXME: Ensure these are constant expressions. |
644 | |
645 | // The size-expr ends up being ambiguous when only looking at the current |
646 | // token, as it could be a deref of a variable/expression. |
647 | if (getCurToken().is(K: tok::star) && |
648 | NextToken().isOneOf(K1: tok::comma, Ks: tok::r_paren, |
649 | Ks: tok::annot_pragma_openacc_end)) { |
650 | ConsumeToken(); |
651 | return false; |
652 | } |
653 | |
654 | return getActions() |
655 | .CorrectDelayedTyposInExpr(ER: ParseAssignmentExpression()) |
656 | .isInvalid(); |
657 | } |
658 | |
659 | bool Parser::ParseOpenACCSizeExprList() { |
660 | if (ParseOpenACCSizeExpr()) { |
661 | SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end, |
662 | Flags: Parser::StopBeforeMatch); |
663 | return false; |
664 | } |
665 | |
666 | while (!getCurToken().isOneOf(K1: tok::r_paren, K2: tok::annot_pragma_openacc_end)) { |
667 | ExpectAndConsume(ExpectedTok: tok::comma); |
668 | |
669 | if (ParseOpenACCSizeExpr()) { |
670 | SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end, |
671 | Flags: Parser::StopBeforeMatch); |
672 | return false; |
673 | } |
674 | } |
675 | return false; |
676 | } |
677 | |
678 | /// OpenACC 3.3 Section 2.9: |
679 | /// |
680 | /// where gang-arg is one of: |
681 | /// [num:]int-expr |
682 | /// dim:int-expr |
683 | /// static:size-expr |
684 | bool Parser::ParseOpenACCGangArg() { |
685 | |
686 | if (isOpenACCSpecialToken(Kind: OpenACCSpecialTokenKind::Static, Tok: getCurToken()) && |
687 | NextToken().is(K: tok::colon)) { |
688 | // 'static' just takes a size-expr, which is an int-expr or an asterisk. |
689 | ConsumeToken(); |
690 | ConsumeToken(); |
691 | return ParseOpenACCSizeExpr(); |
692 | } |
693 | |
694 | if (isOpenACCSpecialToken(Kind: OpenACCSpecialTokenKind::Dim, Tok: getCurToken()) && |
695 | NextToken().is(K: tok::colon)) { |
696 | ConsumeToken(); |
697 | ConsumeToken(); |
698 | return ParseOpenACCIntExpr().isInvalid(); |
699 | } |
700 | |
701 | if (isOpenACCSpecialToken(Kind: OpenACCSpecialTokenKind::Num, Tok: getCurToken()) && |
702 | NextToken().is(K: tok::colon)) { |
703 | ConsumeToken(); |
704 | ConsumeToken(); |
705 | // Fallthrough to the 'int-expr' handling for when 'num' is omitted. |
706 | } |
707 | // This is just the 'num' case where 'num' is optional. |
708 | return ParseOpenACCIntExpr().isInvalid(); |
709 | } |
710 | |
711 | bool Parser::ParseOpenACCGangArgList() { |
712 | if (ParseOpenACCGangArg()) { |
713 | SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end, |
714 | Flags: Parser::StopBeforeMatch); |
715 | return false; |
716 | } |
717 | |
718 | while (!getCurToken().isOneOf(K1: tok::r_paren, K2: tok::annot_pragma_openacc_end)) { |
719 | ExpectAndConsume(ExpectedTok: tok::comma); |
720 | |
721 | if (ParseOpenACCGangArg()) { |
722 | SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end, |
723 | Flags: Parser::StopBeforeMatch); |
724 | return false; |
725 | } |
726 | } |
727 | return false; |
728 | } |
729 | |
730 | // The OpenACC Clause List is a comma or space-delimited list of clauses (see |
731 | // the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't |
732 | // really have its owner grammar and each individual one has its own definition. |
733 | // However, they all are named with a single-identifier (or auto/default!) |
734 | // token, followed in some cases by either braces or parens. |
735 | bool Parser::ParseOpenACCClause(OpenACCDirectiveKind DirKind) { |
736 | // A number of clause names are actually keywords, so accept a keyword that |
737 | // can be converted to a name. |
738 | if (expectIdentifierOrKeyword(P&: *this)) |
739 | return true; |
740 | |
741 | OpenACCClauseKind Kind = getOpenACCClauseKind(Tok: getCurToken()); |
742 | |
743 | if (Kind == OpenACCClauseKind::Invalid) |
744 | return Diag(getCurToken(), diag::err_acc_invalid_clause) |
745 | << getCurToken().getIdentifierInfo(); |
746 | |
747 | // Consume the clause name. |
748 | ConsumeToken(); |
749 | |
750 | return ParseOpenACCClauseParams(DirKind, Kind); |
751 | } |
752 | |
753 | bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, |
754 | OpenACCClauseKind Kind) { |
755 | BalancedDelimiterTracker Parens(*this, tok::l_paren, |
756 | tok::annot_pragma_openacc_end); |
757 | |
758 | if (ClauseHasRequiredParens(DirKind, Kind)) { |
759 | if (Parens.expectAndConsume()) { |
760 | // We are missing a paren, so assume that the person just forgot the |
761 | // parameter. Return 'false' so we try to continue on and parse the next |
762 | // clause. |
763 | SkipUntil(T1: tok::comma, T2: tok::r_paren, T3: tok::annot_pragma_openacc_end, |
764 | Flags: Parser::StopBeforeMatch); |
765 | return false; |
766 | } |
767 | |
768 | switch (Kind) { |
769 | case OpenACCClauseKind::Default: { |
770 | Token DefKindTok = getCurToken(); |
771 | |
772 | if (expectIdentifierOrKeyword(P&: *this)) |
773 | break; |
774 | |
775 | ConsumeToken(); |
776 | |
777 | if (getOpenACCDefaultClauseKind(DefKindTok) == |
778 | OpenACCDefaultClauseKind::Invalid) |
779 | Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind); |
780 | |
781 | break; |
782 | } |
783 | case OpenACCClauseKind::If: { |
784 | ExprResult CondExpr = ParseOpenACCConditionalExpr(P&: *this); |
785 | // An invalid expression can be just about anything, so just give up on |
786 | // this clause list. |
787 | if (CondExpr.isInvalid()) { |
788 | Parens.skipToEnd(); |
789 | return false; |
790 | } |
791 | break; |
792 | } |
793 | case OpenACCClauseKind::CopyIn: |
794 | tryParseAndConsumeSpecialTokenKind( |
795 | P&: *this, Kind: OpenACCSpecialTokenKind::ReadOnly, DirOrClause: Kind); |
796 | if (ParseOpenACCClauseVarList(Kind)) { |
797 | Parens.skipToEnd(); |
798 | return false; |
799 | } |
800 | break; |
801 | case OpenACCClauseKind::Create: |
802 | case OpenACCClauseKind::CopyOut: |
803 | tryParseAndConsumeSpecialTokenKind(P&: *this, Kind: OpenACCSpecialTokenKind::Zero, |
804 | DirOrClause: Kind); |
805 | if (ParseOpenACCClauseVarList(Kind)) { |
806 | Parens.skipToEnd(); |
807 | return false; |
808 | } |
809 | break; |
810 | case OpenACCClauseKind::Reduction: |
811 | // If we're missing a clause-kind (or it is invalid), see if we can parse |
812 | // the var-list anyway. |
813 | ParseReductionOperator(P&: *this); |
814 | if (ParseOpenACCClauseVarList(Kind)) { |
815 | Parens.skipToEnd(); |
816 | return false; |
817 | } |
818 | break; |
819 | case OpenACCClauseKind::Self: |
820 | // The 'self' clause is a var-list instead of a 'condition' in the case of |
821 | // the 'update' clause, so we have to handle it here. U se an assert to |
822 | // make sure we get the right differentiator. |
823 | assert(DirKind == OpenACCDirectiveKind::Update); |
824 | LLVM_FALLTHROUGH; |
825 | case OpenACCClauseKind::Attach: |
826 | case OpenACCClauseKind::Copy: |
827 | case OpenACCClauseKind::Delete: |
828 | case OpenACCClauseKind::Detach: |
829 | case OpenACCClauseKind::Device: |
830 | case OpenACCClauseKind::DeviceResident: |
831 | case OpenACCClauseKind::DevicePtr: |
832 | case OpenACCClauseKind::FirstPrivate: |
833 | case OpenACCClauseKind::Host: |
834 | case OpenACCClauseKind::Link: |
835 | case OpenACCClauseKind::NoCreate: |
836 | case OpenACCClauseKind::Present: |
837 | case OpenACCClauseKind::Private: |
838 | case OpenACCClauseKind::UseDevice: |
839 | if (ParseOpenACCClauseVarList(Kind)) { |
840 | Parens.skipToEnd(); |
841 | return false; |
842 | } |
843 | break; |
844 | case OpenACCClauseKind::Collapse: { |
845 | tryParseAndConsumeSpecialTokenKind(P&: *this, Kind: OpenACCSpecialTokenKind::Force, |
846 | DirOrClause: Kind); |
847 | ExprResult NumLoops = |
848 | getActions().CorrectDelayedTyposInExpr(ER: ParseConstantExpression()); |
849 | if (NumLoops.isInvalid()) { |
850 | Parens.skipToEnd(); |
851 | return false; |
852 | } |
853 | break; |
854 | } |
855 | case OpenACCClauseKind::Bind: { |
856 | ExprResult BindArg = ParseOpenACCBindClauseArgument(); |
857 | if (BindArg.isInvalid()) { |
858 | Parens.skipToEnd(); |
859 | return false; |
860 | } |
861 | break; |
862 | } |
863 | case OpenACCClauseKind::NumGangs: |
864 | case OpenACCClauseKind::NumWorkers: |
865 | case OpenACCClauseKind::DeviceNum: |
866 | case OpenACCClauseKind::DefaultAsync: |
867 | case OpenACCClauseKind::VectorLength: { |
868 | ExprResult IntExpr = ParseOpenACCIntExpr(); |
869 | if (IntExpr.isInvalid()) { |
870 | Parens.skipToEnd(); |
871 | return false; |
872 | } |
873 | break; |
874 | } |
875 | case OpenACCClauseKind::DType: |
876 | case OpenACCClauseKind::DeviceType: |
877 | if (getCurToken().is(K: tok::star)) { |
878 | // FIXME: We want to mark that this is an 'everything else' type of |
879 | // device_type in Sema. |
880 | ConsumeToken(); |
881 | } else if (ParseOpenACCDeviceTypeList()) { |
882 | Parens.skipToEnd(); |
883 | return false; |
884 | } |
885 | break; |
886 | case OpenACCClauseKind::Tile: |
887 | if (ParseOpenACCSizeExprList()) { |
888 | Parens.skipToEnd(); |
889 | return false; |
890 | } |
891 | break; |
892 | default: |
893 | llvm_unreachable("Not a required parens type?" ); |
894 | } |
895 | |
896 | return Parens.consumeClose(); |
897 | } else if (ClauseHasOptionalParens(DirKind, Kind)) { |
898 | if (!Parens.consumeOpen()) { |
899 | switch (Kind) { |
900 | case OpenACCClauseKind::Self: { |
901 | assert(DirKind != OpenACCDirectiveKind::Update); |
902 | ExprResult CondExpr = ParseOpenACCConditionalExpr(P&: *this); |
903 | // An invalid expression can be just about anything, so just give up on |
904 | // this clause list. |
905 | if (CondExpr.isInvalid()) { |
906 | Parens.skipToEnd(); |
907 | return false; |
908 | } |
909 | break; |
910 | } |
911 | case OpenACCClauseKind::Vector: |
912 | case OpenACCClauseKind::Worker: { |
913 | tryParseAndConsumeSpecialTokenKind(P&: *this, |
914 | Kind: Kind == OpenACCClauseKind::Vector |
915 | ? OpenACCSpecialTokenKind::Length |
916 | : OpenACCSpecialTokenKind::Num, |
917 | DirOrClause: Kind); |
918 | ExprResult IntExpr = ParseOpenACCIntExpr(); |
919 | if (IntExpr.isInvalid()) { |
920 | Parens.skipToEnd(); |
921 | return false; |
922 | } |
923 | break; |
924 | } |
925 | case OpenACCClauseKind::Async: { |
926 | ExprResult AsyncArg = ParseOpenACCAsyncArgument(); |
927 | if (AsyncArg.isInvalid()) { |
928 | Parens.skipToEnd(); |
929 | return false; |
930 | } |
931 | break; |
932 | } |
933 | case OpenACCClauseKind::Gang: |
934 | if (ParseOpenACCGangArgList()) { |
935 | Parens.skipToEnd(); |
936 | return false; |
937 | } |
938 | break; |
939 | case OpenACCClauseKind::Wait: |
940 | if (ParseOpenACCWaitArgument()) { |
941 | Parens.skipToEnd(); |
942 | return false; |
943 | } |
944 | break; |
945 | default: |
946 | llvm_unreachable("Not an optional parens type?" ); |
947 | } |
948 | Parens.consumeClose(); |
949 | } |
950 | } |
951 | return false; |
952 | } |
953 | |
954 | /// OpenACC 3.3 section 2.16: |
955 | /// In this section and throughout the specification, the term async-argument |
956 | /// means a nonnegative scalar integer expression (int for C or C++, integer for |
957 | /// Fortran), or one of the special values acc_async_noval or acc_async_sync, as |
958 | /// defined in the C header file and the Fortran openacc module. The special |
959 | /// values are negative values, so as not to conflict with a user-specified |
960 | /// nonnegative async-argument. |
961 | ExprResult Parser::ParseOpenACCAsyncArgument() { |
962 | return getActions().CorrectDelayedTyposInExpr(ER: ParseAssignmentExpression()); |
963 | } |
964 | |
965 | /// OpenACC 3.3, section 2.16: |
966 | /// In this section and throughout the specification, the term wait-argument |
967 | /// means: |
968 | /// [ devnum : int-expr : ] [ queues : ] async-argument-list |
969 | bool Parser::ParseOpenACCWaitArgument() { |
970 | // [devnum : int-expr : ] |
971 | if (isOpenACCSpecialToken(Kind: OpenACCSpecialTokenKind::DevNum, Tok) && |
972 | NextToken().is(K: tok::colon)) { |
973 | // Consume devnum. |
974 | ConsumeToken(); |
975 | // Consume colon. |
976 | ConsumeToken(); |
977 | |
978 | ExprResult IntExpr = ParseOpenACCIntExpr(); |
979 | if (IntExpr.isInvalid()) |
980 | return true; |
981 | |
982 | if (ExpectAndConsume(ExpectedTok: tok::colon)) |
983 | return true; |
984 | } |
985 | |
986 | // [ queues : ] |
987 | if (isOpenACCSpecialToken(Kind: OpenACCSpecialTokenKind::Queues, Tok) && |
988 | NextToken().is(K: tok::colon)) { |
989 | // Consume queues. |
990 | ConsumeToken(); |
991 | // Consume colon. |
992 | ConsumeToken(); |
993 | } |
994 | |
995 | // OpenACC 3.3, section 2.16: |
996 | // the term 'async-argument' means a nonnegative scalar integer expression, or |
997 | // one of the special values 'acc_async_noval' or 'acc_async_sync', as defined |
998 | // in the C header file and the Fortran opacc module. |
999 | bool FirstArg = true; |
1000 | while (!getCurToken().isOneOf(K1: tok::r_paren, K2: tok::annot_pragma_openacc_end)) { |
1001 | if (!FirstArg) { |
1002 | if (ExpectAndConsume(ExpectedTok: tok::comma)) |
1003 | return true; |
1004 | } |
1005 | FirstArg = false; |
1006 | |
1007 | ExprResult CurArg = ParseOpenACCAsyncArgument(); |
1008 | |
1009 | if (CurArg.isInvalid()) |
1010 | return true; |
1011 | } |
1012 | |
1013 | return false; |
1014 | } |
1015 | |
1016 | ExprResult Parser::ParseOpenACCIDExpression() { |
1017 | ExprResult Res; |
1018 | if (getLangOpts().CPlusPlus) { |
1019 | Res = ParseCXXIdExpression(/*isAddressOfOperand=*/true); |
1020 | } else { |
1021 | // There isn't anything quite the same as ParseCXXIdExpression for C, so we |
1022 | // need to get the identifier, then call into Sema ourselves. |
1023 | |
1024 | if (Tok.isNot(K: tok::identifier)) { |
1025 | Diag(Tok, diag::err_expected) << tok::identifier; |
1026 | return ExprError(); |
1027 | } |
1028 | |
1029 | Token FuncName = getCurToken(); |
1030 | UnqualifiedId Name; |
1031 | CXXScopeSpec ScopeSpec; |
1032 | SourceLocation TemplateKWLoc; |
1033 | Name.setIdentifier(Id: FuncName.getIdentifierInfo(), IdLoc: ConsumeToken()); |
1034 | |
1035 | // Ensure this is a valid identifier. We don't accept causing implicit |
1036 | // function declarations per the spec, so always claim to not have trailing |
1037 | // L Paren. |
1038 | Res = Actions.ActOnIdExpression(S: getCurScope(), SS&: ScopeSpec, TemplateKWLoc, |
1039 | Id&: Name, /*HasTrailingLParen=*/false, |
1040 | /*isAddressOfOperand=*/IsAddressOfOperand: false); |
1041 | } |
1042 | |
1043 | return getActions().CorrectDelayedTyposInExpr(ER: Res); |
1044 | } |
1045 | |
1046 | ExprResult Parser::ParseOpenACCBindClauseArgument() { |
1047 | // OpenACC 3.3 section 2.15: |
1048 | // The bind clause specifies the name to use when calling the procedure on a |
1049 | // device other than the host. If the name is specified as an identifier, it |
1050 | // is called as if that name were specified in the language being compiled. If |
1051 | // the name is specified as a string, the string is used for the procedure |
1052 | // name unmodified. |
1053 | if (getCurToken().is(K: tok::r_paren)) { |
1054 | Diag(getCurToken(), diag::err_acc_incorrect_bind_arg); |
1055 | return ExprError(); |
1056 | } |
1057 | |
1058 | if (tok::isStringLiteral(K: getCurToken().getKind())) |
1059 | return getActions().CorrectDelayedTyposInExpr(ER: ParseStringLiteralExpression( |
1060 | /*AllowUserDefinedLiteral=*/false, /*Unevaluated=*/true)); |
1061 | |
1062 | return ParseOpenACCIDExpression(); |
1063 | } |
1064 | |
1065 | /// OpenACC 3.3, section 1.6: |
1066 | /// In this spec, a 'var' (in italics) is one of the following: |
1067 | /// - a variable name (a scalar, array, or compisite variable name) |
1068 | /// - a subarray specification with subscript ranges |
1069 | /// - an array element |
1070 | /// - a member of a composite variable |
1071 | /// - a common block name between slashes (fortran only) |
1072 | bool Parser::ParseOpenACCVar() { |
1073 | OpenACCArraySectionRAII ArraySections(*this); |
1074 | ExprResult Res = |
1075 | getActions().CorrectDelayedTyposInExpr(ER: ParseAssignmentExpression()); |
1076 | return Res.isInvalid(); |
1077 | } |
1078 | |
1079 | /// OpenACC 3.3, section 2.10: |
1080 | /// In C and C++, the syntax of the cache directive is: |
1081 | /// |
1082 | /// #pragma acc cache ([readonly:]var-list) new-line |
1083 | void Parser::ParseOpenACCCacheVarList() { |
1084 | // If this is the end of the line, just return 'false' and count on the close |
1085 | // paren diagnostic to catch the issue. |
1086 | if (getCurToken().isAnnotation()) |
1087 | return; |
1088 | |
1089 | // The VarList is an optional `readonly:` followed by a list of a variable |
1090 | // specifications. Consume something that looks like a 'tag', and diagnose if |
1091 | // it isn't 'readonly'. |
1092 | if (tryParseAndConsumeSpecialTokenKind(P&: *this, |
1093 | Kind: OpenACCSpecialTokenKind::ReadOnly, |
1094 | DirOrClause: OpenACCDirectiveKind::Cache)) { |
1095 | // FIXME: Record that this is a 'readonly' so that we can use that during |
1096 | // Sema/AST generation. |
1097 | } |
1098 | |
1099 | bool FirstArray = true; |
1100 | while (!getCurToken().isOneOf(K1: tok::r_paren, K2: tok::annot_pragma_openacc_end)) { |
1101 | if (!FirstArray) |
1102 | ExpectAndConsume(ExpectedTok: tok::comma); |
1103 | FirstArray = false; |
1104 | |
1105 | // OpenACC 3.3, section 2.10: |
1106 | // A 'var' in a cache directive must be a single array element or a simple |
1107 | // subarray. In C and C++, a simple subarray is an array name followed by |
1108 | // an extended array range specification in brackets, with a start and |
1109 | // length such as: |
1110 | // |
1111 | // arr[lower:length] |
1112 | // |
1113 | if (ParseOpenACCVar()) |
1114 | SkipUntil(T1: tok::r_paren, T2: tok::annot_pragma_openacc_end, T3: tok::comma, |
1115 | Flags: StopBeforeMatch); |
1116 | } |
1117 | } |
1118 | |
1119 | void Parser::ParseOpenACCDirective() { |
1120 | OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(P&: *this); |
1121 | |
1122 | // Once we've parsed the construct/directive name, some have additional |
1123 | // specifiers that need to be taken care of. Atomic has an 'atomic-clause' |
1124 | // that needs to be parsed. |
1125 | if (DirKind == OpenACCDirectiveKind::Atomic) |
1126 | ParseOpenACCAtomicKind(P&: *this); |
1127 | |
1128 | // We've successfully parsed the construct/directive name, however a few of |
1129 | // the constructs have optional parens that contain further details. |
1130 | BalancedDelimiterTracker T(*this, tok::l_paren, |
1131 | tok::annot_pragma_openacc_end); |
1132 | |
1133 | if (!T.consumeOpen()) { |
1134 | switch (DirKind) { |
1135 | default: |
1136 | Diag(T.getOpenLocation(), diag::err_acc_invalid_open_paren); |
1137 | T.skipToEnd(); |
1138 | break; |
1139 | case OpenACCDirectiveKind::Routine: { |
1140 | // Routine has an optional paren-wrapped name of a function in the local |
1141 | // scope. We parse the name, emitting any diagnostics |
1142 | ExprResult RoutineName = ParseOpenACCIDExpression(); |
1143 | // If the routine name is invalid, just skip until the closing paren to |
1144 | // recover more gracefully. |
1145 | if (RoutineName.isInvalid()) |
1146 | T.skipToEnd(); |
1147 | else |
1148 | T.consumeClose(); |
1149 | break; |
1150 | } |
1151 | case OpenACCDirectiveKind::Cache: |
1152 | ParseOpenACCCacheVarList(); |
1153 | // The ParseOpenACCCacheVarList function manages to recover from failures, |
1154 | // so we can always consume the close. |
1155 | T.consumeClose(); |
1156 | break; |
1157 | case OpenACCDirectiveKind::Wait: |
1158 | // OpenACC has an optional paren-wrapped 'wait-argument'. |
1159 | if (ParseOpenACCWaitArgument()) |
1160 | T.skipToEnd(); |
1161 | else |
1162 | T.consumeClose(); |
1163 | break; |
1164 | } |
1165 | } else if (DirKind == OpenACCDirectiveKind::Cache) { |
1166 | // Cache's paren var-list is required, so error here if it isn't provided. |
1167 | // We know that the consumeOpen above left the first non-paren here, so |
1168 | // diagnose, then continue as if it was completely omitted. |
1169 | Diag(Tok, diag::err_expected) << tok::l_paren; |
1170 | } |
1171 | |
1172 | // Parses the list of clauses, if present. |
1173 | ParseOpenACCClauseList(DirKind); |
1174 | |
1175 | Diag(getCurToken(), diag::warn_pragma_acc_unimplemented); |
1176 | assert(Tok.is(tok::annot_pragma_openacc_end) && |
1177 | "Didn't parse all OpenACC Clauses" ); |
1178 | ConsumeAnnotationToken(); |
1179 | } |
1180 | |
1181 | // Parse OpenACC directive on a declaration. |
1182 | Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() { |
1183 | assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token" ); |
1184 | |
1185 | ParsingOpenACCDirectiveRAII DirScope(*this); |
1186 | ConsumeAnnotationToken(); |
1187 | |
1188 | ParseOpenACCDirective(); |
1189 | |
1190 | return nullptr; |
1191 | } |
1192 | |
1193 | // Parse OpenACC Directive on a Statement. |
1194 | StmtResult Parser::ParseOpenACCDirectiveStmt() { |
1195 | assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token" ); |
1196 | |
1197 | ParsingOpenACCDirectiveRAII DirScope(*this); |
1198 | ConsumeAnnotationToken(); |
1199 | |
1200 | ParseOpenACCDirective(); |
1201 | |
1202 | return StmtEmpty(); |
1203 | } |
1204 | |