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/Basic/OpenACCKinds.h" |
19 | #include "clang/Basic/SourceLocation.h" |
20 | #include "clang/Sema/Ownership.h" |
21 | #include "clang/Sema/SemaBase.h" |
22 | #include <variant> |
23 | |
24 | namespace clang { |
25 | class OpenACCClause; |
26 | |
27 | class SemaOpenACC : public SemaBase { |
28 | public: |
29 | /// A type to represent all the data for an OpenACC Clause that has been |
30 | /// parsed, but not yet created/semantically analyzed. This is effectively a |
31 | /// discriminated union on the 'Clause Kind', with all of the individual |
32 | /// clause details stored in a std::variant. |
33 | class OpenACCParsedClause { |
34 | OpenACCDirectiveKind DirKind; |
35 | OpenACCClauseKind ClauseKind; |
36 | SourceRange ClauseRange; |
37 | SourceLocation LParenLoc; |
38 | |
39 | struct DefaultDetails { |
40 | OpenACCDefaultClauseKind DefaultClauseKind; |
41 | }; |
42 | |
43 | struct ConditionDetails { |
44 | Expr *ConditionExpr; |
45 | }; |
46 | |
47 | struct IntExprDetails { |
48 | SmallVector<Expr *> IntExprs; |
49 | }; |
50 | |
51 | std::variant<std::monostate, DefaultDetails, ConditionDetails, |
52 | IntExprDetails> |
53 | Details = std::monostate{}; |
54 | |
55 | public: |
56 | OpenACCParsedClause(OpenACCDirectiveKind DirKind, |
57 | OpenACCClauseKind ClauseKind, SourceLocation BeginLoc) |
58 | : DirKind(DirKind), ClauseKind(ClauseKind), ClauseRange(BeginLoc, {}) {} |
59 | |
60 | OpenACCDirectiveKind getDirectiveKind() const { return DirKind; } |
61 | |
62 | OpenACCClauseKind getClauseKind() const { return ClauseKind; } |
63 | |
64 | SourceLocation getBeginLoc() const { return ClauseRange.getBegin(); } |
65 | |
66 | SourceLocation getLParenLoc() const { return LParenLoc; } |
67 | |
68 | SourceLocation getEndLoc() const { return ClauseRange.getEnd(); } |
69 | |
70 | OpenACCDefaultClauseKind getDefaultClauseKind() const { |
71 | assert(ClauseKind == OpenACCClauseKind::Default && |
72 | "Parsed clause is not a default clause" ); |
73 | return std::get<DefaultDetails>(v: Details).DefaultClauseKind; |
74 | } |
75 | |
76 | const Expr *getConditionExpr() const { |
77 | return const_cast<OpenACCParsedClause *>(this)->getConditionExpr(); |
78 | } |
79 | |
80 | Expr *getConditionExpr() { |
81 | assert((ClauseKind == OpenACCClauseKind::If || |
82 | (ClauseKind == OpenACCClauseKind::Self && |
83 | DirKind != OpenACCDirectiveKind::Update)) && |
84 | "Parsed clause kind does not have a condition expr" ); |
85 | |
86 | // 'self' has an optional ConditionExpr, so be tolerant of that. This will |
87 | // assert in variant otherwise. |
88 | if (ClauseKind == OpenACCClauseKind::Self && |
89 | std::holds_alternative<std::monostate>(v: Details)) |
90 | return nullptr; |
91 | |
92 | return std::get<ConditionDetails>(v&: Details).ConditionExpr; |
93 | } |
94 | |
95 | unsigned getNumIntExprs() const { |
96 | assert((ClauseKind == OpenACCClauseKind::NumGangs || |
97 | ClauseKind == OpenACCClauseKind::NumWorkers || |
98 | ClauseKind == OpenACCClauseKind::VectorLength) && |
99 | "Parsed clause kind does not have a int exprs" ); |
100 | return std::get<IntExprDetails>(v: Details).IntExprs.size(); |
101 | } |
102 | |
103 | ArrayRef<Expr *> getIntExprs() { |
104 | assert((ClauseKind == OpenACCClauseKind::NumGangs || |
105 | ClauseKind == OpenACCClauseKind::NumWorkers || |
106 | ClauseKind == OpenACCClauseKind::VectorLength) && |
107 | "Parsed clause kind does not have a int exprs" ); |
108 | return std::get<IntExprDetails>(v&: Details).IntExprs; |
109 | } |
110 | |
111 | ArrayRef<Expr *> getIntExprs() const { |
112 | return const_cast<OpenACCParsedClause *>(this)->getIntExprs(); |
113 | } |
114 | |
115 | void setLParenLoc(SourceLocation EndLoc) { LParenLoc = EndLoc; } |
116 | void setEndLoc(SourceLocation EndLoc) { ClauseRange.setEnd(EndLoc); } |
117 | |
118 | void setDefaultDetails(OpenACCDefaultClauseKind DefKind) { |
119 | assert(ClauseKind == OpenACCClauseKind::Default && |
120 | "Parsed clause is not a default clause" ); |
121 | Details = DefaultDetails{.DefaultClauseKind: DefKind}; |
122 | } |
123 | |
124 | void setConditionDetails(Expr *ConditionExpr) { |
125 | assert((ClauseKind == OpenACCClauseKind::If || |
126 | (ClauseKind == OpenACCClauseKind::Self && |
127 | DirKind != OpenACCDirectiveKind::Update)) && |
128 | "Parsed clause kind does not have a condition expr" ); |
129 | // In C++ we can count on this being a 'bool', but in C this gets left as |
130 | // some sort of scalar that codegen will have to take care of converting. |
131 | assert((!ConditionExpr || ConditionExpr->isInstantiationDependent() || |
132 | ConditionExpr->getType()->isScalarType()) && |
133 | "Condition expression type not scalar/dependent" ); |
134 | |
135 | Details = ConditionDetails{.ConditionExpr: ConditionExpr}; |
136 | } |
137 | |
138 | void setIntExprDetails(ArrayRef<Expr *> IntExprs) { |
139 | assert((ClauseKind == OpenACCClauseKind::NumGangs || |
140 | ClauseKind == OpenACCClauseKind::NumWorkers || |
141 | ClauseKind == OpenACCClauseKind::VectorLength) && |
142 | "Parsed clause kind does not have a int exprs" ); |
143 | Details = IntExprDetails{.IntExprs: {IntExprs.begin(), IntExprs.end()}}; |
144 | } |
145 | void setIntExprDetails(llvm::SmallVector<Expr *> &&IntExprs) { |
146 | assert((ClauseKind == OpenACCClauseKind::NumGangs || |
147 | ClauseKind == OpenACCClauseKind::NumWorkers || |
148 | ClauseKind == OpenACCClauseKind::VectorLength) && |
149 | "Parsed clause kind does not have a int exprs" ); |
150 | Details = IntExprDetails{.IntExprs: IntExprs}; |
151 | } |
152 | }; |
153 | |
154 | SemaOpenACC(Sema &S); |
155 | |
156 | /// Called after parsing an OpenACC Clause so that it can be checked. |
157 | OpenACCClause *ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses, |
158 | OpenACCParsedClause &Clause); |
159 | |
160 | /// Called after the construct has been parsed, but clauses haven't been |
161 | /// parsed. This allows us to diagnose not-implemented, as well as set up any |
162 | /// state required for parsing the clauses. |
163 | void ActOnConstruct(OpenACCDirectiveKind K, SourceLocation StartLoc); |
164 | |
165 | /// Called after the directive, including its clauses, have been parsed and |
166 | /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES |
167 | /// happen before any associated declarations or statements have been parsed. |
168 | /// This function is only called when we are parsing a 'statement' context. |
169 | bool ActOnStartStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc); |
170 | |
171 | /// Called after the directive, including its clauses, have been parsed and |
172 | /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES |
173 | /// happen before any associated declarations or statements have been parsed. |
174 | /// This function is only called when we are parsing a 'Decl' context. |
175 | bool ActOnStartDeclDirective(OpenACCDirectiveKind K, SourceLocation StartLoc); |
176 | /// Called when we encounter an associated statement for our construct, this |
177 | /// should check legality of the statement as it appertains to this Construct. |
178 | StmtResult ActOnAssociatedStmt(OpenACCDirectiveKind K, StmtResult AssocStmt); |
179 | |
180 | /// Called after the directive has been completely parsed, including the |
181 | /// declaration group or associated statement. |
182 | StmtResult ActOnEndStmtDirective(OpenACCDirectiveKind K, |
183 | SourceLocation StartLoc, |
184 | SourceLocation EndLoc, |
185 | ArrayRef<OpenACCClause *> Clauses, |
186 | StmtResult AssocStmt); |
187 | |
188 | /// Called after the directive has been completely parsed, including the |
189 | /// declaration group or associated statement. |
190 | DeclGroupRef ActOnEndDeclDirective(); |
191 | |
192 | /// Called when encountering an 'int-expr' for OpenACC, and manages |
193 | /// conversions and diagnostics to 'int'. |
194 | ExprResult ActOnIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK, |
195 | SourceLocation Loc, Expr *IntExpr); |
196 | }; |
197 | |
198 | } // namespace clang |
199 | |
200 | #endif // LLVM_CLANG_SEMA_SEMAOPENACC_H |
201 | |