xref: /freebsd/contrib/llvm-project/clang/include/clang/Sema/SemaOpenACC.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===----- SemaOpenACC.h - Semantic Analysis for OpenACC constructs -------===//
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 /// \file
9 /// This file declares semantic analysis for OpenACC constructs and
10 /// clauses.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_SEMA_SEMAOPENACC_H
15 #define LLVM_CLANG_SEMA_SEMAOPENACC_H
16 
17 #include "clang/AST/DeclGroup.h"
18 #include "clang/AST/StmtOpenACC.h"
19 #include "clang/Basic/OpenACCKinds.h"
20 #include "clang/Basic/SourceLocation.h"
21 #include "clang/Sema/Ownership.h"
22 #include "clang/Sema/SemaBase.h"
23 #include <variant>
24 
25 namespace clang {
26 class OpenACCClause;
27 
28 class SemaOpenACC : public SemaBase {
29 private:
30   /// A collection of loop constructs in the compute construct scope that
31   /// haven't had their 'parent' compute construct set yet. Entires will only be
32   /// made to this list in the case where we know the loop isn't an orphan.
33   llvm::SmallVector<OpenACCLoopConstruct *> ParentlessLoopConstructs;
34   /// Whether we are inside of a compute construct, and should add loops to the
35   /// above collection.
36   bool InsideComputeConstruct = false;
37 
38 public:
39   // Redeclaration of the version in OpenACCClause.h.
40   using DeviceTypeArgument = std::pair<IdentifierInfo *, SourceLocation>;
41 
42   /// A type to represent all the data for an OpenACC Clause that has been
43   /// parsed, but not yet created/semantically analyzed. This is effectively a
44   /// discriminated union on the 'Clause Kind', with all of the individual
45   /// clause details stored in a std::variant.
46   class OpenACCParsedClause {
47     OpenACCDirectiveKind DirKind;
48     OpenACCClauseKind ClauseKind;
49     SourceRange ClauseRange;
50     SourceLocation LParenLoc;
51 
52     struct DefaultDetails {
53       OpenACCDefaultClauseKind DefaultClauseKind;
54     };
55 
56     struct ConditionDetails {
57       Expr *ConditionExpr;
58     };
59 
60     struct IntExprDetails {
61       SmallVector<Expr *> IntExprs;
62     };
63 
64     struct VarListDetails {
65       SmallVector<Expr *> VarList;
66       bool IsReadOnly;
67       bool IsZero;
68     };
69 
70     struct WaitDetails {
71       Expr *DevNumExpr;
72       SourceLocation QueuesLoc;
73       SmallVector<Expr *> QueueIdExprs;
74     };
75 
76     struct DeviceTypeDetails {
77       SmallVector<DeviceTypeArgument> Archs;
78     };
79     struct ReductionDetails {
80       OpenACCReductionOperator Op;
81       SmallVector<Expr *> VarList;
82     };
83 
84     std::variant<std::monostate, DefaultDetails, ConditionDetails,
85                  IntExprDetails, VarListDetails, WaitDetails, DeviceTypeDetails,
86                  ReductionDetails>
87         Details = std::monostate{};
88 
89   public:
OpenACCParsedClause(OpenACCDirectiveKind DirKind,OpenACCClauseKind ClauseKind,SourceLocation BeginLoc)90     OpenACCParsedClause(OpenACCDirectiveKind DirKind,
91                         OpenACCClauseKind ClauseKind, SourceLocation BeginLoc)
92         : DirKind(DirKind), ClauseKind(ClauseKind), ClauseRange(BeginLoc, {}) {}
93 
getDirectiveKind()94     OpenACCDirectiveKind getDirectiveKind() const { return DirKind; }
95 
getClauseKind()96     OpenACCClauseKind getClauseKind() const { return ClauseKind; }
97 
getBeginLoc()98     SourceLocation getBeginLoc() const { return ClauseRange.getBegin(); }
99 
getLParenLoc()100     SourceLocation getLParenLoc() const { return LParenLoc; }
101 
getEndLoc()102     SourceLocation getEndLoc() const { return ClauseRange.getEnd(); }
103 
getDefaultClauseKind()104     OpenACCDefaultClauseKind getDefaultClauseKind() const {
105       assert(ClauseKind == OpenACCClauseKind::Default &&
106              "Parsed clause is not a default clause");
107       return std::get<DefaultDetails>(Details).DefaultClauseKind;
108     }
109 
getConditionExpr()110     const Expr *getConditionExpr() const {
111       return const_cast<OpenACCParsedClause *>(this)->getConditionExpr();
112     }
113 
getConditionExpr()114     Expr *getConditionExpr() {
115       assert((ClauseKind == OpenACCClauseKind::If ||
116               (ClauseKind == OpenACCClauseKind::Self &&
117                DirKind != OpenACCDirectiveKind::Update)) &&
118              "Parsed clause kind does not have a condition expr");
119 
120       // 'self' has an optional ConditionExpr, so be tolerant of that. This will
121       // assert in variant otherwise.
122       if (ClauseKind == OpenACCClauseKind::Self &&
123           std::holds_alternative<std::monostate>(Details))
124         return nullptr;
125 
126       return std::get<ConditionDetails>(Details).ConditionExpr;
127     }
128 
getNumIntExprs()129     unsigned getNumIntExprs() const {
130       assert((ClauseKind == OpenACCClauseKind::NumGangs ||
131               ClauseKind == OpenACCClauseKind::NumWorkers ||
132               ClauseKind == OpenACCClauseKind::Async ||
133               ClauseKind == OpenACCClauseKind::VectorLength) &&
134              "Parsed clause kind does not have a int exprs");
135 
136       // 'async' and 'wait' have an optional IntExpr, so be tolerant of that.
137       if ((ClauseKind == OpenACCClauseKind::Async ||
138            ClauseKind == OpenACCClauseKind::Wait) &&
139           std::holds_alternative<std::monostate>(Details))
140         return 0;
141       return std::get<IntExprDetails>(Details).IntExprs.size();
142     }
143 
getQueuesLoc()144     SourceLocation getQueuesLoc() const {
145       assert(ClauseKind == OpenACCClauseKind::Wait &&
146              "Parsed clause kind does not have a queues location");
147 
148       if (std::holds_alternative<std::monostate>(Details))
149         return SourceLocation{};
150 
151       return std::get<WaitDetails>(Details).QueuesLoc;
152     }
153 
getDevNumExpr()154     Expr *getDevNumExpr() const {
155       assert(ClauseKind == OpenACCClauseKind::Wait &&
156              "Parsed clause kind does not have a device number expr");
157 
158       if (std::holds_alternative<std::monostate>(Details))
159         return nullptr;
160 
161       return std::get<WaitDetails>(Details).DevNumExpr;
162     }
163 
getQueueIdExprs()164     ArrayRef<Expr *> getQueueIdExprs() const {
165       assert(ClauseKind == OpenACCClauseKind::Wait &&
166              "Parsed clause kind does not have a queue id expr list");
167 
168       if (std::holds_alternative<std::monostate>(Details))
169         return ArrayRef<Expr *>{std::nullopt};
170 
171       return std::get<WaitDetails>(Details).QueueIdExprs;
172     }
173 
getIntExprs()174     ArrayRef<Expr *> getIntExprs() {
175       assert((ClauseKind == OpenACCClauseKind::NumGangs ||
176               ClauseKind == OpenACCClauseKind::NumWorkers ||
177               ClauseKind == OpenACCClauseKind::Async ||
178               ClauseKind == OpenACCClauseKind::VectorLength) &&
179              "Parsed clause kind does not have a int exprs");
180 
181       return std::get<IntExprDetails>(Details).IntExprs;
182     }
183 
getIntExprs()184     ArrayRef<Expr *> getIntExprs() const {
185       return const_cast<OpenACCParsedClause *>(this)->getIntExprs();
186     }
187 
getReductionOp()188     OpenACCReductionOperator getReductionOp() const {
189       return std::get<ReductionDetails>(Details).Op;
190     }
191 
getVarList()192     ArrayRef<Expr *> getVarList() {
193       assert((ClauseKind == OpenACCClauseKind::Private ||
194               ClauseKind == OpenACCClauseKind::NoCreate ||
195               ClauseKind == OpenACCClauseKind::Present ||
196               ClauseKind == OpenACCClauseKind::Copy ||
197               ClauseKind == OpenACCClauseKind::PCopy ||
198               ClauseKind == OpenACCClauseKind::PresentOrCopy ||
199               ClauseKind == OpenACCClauseKind::CopyIn ||
200               ClauseKind == OpenACCClauseKind::PCopyIn ||
201               ClauseKind == OpenACCClauseKind::PresentOrCopyIn ||
202               ClauseKind == OpenACCClauseKind::CopyOut ||
203               ClauseKind == OpenACCClauseKind::PCopyOut ||
204               ClauseKind == OpenACCClauseKind::PresentOrCopyOut ||
205               ClauseKind == OpenACCClauseKind::Create ||
206               ClauseKind == OpenACCClauseKind::PCreate ||
207               ClauseKind == OpenACCClauseKind::PresentOrCreate ||
208               ClauseKind == OpenACCClauseKind::Attach ||
209               ClauseKind == OpenACCClauseKind::DevicePtr ||
210               ClauseKind == OpenACCClauseKind::Reduction ||
211               ClauseKind == OpenACCClauseKind::FirstPrivate) &&
212              "Parsed clause kind does not have a var-list");
213 
214       if (ClauseKind == OpenACCClauseKind::Reduction)
215         return std::get<ReductionDetails>(Details).VarList;
216 
217       return std::get<VarListDetails>(Details).VarList;
218     }
219 
getVarList()220     ArrayRef<Expr *> getVarList() const {
221       return const_cast<OpenACCParsedClause *>(this)->getVarList();
222     }
223 
isReadOnly()224     bool isReadOnly() const {
225       assert((ClauseKind == OpenACCClauseKind::CopyIn ||
226               ClauseKind == OpenACCClauseKind::PCopyIn ||
227               ClauseKind == OpenACCClauseKind::PresentOrCopyIn) &&
228              "Only copyin accepts 'readonly:' tag");
229       return std::get<VarListDetails>(Details).IsReadOnly;
230     }
231 
isZero()232     bool isZero() const {
233       assert((ClauseKind == OpenACCClauseKind::CopyOut ||
234               ClauseKind == OpenACCClauseKind::PCopyOut ||
235               ClauseKind == OpenACCClauseKind::PresentOrCopyOut ||
236               ClauseKind == OpenACCClauseKind::Create ||
237               ClauseKind == OpenACCClauseKind::PCreate ||
238               ClauseKind == OpenACCClauseKind::PresentOrCreate) &&
239              "Only copyout/create accepts 'zero' tag");
240       return std::get<VarListDetails>(Details).IsZero;
241     }
242 
getDeviceTypeArchitectures()243     ArrayRef<DeviceTypeArgument> getDeviceTypeArchitectures() const {
244       assert((ClauseKind == OpenACCClauseKind::DeviceType ||
245               ClauseKind == OpenACCClauseKind::DType) &&
246              "Only 'device_type'/'dtype' has a device-type-arg list");
247       return std::get<DeviceTypeDetails>(Details).Archs;
248     }
249 
setLParenLoc(SourceLocation EndLoc)250     void setLParenLoc(SourceLocation EndLoc) { LParenLoc = EndLoc; }
setEndLoc(SourceLocation EndLoc)251     void setEndLoc(SourceLocation EndLoc) { ClauseRange.setEnd(EndLoc); }
252 
setDefaultDetails(OpenACCDefaultClauseKind DefKind)253     void setDefaultDetails(OpenACCDefaultClauseKind DefKind) {
254       assert(ClauseKind == OpenACCClauseKind::Default &&
255              "Parsed clause is not a default clause");
256       Details = DefaultDetails{DefKind};
257     }
258 
setConditionDetails(Expr * ConditionExpr)259     void setConditionDetails(Expr *ConditionExpr) {
260       assert((ClauseKind == OpenACCClauseKind::If ||
261               (ClauseKind == OpenACCClauseKind::Self &&
262                DirKind != OpenACCDirectiveKind::Update)) &&
263              "Parsed clause kind does not have a condition expr");
264       // In C++ we can count on this being a 'bool', but in C this gets left as
265       // some sort of scalar that codegen will have to take care of converting.
266       assert((!ConditionExpr || ConditionExpr->isInstantiationDependent() ||
267               ConditionExpr->getType()->isScalarType()) &&
268              "Condition expression type not scalar/dependent");
269 
270       Details = ConditionDetails{ConditionExpr};
271     }
272 
setIntExprDetails(ArrayRef<Expr * > IntExprs)273     void setIntExprDetails(ArrayRef<Expr *> IntExprs) {
274       assert((ClauseKind == OpenACCClauseKind::NumGangs ||
275               ClauseKind == OpenACCClauseKind::NumWorkers ||
276               ClauseKind == OpenACCClauseKind::Async ||
277               ClauseKind == OpenACCClauseKind::VectorLength) &&
278              "Parsed clause kind does not have a int exprs");
279       Details = IntExprDetails{{IntExprs.begin(), IntExprs.end()}};
280     }
setIntExprDetails(llvm::SmallVector<Expr * > && IntExprs)281     void setIntExprDetails(llvm::SmallVector<Expr *> &&IntExprs) {
282       assert((ClauseKind == OpenACCClauseKind::NumGangs ||
283               ClauseKind == OpenACCClauseKind::NumWorkers ||
284               ClauseKind == OpenACCClauseKind::Async ||
285               ClauseKind == OpenACCClauseKind::VectorLength) &&
286              "Parsed clause kind does not have a int exprs");
287       Details = IntExprDetails{std::move(IntExprs)};
288     }
289 
setVarListDetails(ArrayRef<Expr * > VarList,bool IsReadOnly,bool IsZero)290     void setVarListDetails(ArrayRef<Expr *> VarList, bool IsReadOnly,
291                            bool IsZero) {
292       assert((ClauseKind == OpenACCClauseKind::Private ||
293               ClauseKind == OpenACCClauseKind::NoCreate ||
294               ClauseKind == OpenACCClauseKind::Present ||
295               ClauseKind == OpenACCClauseKind::Copy ||
296               ClauseKind == OpenACCClauseKind::PCopy ||
297               ClauseKind == OpenACCClauseKind::PresentOrCopy ||
298               ClauseKind == OpenACCClauseKind::CopyIn ||
299               ClauseKind == OpenACCClauseKind::PCopyIn ||
300               ClauseKind == OpenACCClauseKind::PresentOrCopyIn ||
301               ClauseKind == OpenACCClauseKind::CopyOut ||
302               ClauseKind == OpenACCClauseKind::PCopyOut ||
303               ClauseKind == OpenACCClauseKind::PresentOrCopyOut ||
304               ClauseKind == OpenACCClauseKind::Create ||
305               ClauseKind == OpenACCClauseKind::PCreate ||
306               ClauseKind == OpenACCClauseKind::PresentOrCreate ||
307               ClauseKind == OpenACCClauseKind::Attach ||
308               ClauseKind == OpenACCClauseKind::DevicePtr ||
309               ClauseKind == OpenACCClauseKind::FirstPrivate) &&
310              "Parsed clause kind does not have a var-list");
311       assert((!IsReadOnly || ClauseKind == OpenACCClauseKind::CopyIn ||
312               ClauseKind == OpenACCClauseKind::PCopyIn ||
313               ClauseKind == OpenACCClauseKind::PresentOrCopyIn) &&
314              "readonly: tag only valid on copyin");
315       assert((!IsZero || ClauseKind == OpenACCClauseKind::CopyOut ||
316               ClauseKind == OpenACCClauseKind::PCopyOut ||
317               ClauseKind == OpenACCClauseKind::PresentOrCopyOut ||
318               ClauseKind == OpenACCClauseKind::Create ||
319               ClauseKind == OpenACCClauseKind::PCreate ||
320               ClauseKind == OpenACCClauseKind::PresentOrCreate) &&
321              "zero: tag only valid on copyout/create");
322       Details =
323           VarListDetails{{VarList.begin(), VarList.end()}, IsReadOnly, IsZero};
324     }
325 
setVarListDetails(llvm::SmallVector<Expr * > && VarList,bool IsReadOnly,bool IsZero)326     void setVarListDetails(llvm::SmallVector<Expr *> &&VarList, bool IsReadOnly,
327                            bool IsZero) {
328       assert((ClauseKind == OpenACCClauseKind::Private ||
329               ClauseKind == OpenACCClauseKind::NoCreate ||
330               ClauseKind == OpenACCClauseKind::Present ||
331               ClauseKind == OpenACCClauseKind::Copy ||
332               ClauseKind == OpenACCClauseKind::PCopy ||
333               ClauseKind == OpenACCClauseKind::PresentOrCopy ||
334               ClauseKind == OpenACCClauseKind::CopyIn ||
335               ClauseKind == OpenACCClauseKind::PCopyIn ||
336               ClauseKind == OpenACCClauseKind::PresentOrCopyIn ||
337               ClauseKind == OpenACCClauseKind::CopyOut ||
338               ClauseKind == OpenACCClauseKind::PCopyOut ||
339               ClauseKind == OpenACCClauseKind::PresentOrCopyOut ||
340               ClauseKind == OpenACCClauseKind::Create ||
341               ClauseKind == OpenACCClauseKind::PCreate ||
342               ClauseKind == OpenACCClauseKind::PresentOrCreate ||
343               ClauseKind == OpenACCClauseKind::Attach ||
344               ClauseKind == OpenACCClauseKind::DevicePtr ||
345               ClauseKind == OpenACCClauseKind::FirstPrivate) &&
346              "Parsed clause kind does not have a var-list");
347       assert((!IsReadOnly || ClauseKind == OpenACCClauseKind::CopyIn ||
348               ClauseKind == OpenACCClauseKind::PCopyIn ||
349               ClauseKind == OpenACCClauseKind::PresentOrCopyIn) &&
350              "readonly: tag only valid on copyin");
351       assert((!IsZero || ClauseKind == OpenACCClauseKind::CopyOut ||
352               ClauseKind == OpenACCClauseKind::PCopyOut ||
353               ClauseKind == OpenACCClauseKind::PresentOrCopyOut ||
354               ClauseKind == OpenACCClauseKind::Create ||
355               ClauseKind == OpenACCClauseKind::PCreate ||
356               ClauseKind == OpenACCClauseKind::PresentOrCreate) &&
357              "zero: tag only valid on copyout/create");
358       Details = VarListDetails{std::move(VarList), IsReadOnly, IsZero};
359     }
360 
setReductionDetails(OpenACCReductionOperator Op,llvm::SmallVector<Expr * > && VarList)361     void setReductionDetails(OpenACCReductionOperator Op,
362                              llvm::SmallVector<Expr *> &&VarList) {
363       assert(ClauseKind == OpenACCClauseKind::Reduction &&
364              "reduction details only valid on reduction");
365       Details = ReductionDetails{Op, std::move(VarList)};
366     }
367 
setWaitDetails(Expr * DevNum,SourceLocation QueuesLoc,llvm::SmallVector<Expr * > && IntExprs)368     void setWaitDetails(Expr *DevNum, SourceLocation QueuesLoc,
369                         llvm::SmallVector<Expr *> &&IntExprs) {
370       assert(ClauseKind == OpenACCClauseKind::Wait &&
371              "Parsed clause kind does not have a wait-details");
372       Details = WaitDetails{DevNum, QueuesLoc, std::move(IntExprs)};
373     }
374 
setDeviceTypeDetails(llvm::SmallVector<DeviceTypeArgument> && Archs)375     void setDeviceTypeDetails(llvm::SmallVector<DeviceTypeArgument> &&Archs) {
376       assert((ClauseKind == OpenACCClauseKind::DeviceType ||
377               ClauseKind == OpenACCClauseKind::DType) &&
378              "Only 'device_type'/'dtype' has a device-type-arg list");
379       Details = DeviceTypeDetails{std::move(Archs)};
380     }
381   };
382 
383   SemaOpenACC(Sema &S);
384 
385   /// Called after parsing an OpenACC Clause so that it can be checked.
386   OpenACCClause *ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
387                              OpenACCParsedClause &Clause);
388 
389   /// Called after the construct has been parsed, but clauses haven't been
390   /// parsed.  This allows us to diagnose not-implemented, as well as set up any
391   /// state required for parsing the clauses.
392   void ActOnConstruct(OpenACCDirectiveKind K, SourceLocation DirLoc);
393 
394   /// Called after the directive, including its clauses, have been parsed and
395   /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES
396   /// happen before any associated declarations or statements have been parsed.
397   /// This function is only called when we are parsing a 'statement' context.
398   bool ActOnStartStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc);
399 
400   /// Called after the directive, including its clauses, have been parsed and
401   /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES
402   /// happen before any associated declarations or statements have been parsed.
403   /// This function is only called when we are parsing a 'Decl' context.
404   bool ActOnStartDeclDirective(OpenACCDirectiveKind K, SourceLocation StartLoc);
405   /// Called when we encounter an associated statement for our construct, this
406   /// should check legality of the statement as it appertains to this Construct.
407   StmtResult ActOnAssociatedStmt(SourceLocation DirectiveLoc,
408                                  OpenACCDirectiveKind K, StmtResult AssocStmt);
409 
410   /// Called after the directive has been completely parsed, including the
411   /// declaration group or associated statement.
412   StmtResult ActOnEndStmtDirective(OpenACCDirectiveKind K,
413                                    SourceLocation StartLoc,
414                                    SourceLocation DirLoc,
415                                    SourceLocation EndLoc,
416                                    ArrayRef<OpenACCClause *> Clauses,
417                                    StmtResult AssocStmt);
418 
419   /// Called after the directive has been completely parsed, including the
420   /// declaration group or associated statement.
421   DeclGroupRef ActOnEndDeclDirective();
422 
423   /// Called when encountering an 'int-expr' for OpenACC, and manages
424   /// conversions and diagnostics to 'int'.
425   ExprResult ActOnIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
426                           SourceLocation Loc, Expr *IntExpr);
427 
428   /// Called when encountering a 'var' for OpenACC, ensures it is actually a
429   /// declaration reference to a variable of the correct type.
430   ExprResult ActOnVar(OpenACCClauseKind CK, Expr *VarExpr);
431 
432   /// Called while semantically analyzing the reduction clause, ensuring the var
433   /// is the correct kind of reference.
434   ExprResult CheckReductionVar(Expr *VarExpr);
435 
436   /// Called to check the 'var' type is a variable of pointer type, necessary
437   /// for 'deviceptr' and 'attach' clauses. Returns true on success.
438   bool CheckVarIsPointerType(OpenACCClauseKind ClauseKind, Expr *VarExpr);
439 
440   /// Checks and creates an Array Section used in an OpenACC construct/clause.
441   ExprResult ActOnArraySectionExpr(Expr *Base, SourceLocation LBLoc,
442                                    Expr *LowerBound,
443                                    SourceLocation ColonLocFirst, Expr *Length,
444                                    SourceLocation RBLoc);
445 
446   /// Helper type for the registration/assignment of constructs that need to
447   /// 'know' about their parent constructs and hold a reference to them, such as
448   /// Loop needing its parent construct.
449   class AssociatedStmtRAII {
450     SemaOpenACC &SemaRef;
451     bool WasInsideComputeConstruct;
452     OpenACCDirectiveKind DirKind;
453     llvm::SmallVector<OpenACCLoopConstruct *> ParentlessLoopConstructs;
454 
455   public:
456     AssociatedStmtRAII(SemaOpenACC &, OpenACCDirectiveKind);
457     ~AssociatedStmtRAII();
458   };
459 };
460 
461 } // namespace clang
462 
463 #endif // LLVM_CLANG_SEMA_SEMAOPENACC_H
464