1//===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP 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 implements semantic analysis for OpenMP directives and
10/// clauses.
11///
12//===----------------------------------------------------------------------===//
13
14#include "clang/Sema/SemaOpenMP.h"
15#include "clang/AST/ASTConsumer.h"
16
17#include "TreeTransform.h"
18#include "clang/AST/ASTContext.h"
19#include "clang/AST/ASTMutationListener.h"
20#include "clang/AST/Attr.h"
21#include "clang/AST/CXXInheritance.h"
22#include "clang/AST/Decl.h"
23#include "clang/AST/DeclCXX.h"
24#include "clang/AST/DeclOpenMP.h"
25#include "clang/AST/DynamicRecursiveASTVisitor.h"
26#include "clang/AST/OpenMPClause.h"
27#include "clang/AST/RecursiveASTVisitor.h"
28#include "clang/AST/Stmt.h"
29#include "clang/AST/StmtCXX.h"
30#include "clang/AST/StmtOpenMP.h"
31#include "clang/AST/StmtVisitor.h"
32#include "clang/Basic/DiagnosticSema.h"
33#include "clang/Basic/OpenMPKinds.h"
34#include "clang/Basic/PartialDiagnostic.h"
35#include "clang/Basic/TargetInfo.h"
36#include "clang/Sema/EnterExpressionEvaluationContext.h"
37#include "clang/Sema/Initialization.h"
38#include "clang/Sema/Lookup.h"
39#include "clang/Sema/ParsedAttr.h"
40#include "clang/Sema/Scope.h"
41#include "clang/Sema/ScopeInfo.h"
42#include "clang/Sema/Sema.h"
43#include "llvm/ADT/IndexedMap.h"
44#include "llvm/ADT/PointerEmbeddedInt.h"
45#include "llvm/ADT/STLExtras.h"
46#include "llvm/ADT/Sequence.h"
47#include "llvm/ADT/SetVector.h"
48#include "llvm/ADT/SmallSet.h"
49#include "llvm/ADT/StringExtras.h"
50#include "llvm/Frontend/OpenMP/OMPAssume.h"
51#include "llvm/Frontend/OpenMP/OMPConstants.h"
52#include "llvm/Frontend/OpenMP/OMPVersion.h"
53#include "llvm/IR/Assumptions.h"
54#include <limits>
55#include <optional>
56
57using namespace clang;
58using namespace llvm::omp;
59
60//===----------------------------------------------------------------------===//
61// Stack of data-sharing attributes for variables
62//===----------------------------------------------------------------------===//
63
64static const Expr *checkMapClauseExpressionBase(
65 Sema &SemaRef, Expr *E,
66 OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents,
67 OpenMPClauseKind CKind, OpenMPDirectiveKind DKind, bool NoDiagnose);
68
69static std::string getOpenMPClauseNameForDiag(OpenMPClauseKind C);
70
71namespace {
72/// Default data sharing attributes, which can be applied to directive.
73enum DefaultDataSharingAttributes {
74 DSA_unspecified = 0, /// Data sharing attribute not specified.
75 DSA_none = 1 << 0, /// Default data sharing attribute 'none'.
76 DSA_shared = 1 << 1, /// Default data sharing attribute 'shared'.
77 DSA_private = 1 << 2, /// Default data sharing attribute 'private'.
78 DSA_firstprivate = 1 << 3, /// Default data sharing attribute 'firstprivate'.
79};
80
81/// Variable Category attributes to restrict the modifier of the
82/// default clause (DefaultDataSharingAttributes)
83/// Not mentioning any Variable category attribute indicates
84/// the modifier (DefaultDataSharingAttributes) is for all variables.
85enum DefaultDataSharingVCAttributes {
86 DSA_VC_all = 0, /// for all variables.
87 DSA_VC_aggregate, /// for aggregate variables.
88 DSA_VC_pointer, /// for pointer variables.
89 DSA_VC_scalar, /// for scalar variables.
90};
91
92/// Stack for tracking declarations used in OpenMP directives and
93/// clauses and their data-sharing attributes.
94class DSAStackTy {
95public:
96 struct DSAVarData {
97 OpenMPDirectiveKind DKind = OMPD_unknown;
98 OpenMPClauseKind CKind = OMPC_unknown;
99 unsigned Modifier = 0;
100 const Expr *RefExpr = nullptr;
101 DeclRefExpr *PrivateCopy = nullptr;
102 SourceLocation ImplicitDSALoc;
103 bool AppliedToPointee = false;
104 DSAVarData() = default;
105 DSAVarData(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind,
106 const Expr *RefExpr, DeclRefExpr *PrivateCopy,
107 SourceLocation ImplicitDSALoc, unsigned Modifier,
108 bool AppliedToPointee)
109 : DKind(DKind), CKind(CKind), Modifier(Modifier), RefExpr(RefExpr),
110 PrivateCopy(PrivateCopy), ImplicitDSALoc(ImplicitDSALoc),
111 AppliedToPointee(AppliedToPointee) {}
112 };
113 using OperatorOffsetTy =
114 llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4>;
115 using DoacrossClauseMapTy = llvm::DenseMap<OMPClause *, OperatorOffsetTy>;
116 /// Kind of the declaration used in the uses_allocators clauses.
117 enum class UsesAllocatorsDeclKind {
118 /// Predefined allocator
119 PredefinedAllocator,
120 /// User-defined allocator
121 UserDefinedAllocator,
122 /// The declaration that represent allocator trait
123 AllocatorTrait,
124 };
125
126private:
127 struct DSAInfo {
128 OpenMPClauseKind Attributes = OMPC_unknown;
129 unsigned Modifier = 0;
130 /// Pointer to a reference expression and a flag which shows that the
131 /// variable is marked as lastprivate(true) or not (false).
132 llvm::PointerIntPair<const Expr *, 1, bool> RefExpr;
133 DeclRefExpr *PrivateCopy = nullptr;
134 /// true if the attribute is applied to the pointee, not the variable
135 /// itself.
136 bool AppliedToPointee = false;
137 };
138 using DeclSAMapTy = llvm::SmallDenseMap<const ValueDecl *, DSAInfo, 8>;
139 using UsedRefMapTy = llvm::SmallDenseMap<const ValueDecl *, const Expr *, 8>;
140 using LCDeclInfo = std::pair<unsigned, VarDecl *>;
141 using LoopControlVariablesMapTy =
142 llvm::SmallDenseMap<const ValueDecl *, LCDeclInfo, 8>;
143 /// Struct that associates a component with the clause kind where they are
144 /// found.
145 struct MappedExprComponentTy {
146 OMPClauseMappableExprCommon::MappableExprComponentLists Components;
147 OpenMPClauseKind Kind = OMPC_unknown;
148 };
149 using MappedExprComponentsTy =
150 llvm::DenseMap<const ValueDecl *, MappedExprComponentTy>;
151 using CriticalsWithHintsTy =
152 llvm::StringMap<std::pair<const OMPCriticalDirective *, llvm::APSInt>>;
153 struct ReductionData {
154 using BOKPtrType = llvm::PointerEmbeddedInt<BinaryOperatorKind, 16>;
155 SourceRange ReductionRange;
156 llvm::PointerUnion<const Expr *, BOKPtrType> ReductionOp;
157 ReductionData() = default;
158 void set(BinaryOperatorKind BO, SourceRange RR) {
159 ReductionRange = RR;
160 ReductionOp = BO;
161 }
162 void set(const Expr *RefExpr, SourceRange RR) {
163 ReductionRange = RR;
164 ReductionOp = RefExpr;
165 }
166 };
167 using DeclReductionMapTy =
168 llvm::SmallDenseMap<const ValueDecl *, ReductionData, 4>;
169 struct DefaultmapInfo {
170 OpenMPDefaultmapClauseModifier ImplicitBehavior =
171 OMPC_DEFAULTMAP_MODIFIER_unknown;
172 SourceLocation SLoc;
173 DefaultmapInfo() = default;
174 DefaultmapInfo(OpenMPDefaultmapClauseModifier M, SourceLocation Loc)
175 : ImplicitBehavior(M), SLoc(Loc) {}
176 };
177
178 struct SharingMapTy {
179 DeclSAMapTy SharingMap;
180 DeclReductionMapTy ReductionMap;
181 UsedRefMapTy AlignedMap;
182 UsedRefMapTy NontemporalMap;
183 MappedExprComponentsTy MappedExprComponents;
184 LoopControlVariablesMapTy LCVMap;
185 /// Track DecompositionDecls and their data-sharing attributes to detect
186 /// conflicting clauses on bindings from the same decomposition.
187 DefaultDataSharingAttributes DefaultAttr = DSA_unspecified;
188 SourceLocation DefaultAttrLoc;
189 DefaultDataSharingVCAttributes DefaultVCAttr = DSA_VC_all;
190 SourceLocation DefaultAttrVCLoc;
191 DefaultmapInfo DefaultmapMap[OMPC_DEFAULTMAP_unknown + 1];
192 OpenMPDirectiveKind Directive = OMPD_unknown;
193 DeclarationNameInfo DirectiveName;
194 Scope *CurScope = nullptr;
195 DeclContext *Context = nullptr;
196 SourceLocation ConstructLoc;
197 /// Set of 'depend' clauses with 'sink|source' dependence kind. Required to
198 /// get the data (loop counters etc.) about enclosing loop-based construct.
199 /// This data is required during codegen.
200 DoacrossClauseMapTy DoacrossDepends;
201 /// First argument (Expr *) contains optional argument of the
202 /// 'ordered' clause, the second one is true if the regions has 'ordered'
203 /// clause, false otherwise.
204 std::optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion;
205 bool RegionHasOrderConcurrent = false;
206 unsigned AssociatedLoops = 1;
207 bool HasMutipleLoops = false;
208 const Decl *PossiblyLoopCounter = nullptr;
209 bool NowaitRegion = false;
210 bool UntiedRegion = false;
211 bool CancelRegion = false;
212 bool LoopStart = false;
213 bool BodyComplete = false;
214 SourceLocation PrevScanLocation;
215 SourceLocation PrevOrderedLocation;
216 SourceLocation InnerTeamsRegionLoc;
217 /// Reference to the taskgroup task_reduction reference expression.
218 Expr *TaskgroupReductionRef = nullptr;
219 llvm::DenseSet<QualType> MappedClassesQualTypes;
220 SmallVector<Expr *, 4> InnerUsedAllocators;
221 llvm::DenseSet<CanonicalDeclPtr<Decl>> ImplicitTaskFirstprivates;
222 /// List of globals marked as declare target link in this target region
223 /// (isOpenMPTargetExecutionDirective(Directive) == true).
224 llvm::SmallVector<DeclRefExpr *, 4> DeclareTargetLinkVarDecls;
225 /// List of decls used in inclusive/exclusive clauses of the scan directive.
226 llvm::DenseSet<CanonicalDeclPtr<Decl>> UsedInScanDirective;
227 llvm::DenseMap<CanonicalDeclPtr<const Decl>, UsesAllocatorsDeclKind>
228 UsesAllocatorsDecls;
229 /// Data is required on creating capture fields for implicit
230 /// default first|private clause.
231 struct ImplicitDefaultFDInfoTy {
232 /// Field decl.
233 const FieldDecl *FD = nullptr;
234 /// Nesting stack level
235 size_t StackLevel = 0;
236 /// Capture variable decl.
237 VarDecl *VD = nullptr;
238 ImplicitDefaultFDInfoTy(const FieldDecl *FD, size_t StackLevel,
239 VarDecl *VD)
240 : FD(FD), StackLevel(StackLevel), VD(VD) {}
241 };
242 /// List of captured fields
243 llvm::SmallVector<ImplicitDefaultFDInfoTy, 8>
244 ImplicitDefaultFirstprivateFDs;
245 Expr *DeclareMapperVar = nullptr;
246 SmallVector<VarDecl *, 16> IteratorVarDecls;
247 SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
248 Scope *CurScope, SourceLocation Loc)
249 : Directive(DKind), DirectiveName(Name), CurScope(CurScope),
250 ConstructLoc(Loc) {}
251 SharingMapTy() = default;
252 };
253
254 using StackTy = SmallVector<SharingMapTy, 4>;
255
256 /// Stack of used declaration and their data-sharing attributes.
257 DeclSAMapTy Threadprivates;
258 DeclSAMapTy Groupprivates;
259 const FunctionScopeInfo *CurrentNonCapturingFunctionScope = nullptr;
260 SmallVector<std::pair<StackTy, const FunctionScopeInfo *>, 4> Stack;
261 /// true, if check for DSA must be from parent directive, false, if
262 /// from current directive.
263 OpenMPClauseKind ClauseKindMode = OMPC_unknown;
264 Sema &SemaRef;
265 bool ForceCapturing = false;
266 /// true if all the variables in the target executable directives must be
267 /// captured by reference.
268 bool ForceCaptureByReferenceInTargetExecutable = false;
269 CriticalsWithHintsTy Criticals;
270 unsigned IgnoredStackElements = 0;
271
272 /// Iterators over the stack iterate in order from innermost to outermost
273 /// directive.
274 using const_iterator = StackTy::const_reverse_iterator;
275 const_iterator begin() const {
276 return Stack.empty() ? const_iterator()
277 : Stack.back().first.rbegin() + IgnoredStackElements;
278 }
279 const_iterator end() const {
280 return Stack.empty() ? const_iterator() : Stack.back().first.rend();
281 }
282 using iterator = StackTy::reverse_iterator;
283 iterator begin() {
284 return Stack.empty() ? iterator()
285 : Stack.back().first.rbegin() + IgnoredStackElements;
286 }
287 iterator end() {
288 return Stack.empty() ? iterator() : Stack.back().first.rend();
289 }
290
291 // Convenience operations to get at the elements of the stack.
292
293 bool isStackEmpty() const {
294 return Stack.empty() ||
295 Stack.back().second != CurrentNonCapturingFunctionScope ||
296 Stack.back().first.size() <= IgnoredStackElements;
297 }
298 size_t getStackSize() const {
299 return isStackEmpty() ? 0
300 : Stack.back().first.size() - IgnoredStackElements;
301 }
302
303 SharingMapTy *getTopOfStackOrNull() {
304 size_t Size = getStackSize();
305 if (Size == 0)
306 return nullptr;
307 return &Stack.back().first[Size - 1];
308 }
309 const SharingMapTy *getTopOfStackOrNull() const {
310 return const_cast<DSAStackTy &>(*this).getTopOfStackOrNull();
311 }
312 SharingMapTy &getTopOfStack() {
313 assert(!isStackEmpty() && "no current directive");
314 return *getTopOfStackOrNull();
315 }
316 const SharingMapTy &getTopOfStack() const {
317 return const_cast<DSAStackTy &>(*this).getTopOfStack();
318 }
319
320 SharingMapTy *getSecondOnStackOrNull() {
321 size_t Size = getStackSize();
322 if (Size <= 1)
323 return nullptr;
324 return &Stack.back().first[Size - 2];
325 }
326 const SharingMapTy *getSecondOnStackOrNull() const {
327 return const_cast<DSAStackTy &>(*this).getSecondOnStackOrNull();
328 }
329
330 /// Get the stack element at a certain level (previously returned by
331 /// \c getNestingLevel).
332 ///
333 /// Note that nesting levels count from outermost to innermost, and this is
334 /// the reverse of our iteration order where new inner levels are pushed at
335 /// the front of the stack.
336 SharingMapTy &getStackElemAtLevel(unsigned Level) {
337 assert(Level < getStackSize() && "no such stack element");
338 return Stack.back().first[Level];
339 }
340 const SharingMapTy &getStackElemAtLevel(unsigned Level) const {
341 return const_cast<DSAStackTy &>(*this).getStackElemAtLevel(Level);
342 }
343
344 DSAVarData getDSA(const_iterator &Iter, ValueDecl *D) const;
345
346 /// Checks if the variable is a local for OpenMP region.
347 bool isOpenMPLocal(VarDecl *D, const_iterator Iter) const;
348
349 /// Vector of previously declared requires directives
350 SmallVector<const OMPRequiresDecl *, 2> RequiresDecls;
351 /// omp_allocator_handle_t type.
352 QualType OMPAllocatorHandleT;
353 /// omp_depend_t type.
354 QualType OMPDependT;
355 /// omp_event_handle_t type.
356 QualType OMPEventHandleT;
357 /// omp_alloctrait_t type.
358 QualType OMPAlloctraitT;
359 /// Expression for the predefined allocators.
360 Expr *OMPPredefinedAllocators[OMPAllocateDeclAttr::OMPUserDefinedMemAlloc] = {
361 nullptr};
362 /// Vector of previously encountered target directives
363 SmallVector<SourceLocation, 2> TargetLocations;
364 SourceLocation AtomicLocation;
365 /// Vector of declare variant construct traits.
366 SmallVector<llvm::omp::TraitProperty, 8> ConstructTraits;
367
368public:
369 explicit DSAStackTy(Sema &S) : SemaRef(S) {}
370
371 /// Sets omp_allocator_handle_t type.
372 void setOMPAllocatorHandleT(QualType Ty) { OMPAllocatorHandleT = Ty; }
373 /// Gets omp_allocator_handle_t type.
374 QualType getOMPAllocatorHandleT() const { return OMPAllocatorHandleT; }
375 /// Sets omp_alloctrait_t type.
376 void setOMPAlloctraitT(QualType Ty) { OMPAlloctraitT = Ty; }
377 /// Gets omp_alloctrait_t type.
378 QualType getOMPAlloctraitT() const { return OMPAlloctraitT; }
379 /// Sets the given default allocator.
380 void setAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind,
381 Expr *Allocator) {
382 OMPPredefinedAllocators[AllocatorKind] = Allocator;
383 }
384 /// Returns the specified default allocator.
385 Expr *getAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind) const {
386 return OMPPredefinedAllocators[AllocatorKind];
387 }
388 /// Sets omp_depend_t type.
389 void setOMPDependT(QualType Ty) { OMPDependT = Ty; }
390 /// Gets omp_depend_t type.
391 QualType getOMPDependT() const { return OMPDependT; }
392
393 /// Sets omp_event_handle_t type.
394 void setOMPEventHandleT(QualType Ty) { OMPEventHandleT = Ty; }
395 /// Gets omp_event_handle_t type.
396 QualType getOMPEventHandleT() const { return OMPEventHandleT; }
397
398 bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; }
399 OpenMPClauseKind getClauseParsingMode() const {
400 assert(isClauseParsingMode() && "Must be in clause parsing mode.");
401 return ClauseKindMode;
402 }
403 void setClauseParsingMode(OpenMPClauseKind K) { ClauseKindMode = K; }
404
405 bool isBodyComplete() const {
406 const SharingMapTy *Top = getTopOfStackOrNull();
407 return Top && Top->BodyComplete;
408 }
409 void setBodyComplete() { getTopOfStack().BodyComplete = true; }
410
411 bool isForceVarCapturing() const { return ForceCapturing; }
412 void setForceVarCapturing(bool V) { ForceCapturing = V; }
413
414 void setForceCaptureByReferenceInTargetExecutable(bool V) {
415 ForceCaptureByReferenceInTargetExecutable = V;
416 }
417 bool isForceCaptureByReferenceInTargetExecutable() const {
418 return ForceCaptureByReferenceInTargetExecutable;
419 }
420
421 void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName,
422 Scope *CurScope, SourceLocation Loc) {
423 assert(!IgnoredStackElements &&
424 "cannot change stack while ignoring elements");
425 if (Stack.empty() ||
426 Stack.back().second != CurrentNonCapturingFunctionScope)
427 Stack.emplace_back(Args: StackTy(), Args&: CurrentNonCapturingFunctionScope);
428 Stack.back().first.emplace_back(Args&: DKind, Args: DirName, Args&: CurScope, Args&: Loc);
429 Stack.back().first.back().DefaultAttrLoc = Loc;
430 }
431
432 void pop() {
433 assert(!IgnoredStackElements &&
434 "cannot change stack while ignoring elements");
435 assert(!Stack.back().first.empty() &&
436 "Data-sharing attributes stack is empty!");
437 Stack.back().first.pop_back();
438 }
439
440 /// RAII object to temporarily leave the scope of a directive when we want to
441 /// logically operate in its parent.
442 class ParentDirectiveScope {
443 DSAStackTy &Self;
444 bool Active;
445
446 public:
447 ParentDirectiveScope(DSAStackTy &Self, bool Activate)
448 : Self(Self), Active(false) {
449 if (Activate)
450 enable();
451 }
452 ~ParentDirectiveScope() { disable(); }
453 void disable() {
454 if (Active) {
455 --Self.IgnoredStackElements;
456 Active = false;
457 }
458 }
459 void enable() {
460 if (!Active) {
461 ++Self.IgnoredStackElements;
462 Active = true;
463 }
464 }
465 };
466
467 /// Marks that we're started loop parsing.
468 void loopInit() {
469 assert(isOpenMPLoopDirective(getCurrentDirective()) &&
470 "Expected loop-based directive.");
471 getTopOfStack().LoopStart = true;
472 }
473 /// Start capturing of the variables in the loop context.
474 void loopStart() {
475 assert(isOpenMPLoopDirective(getCurrentDirective()) &&
476 "Expected loop-based directive.");
477 getTopOfStack().LoopStart = false;
478 }
479 /// true, if variables are captured, false otherwise.
480 bool isLoopStarted() const {
481 assert(isOpenMPLoopDirective(getCurrentDirective()) &&
482 "Expected loop-based directive.");
483 return !getTopOfStack().LoopStart;
484 }
485 /// Marks (or clears) declaration as possibly loop counter.
486 void resetPossibleLoopCounter(const Decl *D = nullptr) {
487 getTopOfStack().PossiblyLoopCounter = D ? D->getCanonicalDecl() : D;
488 }
489 /// Gets the possible loop counter decl.
490 const Decl *getPossiblyLoopCounter() const {
491 return getTopOfStack().PossiblyLoopCounter;
492 }
493 /// Start new OpenMP region stack in new non-capturing function.
494 void pushFunction() {
495 assert(!IgnoredStackElements &&
496 "cannot change stack while ignoring elements");
497 const FunctionScopeInfo *CurFnScope = SemaRef.getCurFunction();
498 assert(!isa<CapturingScopeInfo>(CurFnScope));
499 CurrentNonCapturingFunctionScope = CurFnScope;
500 }
501 /// Pop region stack for non-capturing function.
502 void popFunction(const FunctionScopeInfo *OldFSI) {
503 assert(!IgnoredStackElements &&
504 "cannot change stack while ignoring elements");
505 if (!Stack.empty() && Stack.back().second == OldFSI) {
506 assert(Stack.back().first.empty());
507 Stack.pop_back();
508 }
509 CurrentNonCapturingFunctionScope = nullptr;
510 for (const FunctionScopeInfo *FSI : llvm::reverse(C&: SemaRef.FunctionScopes)) {
511 if (!isa<CapturingScopeInfo>(Val: FSI)) {
512 CurrentNonCapturingFunctionScope = FSI;
513 break;
514 }
515 }
516 }
517
518 void addCriticalWithHint(const OMPCriticalDirective *D, llvm::APSInt Hint) {
519 Criticals.try_emplace(Key: D->getDirectiveName().getAsString(), Args&: D, Args&: Hint);
520 }
521 std::pair<const OMPCriticalDirective *, llvm::APSInt>
522 getCriticalWithHint(const DeclarationNameInfo &Name) const {
523 auto I = Criticals.find(Key: Name.getAsString());
524 if (I != Criticals.end())
525 return I->second;
526 return std::make_pair(x: nullptr, y: llvm::APSInt());
527 }
528 /// If 'aligned' declaration for given variable \a D was not seen yet,
529 /// add it and return NULL; otherwise return previous occurrence's expression
530 /// for diagnostics.
531 const Expr *addUniqueAligned(const ValueDecl *D, const Expr *NewDE);
532 /// If 'nontemporal' declaration for given variable \a D was not seen yet,
533 /// add it and return NULL; otherwise return previous occurrence's expression
534 /// for diagnostics.
535 const Expr *addUniqueNontemporal(const ValueDecl *D, const Expr *NewDE);
536
537 /// Register specified variable as loop control variable.
538 void addLoopControlVariable(const ValueDecl *D, VarDecl *Capture);
539 /// Check if the specified variable is a loop control variable for
540 /// current region.
541 /// \return The index of the loop control variable in the list of associated
542 /// for-loops (from outer to inner).
543 const LCDeclInfo isLoopControlVariable(const ValueDecl *D) const;
544 /// Check if the specified variable is a loop control variable for
545 /// parent region.
546 /// \return The index of the loop control variable in the list of associated
547 /// for-loops (from outer to inner).
548 const LCDeclInfo isParentLoopControlVariable(const ValueDecl *D) const;
549 /// Check if the specified variable is a loop control variable for
550 /// current region.
551 /// \return The index of the loop control variable in the list of associated
552 /// for-loops (from outer to inner).
553 const LCDeclInfo isLoopControlVariable(const ValueDecl *D,
554 unsigned Level) const;
555 /// Get the loop control variable for the I-th loop (or nullptr) in
556 /// parent directive.
557 const ValueDecl *getParentLoopControlVariable(unsigned I) const;
558
559 /// Marks the specified decl \p D as used in scan directive.
560 void markDeclAsUsedInScanDirective(ValueDecl *D) {
561 if (SharingMapTy *Stack = getSecondOnStackOrNull())
562 Stack->UsedInScanDirective.insert(V: D);
563 }
564
565 /// Checks if the specified declaration was used in the inner scan directive.
566 bool isUsedInScanDirective(ValueDecl *D) const {
567 if (const SharingMapTy *Stack = getTopOfStackOrNull())
568 return Stack->UsedInScanDirective.contains(V: D);
569 return false;
570 }
571
572 /// Adds explicit data sharing attribute to the specified declaration.
573 void addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
574 DeclRefExpr *PrivateCopy = nullptr, unsigned Modifier = 0,
575 bool AppliedToPointee = false);
576
577 /// Adds additional information for the reduction items with the reduction id
578 /// represented as an operator.
579 void addTaskgroupReductionData(const ValueDecl *D, SourceRange SR,
580 BinaryOperatorKind BOK);
581 /// Adds additional information for the reduction items with the reduction id
582 /// represented as reduction identifier.
583 void addTaskgroupReductionData(const ValueDecl *D, SourceRange SR,
584 const Expr *ReductionRef);
585 /// Returns the location and reduction operation from the innermost parent
586 /// region for the given \p D.
587 const DSAVarData
588 getTopMostTaskgroupReductionData(const ValueDecl *D, SourceRange &SR,
589 BinaryOperatorKind &BOK,
590 Expr *&TaskgroupDescriptor) const;
591 /// Returns the location and reduction operation from the innermost parent
592 /// region for the given \p D.
593 const DSAVarData
594 getTopMostTaskgroupReductionData(const ValueDecl *D, SourceRange &SR,
595 const Expr *&ReductionRef,
596 Expr *&TaskgroupDescriptor) const;
597 /// Return reduction reference expression for the current taskgroup or
598 /// parallel/worksharing directives with task reductions.
599 Expr *getTaskgroupReductionRef() const {
600 assert((getTopOfStack().Directive == OMPD_taskgroup ||
601 ((isOpenMPParallelDirective(getTopOfStack().Directive) ||
602 isOpenMPWorksharingDirective(getTopOfStack().Directive)) &&
603 !isOpenMPSimdDirective(getTopOfStack().Directive))) &&
604 "taskgroup reference expression requested for non taskgroup or "
605 "parallel/worksharing directive.");
606 return getTopOfStack().TaskgroupReductionRef;
607 }
608 /// Checks if the given \p VD declaration is actually a taskgroup reduction
609 /// descriptor variable at the \p Level of OpenMP regions.
610 bool isTaskgroupReductionRef(const ValueDecl *VD, unsigned Level) const {
611 return getStackElemAtLevel(Level).TaskgroupReductionRef &&
612 cast<DeclRefExpr>(Val: getStackElemAtLevel(Level).TaskgroupReductionRef)
613 ->getDecl() == VD;
614 }
615
616 /// Returns data sharing attributes from top of the stack for the
617 /// specified declaration.
618 const DSAVarData getTopDSA(ValueDecl *D, bool FromParent);
619 /// Returns data-sharing attributes for the specified declaration.
620 const DSAVarData getImplicitDSA(ValueDecl *D, bool FromParent) const;
621 /// Returns data-sharing attributes for the specified declaration.
622 const DSAVarData getImplicitDSA(ValueDecl *D, unsigned Level) const;
623 /// Checks if the specified variables has data-sharing attributes which
624 /// match specified \a CPred predicate in any directive which matches \a DPred
625 /// predicate.
626 const DSAVarData
627 hasDSA(ValueDecl *D,
628 const llvm::function_ref<bool(OpenMPClauseKind, bool,
629 DefaultDataSharingAttributes)>
630 CPred,
631 const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred,
632 bool FromParent) const;
633 /// Checks if the specified variables has data-sharing attributes which
634 /// match specified \a CPred predicate in any innermost directive which
635 /// matches \a DPred predicate.
636 const DSAVarData
637 hasInnermostDSA(ValueDecl *D,
638 const llvm::function_ref<bool(OpenMPClauseKind, bool)> CPred,
639 const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred,
640 bool FromParent) const;
641 /// Checks if the specified variables has explicit data-sharing
642 /// attributes which match specified \a CPred predicate at the specified
643 /// OpenMP region.
644 bool
645 hasExplicitDSA(const ValueDecl *D,
646 const llvm::function_ref<bool(OpenMPClauseKind, bool)> CPred,
647 unsigned Level, bool NotLastprivate = false) const;
648
649 /// Returns true if the directive at level \Level matches in the
650 /// specified \a DPred predicate.
651 bool hasExplicitDirective(
652 const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred,
653 unsigned Level) const;
654
655 /// Finds a directive which matches specified \a DPred predicate.
656 bool hasDirective(
657 const llvm::function_ref<bool(
658 OpenMPDirectiveKind, const DeclarationNameInfo &, SourceLocation)>
659 DPred,
660 bool FromParent) const;
661
662 /// Returns currently analyzed directive.
663 OpenMPDirectiveKind getCurrentDirective() const {
664 const SharingMapTy *Top = getTopOfStackOrNull();
665 return Top ? Top->Directive : OMPD_unknown;
666 }
667 /// Returns directive kind at specified level.
668 OpenMPDirectiveKind getDirective(unsigned Level) const {
669 assert(!isStackEmpty() && "No directive at specified level.");
670 return getStackElemAtLevel(Level).Directive;
671 }
672 /// Returns the capture region at the specified level.
673 OpenMPDirectiveKind getCaptureRegion(unsigned Level,
674 unsigned OpenMPCaptureLevel) const {
675 SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
676 getOpenMPCaptureRegions(CaptureRegions, DKind: getDirective(Level));
677 return CaptureRegions[OpenMPCaptureLevel];
678 }
679 /// Returns parent directive.
680 OpenMPDirectiveKind getParentDirective() const {
681 const SharingMapTy *Parent = getSecondOnStackOrNull();
682 return Parent ? Parent->Directive : OMPD_unknown;
683 }
684
685 /// Add requires decl to internal vector
686 void addRequiresDecl(OMPRequiresDecl *RD) { RequiresDecls.push_back(Elt: RD); }
687
688 ArrayRef<const OMPRequiresDecl *> getRequiresDecls() const {
689 return RequiresDecls;
690 }
691
692 /// Checks if the defined 'requires' directive has specified type of clause.
693 template <typename ClauseType> bool hasRequiresDeclWithClause() const {
694 return llvm::any_of(RequiresDecls, [](const OMPRequiresDecl *D) {
695 return llvm::any_of(D->clauselists(), [](const OMPClause *C) {
696 return isa<ClauseType>(C);
697 });
698 });
699 }
700
701 /// Checks for a duplicate clause amongst previously declared requires
702 /// directives
703 bool hasDuplicateRequiresClause(ArrayRef<OMPClause *> ClauseList) const {
704 bool IsDuplicate = false;
705 for (OMPClause *CNew : ClauseList) {
706 for (const OMPRequiresDecl *D : RequiresDecls) {
707 for (const OMPClause *CPrev : D->clauselists()) {
708 if (CNew->getClauseKind() == CPrev->getClauseKind()) {
709 SemaRef.Diag(Loc: CNew->getBeginLoc(),
710 DiagID: diag::err_omp_requires_clause_redeclaration)
711 << getOpenMPClauseNameForDiag(C: CNew->getClauseKind());
712 SemaRef.Diag(Loc: CPrev->getBeginLoc(),
713 DiagID: diag::note_omp_requires_previous_clause)
714 << getOpenMPClauseNameForDiag(C: CPrev->getClauseKind());
715 IsDuplicate = true;
716 }
717 }
718 }
719 }
720 return IsDuplicate;
721 }
722
723 /// Add location of previously encountered target to internal vector
724 void addTargetDirLocation(SourceLocation LocStart) {
725 TargetLocations.push_back(Elt: LocStart);
726 }
727
728 /// Add location for the first encountered atomic directive.
729 void addAtomicDirectiveLoc(SourceLocation Loc) {
730 if (AtomicLocation.isInvalid())
731 AtomicLocation = Loc;
732 }
733
734 /// Returns the location of the first encountered atomic directive in the
735 /// module.
736 SourceLocation getAtomicDirectiveLoc() const { return AtomicLocation; }
737
738 // Return previously encountered target region locations.
739 ArrayRef<SourceLocation> getEncounteredTargetLocs() const {
740 return TargetLocations;
741 }
742
743 /// Set default data sharing attribute to none.
744 void setDefaultDSANone(SourceLocation Loc) {
745 getTopOfStack().DefaultAttr = DSA_none;
746 getTopOfStack().DefaultAttrLoc = Loc;
747 }
748 /// Set default data sharing attribute to shared.
749 void setDefaultDSAShared(SourceLocation Loc) {
750 getTopOfStack().DefaultAttr = DSA_shared;
751 getTopOfStack().DefaultAttrLoc = Loc;
752 }
753 /// Set default data sharing attribute to private.
754 void setDefaultDSAPrivate(SourceLocation Loc) {
755 getTopOfStack().DefaultAttr = DSA_private;
756 getTopOfStack().DefaultAttrLoc = Loc;
757 }
758 /// Set default data sharing attribute to firstprivate.
759 void setDefaultDSAFirstPrivate(SourceLocation Loc) {
760 getTopOfStack().DefaultAttr = DSA_firstprivate;
761 getTopOfStack().DefaultAttrLoc = Loc;
762 }
763 /// Set default data sharing variable category attribute to aggregate.
764 void setDefaultDSAVCAggregate(SourceLocation VCLoc) {
765 getTopOfStack().DefaultVCAttr = DSA_VC_aggregate;
766 getTopOfStack().DefaultAttrVCLoc = VCLoc;
767 }
768 /// Set default data sharing variable category attribute to all.
769 void setDefaultDSAVCAll(SourceLocation VCLoc) {
770 getTopOfStack().DefaultVCAttr = DSA_VC_all;
771 getTopOfStack().DefaultAttrVCLoc = VCLoc;
772 }
773 /// Set default data sharing variable category attribute to pointer.
774 void setDefaultDSAVCPointer(SourceLocation VCLoc) {
775 getTopOfStack().DefaultVCAttr = DSA_VC_pointer;
776 getTopOfStack().DefaultAttrVCLoc = VCLoc;
777 }
778 /// Set default data sharing variable category attribute to scalar.
779 void setDefaultDSAVCScalar(SourceLocation VCLoc) {
780 getTopOfStack().DefaultVCAttr = DSA_VC_scalar;
781 getTopOfStack().DefaultAttrVCLoc = VCLoc;
782 }
783 /// Set default data mapping attribute to Modifier:Kind
784 void setDefaultDMAAttr(OpenMPDefaultmapClauseModifier M,
785 OpenMPDefaultmapClauseKind Kind, SourceLocation Loc) {
786 DefaultmapInfo &DMI = getTopOfStack().DefaultmapMap[Kind];
787 DMI.ImplicitBehavior = M;
788 DMI.SLoc = Loc;
789 }
790 /// Check whether the implicit-behavior has been set in defaultmap
791 bool checkDefaultmapCategory(OpenMPDefaultmapClauseKind VariableCategory) {
792 if (VariableCategory == OMPC_DEFAULTMAP_unknown)
793 return getTopOfStack()
794 .DefaultmapMap[OMPC_DEFAULTMAP_aggregate]
795 .ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown ||
796 getTopOfStack()
797 .DefaultmapMap[OMPC_DEFAULTMAP_scalar]
798 .ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown ||
799 getTopOfStack()
800 .DefaultmapMap[OMPC_DEFAULTMAP_pointer]
801 .ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown;
802 return getTopOfStack().DefaultmapMap[VariableCategory].ImplicitBehavior !=
803 OMPC_DEFAULTMAP_MODIFIER_unknown;
804 }
805
806 ArrayRef<llvm::omp::TraitProperty> getConstructTraits() {
807 return ConstructTraits;
808 }
809 void handleConstructTrait(ArrayRef<llvm::omp::TraitProperty> Traits,
810 bool ScopeEntry) {
811 if (ScopeEntry)
812 ConstructTraits.append(in_start: Traits.begin(), in_end: Traits.end());
813 else
814 for (llvm::omp::TraitProperty Trait : llvm::reverse(C&: Traits)) {
815 llvm::omp::TraitProperty Top = ConstructTraits.pop_back_val();
816 assert(Top == Trait && "Something left a trait on the stack!");
817 (void)Trait;
818 (void)Top;
819 }
820 }
821
822 DefaultDataSharingAttributes getDefaultDSA(unsigned Level) const {
823 return getStackSize() <= Level ? DSA_unspecified
824 : getStackElemAtLevel(Level).DefaultAttr;
825 }
826 DefaultDataSharingAttributes getDefaultDSA() const {
827 return isStackEmpty() ? DSA_unspecified : getTopOfStack().DefaultAttr;
828 }
829 SourceLocation getDefaultDSALocation() const {
830 return isStackEmpty() ? SourceLocation() : getTopOfStack().DefaultAttrLoc;
831 }
832 OpenMPDefaultmapClauseModifier
833 getDefaultmapModifier(OpenMPDefaultmapClauseKind Kind) const {
834 return isStackEmpty()
835 ? OMPC_DEFAULTMAP_MODIFIER_unknown
836 : getTopOfStack().DefaultmapMap[Kind].ImplicitBehavior;
837 }
838 OpenMPDefaultmapClauseModifier
839 getDefaultmapModifierAtLevel(unsigned Level,
840 OpenMPDefaultmapClauseKind Kind) const {
841 return getStackElemAtLevel(Level).DefaultmapMap[Kind].ImplicitBehavior;
842 }
843 bool isDefaultmapCapturedByRef(unsigned Level,
844 OpenMPDefaultmapClauseKind Kind) const {
845 OpenMPDefaultmapClauseModifier M =
846 getDefaultmapModifierAtLevel(Level, Kind);
847 if (Kind == OMPC_DEFAULTMAP_scalar || Kind == OMPC_DEFAULTMAP_pointer) {
848 return (M == OMPC_DEFAULTMAP_MODIFIER_alloc) ||
849 (M == OMPC_DEFAULTMAP_MODIFIER_to) ||
850 (M == OMPC_DEFAULTMAP_MODIFIER_from) ||
851 (M == OMPC_DEFAULTMAP_MODIFIER_tofrom) ||
852 (M == OMPC_DEFAULTMAP_MODIFIER_present) ||
853 (M == OMPC_DEFAULTMAP_MODIFIER_storage);
854 }
855 return true;
856 }
857 static bool mustBeFirstprivateBase(OpenMPDefaultmapClauseModifier M,
858 OpenMPDefaultmapClauseKind Kind) {
859 switch (Kind) {
860 case OMPC_DEFAULTMAP_scalar:
861 case OMPC_DEFAULTMAP_pointer:
862 return (M == OMPC_DEFAULTMAP_MODIFIER_unknown) ||
863 (M == OMPC_DEFAULTMAP_MODIFIER_firstprivate) ||
864 (M == OMPC_DEFAULTMAP_MODIFIER_default);
865 case OMPC_DEFAULTMAP_aggregate:
866 return M == OMPC_DEFAULTMAP_MODIFIER_firstprivate;
867 default:
868 break;
869 }
870 llvm_unreachable("Unexpected OpenMPDefaultmapClauseKind enum");
871 }
872 bool mustBeFirstprivateAtLevel(unsigned Level,
873 OpenMPDefaultmapClauseKind Kind) const {
874 OpenMPDefaultmapClauseModifier M =
875 getDefaultmapModifierAtLevel(Level, Kind);
876 return mustBeFirstprivateBase(M, Kind);
877 }
878 bool mustBeFirstprivate(OpenMPDefaultmapClauseKind Kind) const {
879 OpenMPDefaultmapClauseModifier M = getDefaultmapModifier(Kind);
880 return mustBeFirstprivateBase(M, Kind);
881 }
882
883 /// Checks if the specified variable is a threadprivate.
884 bool isThreadPrivate(VarDecl *D) {
885 const DSAVarData DVar = getTopDSA(D, FromParent: false);
886 return isOpenMPThreadPrivate(Kind: DVar.CKind);
887 }
888
889 /// Marks current region as ordered (it has an 'ordered' clause).
890 void setOrderedRegion(bool IsOrdered, const Expr *Param,
891 OMPOrderedClause *Clause) {
892 if (IsOrdered)
893 getTopOfStack().OrderedRegion.emplace(args&: Param, args&: Clause);
894 else
895 getTopOfStack().OrderedRegion.reset();
896 }
897 /// Returns true, if region is ordered (has associated 'ordered' clause),
898 /// false - otherwise.
899 bool isOrderedRegion() const {
900 if (const SharingMapTy *Top = getTopOfStackOrNull())
901 return Top->OrderedRegion.has_value();
902 return false;
903 }
904 /// Returns optional parameter for the ordered region.
905 std::pair<const Expr *, OMPOrderedClause *> getOrderedRegionParam() const {
906 if (const SharingMapTy *Top = getTopOfStackOrNull())
907 if (Top->OrderedRegion)
908 return *Top->OrderedRegion;
909 return std::make_pair(x: nullptr, y: nullptr);
910 }
911 /// Returns true, if parent region is ordered (has associated
912 /// 'ordered' clause), false - otherwise.
913 bool isParentOrderedRegion() const {
914 if (const SharingMapTy *Parent = getSecondOnStackOrNull())
915 return Parent->OrderedRegion.has_value();
916 return false;
917 }
918 /// Returns optional parameter for the ordered region.
919 std::pair<const Expr *, OMPOrderedClause *>
920 getParentOrderedRegionParam() const {
921 if (const SharingMapTy *Parent = getSecondOnStackOrNull())
922 if (Parent->OrderedRegion)
923 return *Parent->OrderedRegion;
924 return std::make_pair(x: nullptr, y: nullptr);
925 }
926 /// Marks current region as having an 'order' clause.
927 void setRegionHasOrderConcurrent(bool HasOrderConcurrent) {
928 getTopOfStack().RegionHasOrderConcurrent = HasOrderConcurrent;
929 }
930 /// Returns true, if parent region is order (has associated
931 /// 'order' clause), false - otherwise.
932 bool isParentOrderConcurrent() const {
933 if (const SharingMapTy *Parent = getSecondOnStackOrNull())
934 return Parent->RegionHasOrderConcurrent;
935 return false;
936 }
937 /// Marks current region as nowait (it has a 'nowait' clause).
938 void setNowaitRegion(bool IsNowait = true) {
939 getTopOfStack().NowaitRegion = IsNowait;
940 }
941 /// Returns true, if parent region is nowait (has associated
942 /// 'nowait' clause), false - otherwise.
943 bool isParentNowaitRegion() const {
944 if (const SharingMapTy *Parent = getSecondOnStackOrNull())
945 return Parent->NowaitRegion;
946 return false;
947 }
948 /// Marks current region as untied (it has a 'untied' clause).
949 void setUntiedRegion(bool IsUntied = true) {
950 getTopOfStack().UntiedRegion = IsUntied;
951 }
952 /// Return true if current region is untied.
953 bool isUntiedRegion() const {
954 const SharingMapTy *Top = getTopOfStackOrNull();
955 return Top ? Top->UntiedRegion : false;
956 }
957 /// Marks parent region as cancel region.
958 void setParentCancelRegion(bool Cancel = true) {
959 if (SharingMapTy *Parent = getSecondOnStackOrNull())
960 Parent->CancelRegion |= Cancel;
961 }
962 /// Return true if current region has inner cancel construct.
963 bool isCancelRegion() const {
964 const SharingMapTy *Top = getTopOfStackOrNull();
965 return Top ? Top->CancelRegion : false;
966 }
967
968 /// Mark that parent region already has scan directive.
969 void setParentHasScanDirective(SourceLocation Loc) {
970 if (SharingMapTy *Parent = getSecondOnStackOrNull())
971 Parent->PrevScanLocation = Loc;
972 }
973 /// Return true if current region has inner cancel construct.
974 bool doesParentHasScanDirective() const {
975 const SharingMapTy *Top = getSecondOnStackOrNull();
976 return Top ? Top->PrevScanLocation.isValid() : false;
977 }
978 /// Return true if current region has inner cancel construct.
979 SourceLocation getParentScanDirectiveLoc() const {
980 const SharingMapTy *Top = getSecondOnStackOrNull();
981 return Top ? Top->PrevScanLocation : SourceLocation();
982 }
983 /// Mark that parent region already has ordered directive.
984 void setParentHasOrderedDirective(SourceLocation Loc) {
985 if (SharingMapTy *Parent = getSecondOnStackOrNull())
986 Parent->PrevOrderedLocation = Loc;
987 }
988 /// Return true if current region has inner ordered construct.
989 bool doesParentHasOrderedDirective() const {
990 const SharingMapTy *Top = getSecondOnStackOrNull();
991 return Top ? Top->PrevOrderedLocation.isValid() : false;
992 }
993 /// Returns the location of the previously specified ordered directive.
994 SourceLocation getParentOrderedDirectiveLoc() const {
995 const SharingMapTy *Top = getSecondOnStackOrNull();
996 return Top ? Top->PrevOrderedLocation : SourceLocation();
997 }
998
999 /// Set collapse value for the region.
1000 void setAssociatedLoops(unsigned Val) {
1001 getTopOfStack().AssociatedLoops = Val;
1002 if (Val > 1)
1003 getTopOfStack().HasMutipleLoops = true;
1004 }
1005 /// Return collapse value for region.
1006 unsigned getAssociatedLoops() const {
1007 const SharingMapTy *Top = getTopOfStackOrNull();
1008 return Top ? Top->AssociatedLoops : 0;
1009 }
1010 /// Returns true if the construct is associated with multiple loops.
1011 bool hasMutipleLoops() const {
1012 const SharingMapTy *Top = getTopOfStackOrNull();
1013 return Top ? Top->HasMutipleLoops : false;
1014 }
1015
1016 /// Marks current target region as one with closely nested teams
1017 /// region.
1018 void setParentTeamsRegionLoc(SourceLocation TeamsRegionLoc) {
1019 if (SharingMapTy *Parent = getSecondOnStackOrNull())
1020 Parent->InnerTeamsRegionLoc = TeamsRegionLoc;
1021 }
1022 /// Returns true, if current region has closely nested teams region.
1023 bool hasInnerTeamsRegion() const {
1024 return getInnerTeamsRegionLoc().isValid();
1025 }
1026 /// Returns location of the nested teams region (if any).
1027 SourceLocation getInnerTeamsRegionLoc() const {
1028 const SharingMapTy *Top = getTopOfStackOrNull();
1029 return Top ? Top->InnerTeamsRegionLoc : SourceLocation();
1030 }
1031
1032 Scope *getCurScope() const {
1033 const SharingMapTy *Top = getTopOfStackOrNull();
1034 return Top ? Top->CurScope : nullptr;
1035 }
1036 void setContext(DeclContext *DC) { getTopOfStack().Context = DC; }
1037 SourceLocation getConstructLoc() const {
1038 const SharingMapTy *Top = getTopOfStackOrNull();
1039 return Top ? Top->ConstructLoc : SourceLocation();
1040 }
1041
1042 /// Do the check specified in \a Check to all component lists and return true
1043 /// if any issue is found.
1044 bool checkMappableExprComponentListsForDecl(
1045 const ValueDecl *VD, bool CurrentRegionOnly,
1046 const llvm::function_ref<
1047 bool(OMPClauseMappableExprCommon::MappableExprComponentListRef,
1048 OpenMPClauseKind)>
1049 Check) const {
1050 if (isStackEmpty())
1051 return false;
1052 auto SI = begin();
1053 auto SE = end();
1054
1055 if (SI == SE)
1056 return false;
1057
1058 if (CurrentRegionOnly)
1059 SE = std::next(x: SI);
1060 else
1061 std::advance(i&: SI, n: 1);
1062
1063 for (; SI != SE; ++SI) {
1064 auto MI = SI->MappedExprComponents.find(Val: VD);
1065 if (MI != SI->MappedExprComponents.end())
1066 for (OMPClauseMappableExprCommon::MappableExprComponentListRef L :
1067 MI->second.Components)
1068 if (Check(L, MI->second.Kind))
1069 return true;
1070 }
1071 return false;
1072 }
1073
1074 /// Do the check specified in \a Check to all component lists at a given level
1075 /// and return true if any issue is found.
1076 bool checkMappableExprComponentListsForDeclAtLevel(
1077 const ValueDecl *VD, unsigned Level,
1078 const llvm::function_ref<
1079 bool(OMPClauseMappableExprCommon::MappableExprComponentListRef,
1080 OpenMPClauseKind)>
1081 Check) const {
1082 if (getStackSize() <= Level)
1083 return false;
1084
1085 const SharingMapTy &StackElem = getStackElemAtLevel(Level);
1086 auto MI = StackElem.MappedExprComponents.find(Val: VD);
1087 if (MI != StackElem.MappedExprComponents.end())
1088 for (OMPClauseMappableExprCommon::MappableExprComponentListRef L :
1089 MI->second.Components)
1090 if (Check(L, MI->second.Kind))
1091 return true;
1092 return false;
1093 }
1094
1095 /// Create a new mappable expression component list associated with a given
1096 /// declaration and initialize it with the provided list of components.
1097 void addMappableExpressionComponents(
1098 const ValueDecl *VD,
1099 OMPClauseMappableExprCommon::MappableExprComponentListRef Components,
1100 OpenMPClauseKind WhereFoundClauseKind) {
1101 MappedExprComponentTy &MEC = getTopOfStack().MappedExprComponents[VD];
1102 // Create new entry and append the new components there.
1103 MEC.Components.resize(N: MEC.Components.size() + 1);
1104 MEC.Components.back().append(in_start: Components.begin(), in_end: Components.end());
1105 MEC.Kind = WhereFoundClauseKind;
1106 }
1107
1108 unsigned getNestingLevel() const {
1109 assert(!isStackEmpty());
1110 return getStackSize() - 1;
1111 }
1112 void addDoacrossDependClause(OMPClause *C, const OperatorOffsetTy &OpsOffs) {
1113 SharingMapTy *Parent = getSecondOnStackOrNull();
1114 assert(Parent && isOpenMPWorksharingDirective(Parent->Directive));
1115 Parent->DoacrossDepends.try_emplace(Key: C, Args: OpsOffs);
1116 }
1117 llvm::iterator_range<DoacrossClauseMapTy::const_iterator>
1118 getDoacrossDependClauses() const {
1119 const SharingMapTy &StackElem = getTopOfStack();
1120 if (isOpenMPWorksharingDirective(DKind: StackElem.Directive)) {
1121 const DoacrossClauseMapTy &Ref = StackElem.DoacrossDepends;
1122 return llvm::make_range(x: Ref.begin(), y: Ref.end());
1123 }
1124 return llvm::make_range(x: StackElem.DoacrossDepends.end(),
1125 y: StackElem.DoacrossDepends.end());
1126 }
1127
1128 // Store types of classes which have been explicitly mapped
1129 void addMappedClassesQualTypes(QualType QT) {
1130 SharingMapTy &StackElem = getTopOfStack();
1131 StackElem.MappedClassesQualTypes.insert(V: QT);
1132 }
1133
1134 // Return set of mapped classes types
1135 bool isClassPreviouslyMapped(QualType QT) const {
1136 const SharingMapTy &StackElem = getTopOfStack();
1137 return StackElem.MappedClassesQualTypes.contains(V: QT);
1138 }
1139
1140 /// Adds global declare target to the parent target region.
1141 void addToParentTargetRegionLinkGlobals(DeclRefExpr *E) {
1142 assert(*OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
1143 E->getDecl()) == OMPDeclareTargetDeclAttr::MT_Link &&
1144 "Expected declare target link global.");
1145 for (auto &Elem : *this) {
1146 if (isOpenMPTargetExecutionDirective(DKind: Elem.Directive)) {
1147 Elem.DeclareTargetLinkVarDecls.push_back(Elt: E);
1148 return;
1149 }
1150 }
1151 }
1152
1153 /// Returns the list of globals with declare target link if current directive
1154 /// is target.
1155 ArrayRef<DeclRefExpr *> getLinkGlobals() const {
1156 assert(isOpenMPTargetExecutionDirective(getCurrentDirective()) &&
1157 "Expected target executable directive.");
1158 return getTopOfStack().DeclareTargetLinkVarDecls;
1159 }
1160
1161 /// Adds list of allocators expressions.
1162 void addInnerAllocatorExpr(Expr *E) {
1163 getTopOfStack().InnerUsedAllocators.push_back(Elt: E);
1164 }
1165 /// Return list of used allocators.
1166 ArrayRef<Expr *> getInnerAllocators() const {
1167 return getTopOfStack().InnerUsedAllocators;
1168 }
1169 /// Marks the declaration as implicitly firstprivate nin the task-based
1170 /// regions.
1171 void addImplicitTaskFirstprivate(unsigned Level, Decl *D) {
1172 getStackElemAtLevel(Level).ImplicitTaskFirstprivates.insert(V: D);
1173 }
1174 /// Checks if the decl is implicitly firstprivate in the task-based region.
1175 bool isImplicitTaskFirstprivate(Decl *D) const {
1176 return getTopOfStack().ImplicitTaskFirstprivates.contains(V: D);
1177 }
1178
1179 /// Marks decl as used in uses_allocators clause as the allocator.
1180 void addUsesAllocatorsDecl(const Decl *D, UsesAllocatorsDeclKind Kind) {
1181 getTopOfStack().UsesAllocatorsDecls.try_emplace(Key: D, Args&: Kind);
1182 }
1183 /// Checks if specified decl is used in uses allocator clause as the
1184 /// allocator.
1185 std::optional<UsesAllocatorsDeclKind>
1186 isUsesAllocatorsDecl(unsigned Level, const Decl *D) const {
1187 const SharingMapTy &StackElem = getTopOfStack();
1188 auto I = StackElem.UsesAllocatorsDecls.find(Val: D);
1189 if (I == StackElem.UsesAllocatorsDecls.end())
1190 return std::nullopt;
1191 return I->getSecond();
1192 }
1193 std::optional<UsesAllocatorsDeclKind>
1194 isUsesAllocatorsDecl(const Decl *D) const {
1195 const SharingMapTy &StackElem = getTopOfStack();
1196 auto I = StackElem.UsesAllocatorsDecls.find(Val: D);
1197 if (I == StackElem.UsesAllocatorsDecls.end())
1198 return std::nullopt;
1199 return I->getSecond();
1200 }
1201
1202 void addDeclareMapperVarRef(Expr *Ref) {
1203 SharingMapTy &StackElem = getTopOfStack();
1204 StackElem.DeclareMapperVar = Ref;
1205 }
1206 const Expr *getDeclareMapperVarRef() const {
1207 const SharingMapTy *Top = getTopOfStackOrNull();
1208 return Top ? Top->DeclareMapperVar : nullptr;
1209 }
1210
1211 /// Add a new iterator variable.
1212 void addIteratorVarDecl(VarDecl *VD) {
1213 SharingMapTy &StackElem = getTopOfStack();
1214 StackElem.IteratorVarDecls.push_back(Elt: VD->getCanonicalDecl());
1215 }
1216 /// Check if variable declaration is an iterator VarDecl.
1217 bool isIteratorVarDecl(const VarDecl *VD) const {
1218 const SharingMapTy *Top = getTopOfStackOrNull();
1219 if (!Top)
1220 return false;
1221
1222 return llvm::is_contained(Range: Top->IteratorVarDecls, Element: VD->getCanonicalDecl());
1223 }
1224 /// get captured field from ImplicitDefaultFirstprivateFDs
1225 VarDecl *getImplicitFDCapExprDecl(const FieldDecl *FD) const {
1226 const_iterator I = begin();
1227 const_iterator EndI = end();
1228 size_t StackLevel = getStackSize();
1229 for (; I != EndI; ++I) {
1230 if (I->DefaultAttr == DSA_firstprivate || I->DefaultAttr == DSA_private)
1231 break;
1232 StackLevel--;
1233 }
1234 assert((StackLevel > 0 && I != EndI) || (StackLevel == 0 && I == EndI));
1235 if (I == EndI)
1236 return nullptr;
1237 for (const auto &IFD : I->ImplicitDefaultFirstprivateFDs)
1238 if (IFD.FD == FD && IFD.StackLevel == StackLevel)
1239 return IFD.VD;
1240 return nullptr;
1241 }
1242 /// Check if capture decl is field captured in ImplicitDefaultFirstprivateFDs
1243 bool isImplicitDefaultFirstprivateFD(VarDecl *VD) const {
1244 const_iterator I = begin();
1245 const_iterator EndI = end();
1246 for (; I != EndI; ++I)
1247 if (I->DefaultAttr == DSA_firstprivate || I->DefaultAttr == DSA_private)
1248 break;
1249 if (I == EndI)
1250 return false;
1251 for (const auto &IFD : I->ImplicitDefaultFirstprivateFDs)
1252 if (IFD.VD == VD)
1253 return true;
1254 return false;
1255 }
1256 /// Store capture FD info in ImplicitDefaultFirstprivateFDs
1257 void addImplicitDefaultFirstprivateFD(const FieldDecl *FD, VarDecl *VD) {
1258 iterator I = begin();
1259 const_iterator EndI = end();
1260 size_t StackLevel = getStackSize();
1261 for (; I != EndI; ++I) {
1262 if (I->DefaultAttr == DSA_private || I->DefaultAttr == DSA_firstprivate) {
1263 I->ImplicitDefaultFirstprivateFDs.emplace_back(Args&: FD, Args&: StackLevel, Args&: VD);
1264 break;
1265 }
1266 StackLevel--;
1267 }
1268 assert((StackLevel > 0 && I != EndI) || (StackLevel == 0 && I == EndI));
1269 }
1270 void setOrderedToBlockAssociated() {
1271 assert(getCurrentDirective() == OMPD_ordered_standalone);
1272 getTopOfStack().Directive = OMPD_ordered_blockassoc;
1273 }
1274};
1275
1276bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) {
1277 return isOpenMPParallelDirective(DKind) || isOpenMPTeamsDirective(DKind);
1278}
1279
1280bool isImplicitOrExplicitTaskingRegion(OpenMPDirectiveKind DKind) {
1281 return isImplicitTaskingRegion(DKind) || isOpenMPTaskingDirective(Kind: DKind) ||
1282 DKind == OMPD_unknown;
1283}
1284
1285} // namespace
1286
1287static const Expr *getExprAsWritten(const Expr *E) {
1288 if (const auto *FE = dyn_cast<FullExpr>(Val: E))
1289 E = FE->getSubExpr();
1290
1291 if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Val: E))
1292 E = MTE->getSubExpr();
1293
1294 while (const auto *Binder = dyn_cast<CXXBindTemporaryExpr>(Val: E))
1295 E = Binder->getSubExpr();
1296
1297 if (const auto *ICE = dyn_cast<ImplicitCastExpr>(Val: E))
1298 E = ICE->getSubExprAsWritten();
1299 return E->IgnoreParens();
1300}
1301
1302static Expr *getExprAsWritten(Expr *E) {
1303 return const_cast<Expr *>(getExprAsWritten(E: const_cast<const Expr *>(E)));
1304}
1305
1306static const ValueDecl *getCanonicalDecl(const ValueDecl *D) {
1307 if (const auto *CED = dyn_cast<OMPCapturedExprDecl>(Val: D))
1308 if (const auto *ME = dyn_cast<MemberExpr>(Val: getExprAsWritten(E: CED->getInit())))
1309 D = ME->getMemberDecl();
1310
1311 D = cast<ValueDecl>(Val: D->getCanonicalDecl());
1312 return D;
1313}
1314
1315static ValueDecl *getCanonicalDecl(ValueDecl *D) {
1316 return const_cast<ValueDecl *>(
1317 getCanonicalDecl(D: const_cast<const ValueDecl *>(D)));
1318}
1319
1320static std::string getOpenMPClauseNameForDiag(OpenMPClauseKind C) {
1321 if (C == OMPC_threadprivate)
1322 return getOpenMPClauseName(C).str() + " or thread local";
1323 return getOpenMPClauseName(C).str();
1324}
1325
1326DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter,
1327 ValueDecl *D) const {
1328 D = getCanonicalDecl(D);
1329 auto *VD = dyn_cast<VarDecl>(Val: D);
1330 const auto *FD = dyn_cast<FieldDecl>(Val: D);
1331 DSAVarData DVar;
1332 if (Iter == end()) {
1333 // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
1334 // in a region but not in construct]
1335 // File-scope or namespace-scope variables referenced in called routines
1336 // in the region are shared unless they appear in a threadprivate
1337 // directive.
1338 if (VD && !VD->isFunctionOrMethodVarDecl() && !isa<ParmVarDecl>(Val: VD))
1339 DVar.CKind = OMPC_shared;
1340
1341 // OpenMP [2.9.1.2, Data-sharing Attribute Rules for Variables Referenced
1342 // in a region but not in construct]
1343 // Variables with static storage duration that are declared in called
1344 // routines in the region are shared.
1345 if (VD && VD->hasGlobalStorage())
1346 DVar.CKind = OMPC_shared;
1347
1348 // Non-static data members are shared by default.
1349 if (FD)
1350 DVar.CKind = OMPC_shared;
1351
1352 return DVar;
1353 }
1354
1355 // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
1356 // in a Construct, C/C++, predetermined, p.1]
1357 // Variables with automatic storage duration that are declared in a scope
1358 // inside the construct are private.
1359 if (VD && isOpenMPLocal(D: VD, Iter) && VD->isLocalVarDecl() &&
1360 (VD->getStorageClass() == SC_Auto || VD->getStorageClass() == SC_None)) {
1361 DVar.CKind = OMPC_private;
1362 return DVar;
1363 }
1364
1365 DVar.DKind = Iter->Directive;
1366 // Explicitly specified attributes and local variables with predetermined
1367 // attributes.
1368 if (Iter->SharingMap.count(Val: D)) {
1369 const DSAInfo &Data = Iter->SharingMap.lookup(Val: D);
1370 DVar.RefExpr = Data.RefExpr.getPointer();
1371 DVar.PrivateCopy = Data.PrivateCopy;
1372 DVar.CKind = Data.Attributes;
1373 DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
1374 DVar.Modifier = Data.Modifier;
1375 DVar.AppliedToPointee = Data.AppliedToPointee;
1376 // For BindingDecls with OMPC_unknown, fall through to implicit DSA logic
1377 // instead of treating them as explicitly specified.
1378 if (!(isa<BindingDecl>(Val: D) && DVar.CKind == OMPC_unknown)) {
1379 return DVar;
1380 }
1381 }
1382
1383 DefaultDataSharingAttributes IterDA = Iter->DefaultAttr;
1384 switch (Iter->DefaultVCAttr) {
1385 case DSA_VC_aggregate:
1386 if (!D->getType()->isAggregateType())
1387 IterDA = DSA_none;
1388 break;
1389 case DSA_VC_pointer:
1390 if (!D->getType()->isPointerType())
1391 IterDA = DSA_none;
1392 break;
1393 case DSA_VC_scalar:
1394 if (!D->getType()->isScalarType())
1395 IterDA = DSA_none;
1396 break;
1397 case DSA_VC_all:
1398 break;
1399 }
1400
1401 // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
1402 // in a Construct, C/C++, implicitly determined, p.1]
1403 // In a parallel or task construct, the data-sharing attributes of these
1404 // variables are determined by the default clause, if present.
1405 switch (IterDA) {
1406 case DSA_shared:
1407 DVar.CKind = OMPC_shared;
1408 DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
1409 return DVar;
1410 case DSA_none:
1411 return DVar;
1412 case DSA_firstprivate:
1413 if (VD && VD->getStorageDuration() == SD_Static &&
1414 VD->getDeclContext()->isFileContext()) {
1415 DVar.CKind = OMPC_unknown;
1416 } else {
1417 DVar.CKind = OMPC_firstprivate;
1418 }
1419 DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
1420 return DVar;
1421 case DSA_private:
1422 // each variable with static storage duration that is declared
1423 // in a namespace or global scope and referenced in the construct,
1424 // and that does not have a predetermined data-sharing attribute
1425 if (VD && VD->getStorageDuration() == SD_Static &&
1426 VD->getDeclContext()->isFileContext()) {
1427 DVar.CKind = OMPC_unknown;
1428 } else {
1429 DVar.CKind = OMPC_private;
1430 }
1431 DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
1432 return DVar;
1433 case DSA_unspecified:
1434 // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
1435 // in a Construct, implicitly determined, p.2]
1436 // In a parallel construct, if no default clause is present, these
1437 // variables are shared.
1438 DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
1439 if ((isOpenMPParallelDirective(DKind: DVar.DKind) &&
1440 !isOpenMPTaskLoopDirective(DKind: DVar.DKind)) ||
1441 isOpenMPTeamsDirective(DKind: DVar.DKind)) {
1442 DVar.CKind = OMPC_shared;
1443 return DVar;
1444 }
1445
1446 // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
1447 // in a Construct, implicitly determined, p.4]
1448 // In a task construct, if no default clause is present, a variable that in
1449 // the enclosing context is determined to be shared by all implicit tasks
1450 // bound to the current team is shared.
1451 if (isOpenMPTaskingDirective(Kind: DVar.DKind)) {
1452 DSAVarData DVarTemp;
1453 const_iterator I = Iter, E = end();
1454 do {
1455 ++I;
1456 // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables
1457 // Referenced in a Construct, implicitly determined, p.6]
1458 // In a task construct, if no default clause is present, a variable
1459 // whose data-sharing attribute is not determined by the rules above is
1460 // firstprivate.
1461 DVarTemp = getDSA(Iter&: I, D);
1462 if (DVarTemp.CKind != OMPC_shared) {
1463 DVar.RefExpr = nullptr;
1464 DVar.CKind = OMPC_firstprivate;
1465 return DVar;
1466 }
1467 } while (I != E && !isImplicitTaskingRegion(DKind: I->Directive));
1468 DVar.CKind =
1469 (DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared;
1470 return DVar;
1471 }
1472 }
1473 // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
1474 // in a Construct, implicitly determined, p.3]
1475 // For constructs other than task, if no default clause is present, these
1476 // variables inherit their data-sharing attributes from the enclosing
1477 // context.
1478 return getDSA(Iter&: ++Iter, D);
1479}
1480
1481const Expr *DSAStackTy::addUniqueAligned(const ValueDecl *D,
1482 const Expr *NewDE) {
1483 assert(!isStackEmpty() && "Data sharing attributes stack is empty");
1484 D = getCanonicalDecl(D);
1485 SharingMapTy &StackElem = getTopOfStack();
1486 auto [It, Inserted] = StackElem.AlignedMap.try_emplace(Key: D, Args&: NewDE);
1487 if (Inserted) {
1488 assert(NewDE && "Unexpected nullptr expr to be added into aligned map");
1489 return nullptr;
1490 }
1491 assert(It->second && "Unexpected nullptr expr in the aligned map");
1492 return It->second;
1493}
1494
1495const Expr *DSAStackTy::addUniqueNontemporal(const ValueDecl *D,
1496 const Expr *NewDE) {
1497 assert(!isStackEmpty() && "Data sharing attributes stack is empty");
1498 D = getCanonicalDecl(D);
1499 SharingMapTy &StackElem = getTopOfStack();
1500 auto [It, Inserted] = StackElem.NontemporalMap.try_emplace(Key: D, Args&: NewDE);
1501 if (Inserted) {
1502 assert(NewDE && "Unexpected nullptr expr to be added into aligned map");
1503 return nullptr;
1504 }
1505 assert(It->second && "Unexpected nullptr expr in the aligned map");
1506 return It->second;
1507}
1508
1509void DSAStackTy::addLoopControlVariable(const ValueDecl *D, VarDecl *Capture) {
1510 assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
1511 D = getCanonicalDecl(D);
1512 SharingMapTy &StackElem = getTopOfStack();
1513 StackElem.LCVMap.try_emplace(
1514 Key: D, Args: LCDeclInfo(StackElem.LCVMap.size() + 1, Capture));
1515}
1516
1517const DSAStackTy::LCDeclInfo
1518DSAStackTy::isLoopControlVariable(const ValueDecl *D) const {
1519 assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
1520 D = getCanonicalDecl(D);
1521 const SharingMapTy &StackElem = getTopOfStack();
1522 auto It = StackElem.LCVMap.find(Val: D);
1523 if (It != StackElem.LCVMap.end())
1524 return It->second;
1525 return {0, nullptr};
1526}
1527
1528const DSAStackTy::LCDeclInfo
1529DSAStackTy::isLoopControlVariable(const ValueDecl *D, unsigned Level) const {
1530 assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
1531 D = getCanonicalDecl(D);
1532 for (unsigned I = Level + 1; I > 0; --I) {
1533 const SharingMapTy &StackElem = getStackElemAtLevel(Level: I - 1);
1534 auto It = StackElem.LCVMap.find(Val: D);
1535 if (It != StackElem.LCVMap.end())
1536 return It->second;
1537 }
1538 return {0, nullptr};
1539}
1540
1541const DSAStackTy::LCDeclInfo
1542DSAStackTy::isParentLoopControlVariable(const ValueDecl *D) const {
1543 const SharingMapTy *Parent = getSecondOnStackOrNull();
1544 assert(Parent && "Data-sharing attributes stack is empty");
1545 D = getCanonicalDecl(D);
1546 auto It = Parent->LCVMap.find(Val: D);
1547 if (It != Parent->LCVMap.end())
1548 return It->second;
1549 return {0, nullptr};
1550}
1551
1552const ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) const {
1553 const SharingMapTy *Parent = getSecondOnStackOrNull();
1554 assert(Parent && "Data-sharing attributes stack is empty");
1555 if (Parent->LCVMap.size() < I)
1556 return nullptr;
1557 for (const auto &Pair : Parent->LCVMap)
1558 if (Pair.second.first == I)
1559 return Pair.first;
1560 return nullptr;
1561}
1562
1563void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
1564 DeclRefExpr *PrivateCopy, unsigned Modifier,
1565 bool AppliedToPointee) {
1566 D = getCanonicalDecl(D);
1567 if (A == OMPC_threadprivate) {
1568 DSAInfo &Data = Threadprivates[D];
1569 Data.Attributes = A;
1570 Data.RefExpr.setPointer(E);
1571 Data.PrivateCopy = nullptr;
1572 Data.Modifier = Modifier;
1573 } else if (A == OMPC_groupprivate) {
1574 DSAInfo &Data = Groupprivates[D];
1575 Data.Attributes = A;
1576 Data.RefExpr.setPointer(E);
1577 Data.PrivateCopy = nullptr;
1578 Data.Modifier = Modifier;
1579 } else {
1580 DSAInfo &Data = getTopOfStack().SharingMap[D];
1581 assert(Data.Attributes == OMPC_unknown || (A == Data.Attributes) ||
1582 (A == OMPC_firstprivate && Data.Attributes == OMPC_lastprivate) ||
1583 (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) ||
1584 (isLoopControlVariable(D).first && A == OMPC_private));
1585 Data.Modifier = Modifier;
1586 if (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) {
1587 Data.RefExpr.setInt(/*IntVal=*/true);
1588 return;
1589 }
1590 const bool IsLastprivate =
1591 A == OMPC_lastprivate || Data.Attributes == OMPC_lastprivate;
1592 Data.Attributes = A;
1593 Data.RefExpr.setPointerAndInt(PtrVal: E, IntVal: IsLastprivate);
1594 Data.PrivateCopy = PrivateCopy;
1595 Data.AppliedToPointee = AppliedToPointee;
1596 if (PrivateCopy) {
1597 DSAInfo &Data = getTopOfStack().SharingMap[PrivateCopy->getDecl()];
1598 Data.Modifier = Modifier;
1599 Data.Attributes = A;
1600 Data.RefExpr.setPointerAndInt(PtrVal: PrivateCopy, IntVal: IsLastprivate);
1601 Data.PrivateCopy = nullptr;
1602 Data.AppliedToPointee = AppliedToPointee;
1603 }
1604 }
1605}
1606
1607/// Build a variable declaration for OpenMP loop iteration variable.
1608static VarDecl *buildVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type,
1609 StringRef Name, const AttrVec *Attrs = nullptr,
1610 DeclRefExpr *OrigRef = nullptr) {
1611 DeclContext *DC = SemaRef.CurContext;
1612 IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name);
1613 TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(T: Type, Loc);
1614 auto *Decl =
1615 VarDecl::Create(C&: SemaRef.Context, DC, StartLoc: Loc, IdLoc: Loc, Id: II, T: Type, TInfo, S: SC_None);
1616 if (Attrs) {
1617 for (specific_attr_iterator<AlignedAttr> I(Attrs->begin()), E(Attrs->end());
1618 I != E; ++I)
1619 Decl->addAttr(A: *I);
1620 }
1621 Decl->setImplicit();
1622 if (OrigRef) {
1623 Decl->addAttr(
1624 A: OMPReferencedVarAttr::CreateImplicit(Ctx&: SemaRef.Context, Ref: OrigRef));
1625 }
1626 return Decl;
1627}
1628
1629static DeclRefExpr *buildDeclRefExpr(Sema &S, VarDecl *D, QualType Ty,
1630 SourceLocation Loc,
1631 bool RefersToCapture = false) {
1632 D->setReferenced();
1633 D->markUsed(C&: S.Context);
1634 return DeclRefExpr::Create(Context: S.getASTContext(), QualifierLoc: NestedNameSpecifierLoc(),
1635 TemplateKWLoc: SourceLocation(), D, RefersToEnclosingVariableOrCapture: RefersToCapture, NameLoc: Loc, T: Ty,
1636 VK: VK_LValue);
1637}
1638
1639void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR,
1640 BinaryOperatorKind BOK) {
1641 D = getCanonicalDecl(D);
1642 assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
1643 assert(
1644 getTopOfStack().SharingMap[D].Attributes == OMPC_reduction &&
1645 "Additional reduction info may be specified only for reduction items.");
1646 ReductionData &ReductionData = getTopOfStack().ReductionMap[D];
1647 assert(ReductionData.ReductionRange.isInvalid() &&
1648 (getTopOfStack().Directive == OMPD_taskgroup ||
1649 ((isOpenMPParallelDirective(getTopOfStack().Directive) ||
1650 isOpenMPWorksharingDirective(getTopOfStack().Directive)) &&
1651 !isOpenMPSimdDirective(getTopOfStack().Directive))) &&
1652 "Additional reduction info may be specified only once for reduction "
1653 "items.");
1654 ReductionData.set(BO: BOK, RR: SR);
1655 Expr *&TaskgroupReductionRef = getTopOfStack().TaskgroupReductionRef;
1656 if (!TaskgroupReductionRef) {
1657 VarDecl *VD = buildVarDecl(SemaRef, Loc: SR.getBegin(),
1658 Type: SemaRef.Context.VoidPtrTy, Name: ".task_red.");
1659 TaskgroupReductionRef =
1660 buildDeclRefExpr(S&: SemaRef, D: VD, Ty: SemaRef.Context.VoidPtrTy, Loc: SR.getBegin());
1661 }
1662}
1663
1664void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR,
1665 const Expr *ReductionRef) {
1666 D = getCanonicalDecl(D);
1667 assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
1668 assert(
1669 getTopOfStack().SharingMap[D].Attributes == OMPC_reduction &&
1670 "Additional reduction info may be specified only for reduction items.");
1671 ReductionData &ReductionData = getTopOfStack().ReductionMap[D];
1672 assert(ReductionData.ReductionRange.isInvalid() &&
1673 (getTopOfStack().Directive == OMPD_taskgroup ||
1674 ((isOpenMPParallelDirective(getTopOfStack().Directive) ||
1675 isOpenMPWorksharingDirective(getTopOfStack().Directive)) &&
1676 !isOpenMPSimdDirective(getTopOfStack().Directive))) &&
1677 "Additional reduction info may be specified only once for reduction "
1678 "items.");
1679 ReductionData.set(RefExpr: ReductionRef, RR: SR);
1680 Expr *&TaskgroupReductionRef = getTopOfStack().TaskgroupReductionRef;
1681 if (!TaskgroupReductionRef) {
1682 VarDecl *VD = buildVarDecl(SemaRef, Loc: SR.getBegin(),
1683 Type: SemaRef.Context.VoidPtrTy, Name: ".task_red.");
1684 TaskgroupReductionRef =
1685 buildDeclRefExpr(S&: SemaRef, D: VD, Ty: SemaRef.Context.VoidPtrTy, Loc: SR.getBegin());
1686 }
1687}
1688
1689const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
1690 const ValueDecl *D, SourceRange &SR, BinaryOperatorKind &BOK,
1691 Expr *&TaskgroupDescriptor) const {
1692 D = getCanonicalDecl(D);
1693 assert(!isStackEmpty() && "Data-sharing attributes stack is empty.");
1694 for (const_iterator I = begin() + 1, E = end(); I != E; ++I) {
1695 const DSAInfo &Data = I->SharingMap.lookup(Val: D);
1696 if (Data.Attributes != OMPC_reduction ||
1697 Data.Modifier != OMPC_REDUCTION_task)
1698 continue;
1699 const ReductionData &ReductionData = I->ReductionMap.lookup(Val: D);
1700 if (!ReductionData.ReductionOp ||
1701 isa<const Expr *>(Val: ReductionData.ReductionOp))
1702 return DSAVarData();
1703 SR = ReductionData.ReductionRange;
1704 BOK = cast<ReductionData::BOKPtrType>(Val: ReductionData.ReductionOp);
1705 assert(I->TaskgroupReductionRef && "taskgroup reduction reference "
1706 "expression for the descriptor is not "
1707 "set.");
1708 TaskgroupDescriptor = I->TaskgroupReductionRef;
1709 return DSAVarData(I->Directive, OMPC_reduction, Data.RefExpr.getPointer(),
1710 Data.PrivateCopy, I->DefaultAttrLoc, OMPC_REDUCTION_task,
1711 /*AppliedToPointee=*/false);
1712 }
1713 return DSAVarData();
1714}
1715
1716const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
1717 const ValueDecl *D, SourceRange &SR, const Expr *&ReductionRef,
1718 Expr *&TaskgroupDescriptor) const {
1719 D = getCanonicalDecl(D);
1720 assert(!isStackEmpty() && "Data-sharing attributes stack is empty.");
1721 for (const_iterator I = begin() + 1, E = end(); I != E; ++I) {
1722 const DSAInfo &Data = I->SharingMap.lookup(Val: D);
1723 if (Data.Attributes != OMPC_reduction ||
1724 Data.Modifier != OMPC_REDUCTION_task)
1725 continue;
1726 const ReductionData &ReductionData = I->ReductionMap.lookup(Val: D);
1727 if (!ReductionData.ReductionOp ||
1728 !isa<const Expr *>(Val: ReductionData.ReductionOp))
1729 return DSAVarData();
1730 SR = ReductionData.ReductionRange;
1731 ReductionRef = cast<const Expr *>(Val: ReductionData.ReductionOp);
1732 assert(I->TaskgroupReductionRef && "taskgroup reduction reference "
1733 "expression for the descriptor is not "
1734 "set.");
1735 TaskgroupDescriptor = I->TaskgroupReductionRef;
1736 return DSAVarData(I->Directive, OMPC_reduction, Data.RefExpr.getPointer(),
1737 Data.PrivateCopy, I->DefaultAttrLoc, OMPC_REDUCTION_task,
1738 /*AppliedToPointee=*/false);
1739 }
1740 return DSAVarData();
1741}
1742
1743bool DSAStackTy::isOpenMPLocal(VarDecl *D, const_iterator I) const {
1744 D = D->getCanonicalDecl();
1745 for (const_iterator E = end(); I != E; ++I) {
1746 if (isImplicitOrExplicitTaskingRegion(DKind: I->Directive) ||
1747 isOpenMPTargetExecutionDirective(DKind: I->Directive)) {
1748 if (I->CurScope) {
1749 Scope *TopScope = I->CurScope->getParent();
1750 Scope *CurScope = getCurScope();
1751 while (CurScope && CurScope != TopScope && !CurScope->isDeclScope(D))
1752 CurScope = CurScope->getParent();
1753 return CurScope != TopScope;
1754 }
1755 for (DeclContext *DC = D->getDeclContext(); DC; DC = DC->getParent())
1756 if (I->Context == DC)
1757 return true;
1758 return false;
1759 }
1760 }
1761 return false;
1762}
1763
1764static bool isConstNotMutableType(Sema &SemaRef, QualType Type,
1765 bool AcceptIfMutable = true,
1766 bool *IsClassType = nullptr) {
1767 ASTContext &Context = SemaRef.getASTContext();
1768 Type = Type.getNonReferenceType().getCanonicalType();
1769 bool IsConstant = Type.isConstant(Ctx: Context);
1770 Type = Context.getBaseElementType(QT: Type);
1771 const CXXRecordDecl *RD = AcceptIfMutable && SemaRef.getLangOpts().CPlusPlus
1772 ? Type->getAsCXXRecordDecl()
1773 : nullptr;
1774 if (const auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(Val: RD))
1775 if (const ClassTemplateDecl *CTD = CTSD->getSpecializedTemplate())
1776 RD = CTD->getTemplatedDecl();
1777 if (IsClassType)
1778 *IsClassType = RD;
1779 return IsConstant && !(SemaRef.getLangOpts().CPlusPlus && RD &&
1780 RD->hasDefinition() && RD->hasMutableFields());
1781}
1782
1783static bool rejectConstNotMutableType(Sema &SemaRef, const ValueDecl *D,
1784 QualType Type, OpenMPClauseKind CKind,
1785 SourceLocation ELoc,
1786 bool AcceptIfMutable = true,
1787 bool ListItemNotVar = false) {
1788 ASTContext &Context = SemaRef.getASTContext();
1789 bool IsClassType;
1790 if (isConstNotMutableType(SemaRef, Type, AcceptIfMutable, IsClassType: &IsClassType)) {
1791 unsigned Diag = ListItemNotVar ? diag::err_omp_const_list_item
1792 : IsClassType ? diag::err_omp_const_not_mutable_variable
1793 : diag::err_omp_const_variable;
1794 SemaRef.Diag(Loc: ELoc, DiagID: Diag) << getOpenMPClauseNameForDiag(C: CKind);
1795 if (!ListItemNotVar && D) {
1796 const VarDecl *VD = dyn_cast<VarDecl>(Val: D);
1797 bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
1798 VarDecl::DeclarationOnly;
1799 SemaRef.Diag(Loc: D->getLocation(),
1800 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
1801 << D;
1802 }
1803 return true;
1804 }
1805 return false;
1806}
1807
1808const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
1809 bool FromParent) {
1810 D = getCanonicalDecl(D);
1811 DSAVarData DVar;
1812
1813 auto *VD = dyn_cast<VarDecl>(Val: D);
1814 auto TI = Threadprivates.find(Val: D);
1815 if (TI != Threadprivates.end()) {
1816 DVar.RefExpr = TI->getSecond().RefExpr.getPointer();
1817 DVar.CKind = OMPC_threadprivate;
1818 DVar.Modifier = TI->getSecond().Modifier;
1819 return DVar;
1820 }
1821 if (VD && VD->hasAttr<OMPThreadPrivateDeclAttr>()) {
1822 DVar.RefExpr = buildDeclRefExpr(
1823 S&: SemaRef, D: VD, Ty: D->getType().getNonReferenceType(),
1824 Loc: VD->getAttr<OMPThreadPrivateDeclAttr>()->getLocation());
1825 DVar.CKind = OMPC_threadprivate;
1826 addDSA(D, E: DVar.RefExpr, A: OMPC_threadprivate);
1827 return DVar;
1828 }
1829 // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
1830 // in a Construct, C/C++, predetermined, p.1]
1831 // Variables appearing in threadprivate directives are threadprivate.
1832 if ((VD && VD->getTLSKind() != VarDecl::TLS_None &&
1833 !(VD->hasAttr<OMPThreadPrivateDeclAttr>() &&
1834 SemaRef.getLangOpts().OpenMPUseTLS &&
1835 SemaRef.getASTContext().getTargetInfo().isTLSSupported())) ||
1836 (VD && VD->getStorageClass() == SC_Register &&
1837 VD->hasAttr<AsmLabelAttr>() && !VD->isLocalVarDecl())) {
1838 DVar.RefExpr = buildDeclRefExpr(
1839 S&: SemaRef, D: VD, Ty: D->getType().getNonReferenceType(), Loc: D->getLocation());
1840 DVar.CKind = OMPC_threadprivate;
1841 addDSA(D, E: DVar.RefExpr, A: OMPC_threadprivate);
1842 return DVar;
1843 }
1844 if (SemaRef.getLangOpts().OpenMPCUDAMode && VD &&
1845 VD->isLocalVarDeclOrParm() && !isStackEmpty() &&
1846 !isLoopControlVariable(D).first) {
1847 const_iterator IterTarget =
1848 std::find_if(first: begin(), last: end(), pred: [](const SharingMapTy &Data) {
1849 return isOpenMPTargetExecutionDirective(DKind: Data.Directive);
1850 });
1851 if (IterTarget != end()) {
1852 const_iterator ParentIterTarget = IterTarget + 1;
1853 for (const_iterator Iter = begin(); Iter != ParentIterTarget; ++Iter) {
1854 if (isOpenMPLocal(D: VD, I: Iter)) {
1855 DVar.RefExpr =
1856 buildDeclRefExpr(S&: SemaRef, D: VD, Ty: D->getType().getNonReferenceType(),
1857 Loc: D->getLocation());
1858 DVar.CKind = OMPC_threadprivate;
1859 return DVar;
1860 }
1861 }
1862 if (!isClauseParsingMode() || IterTarget != begin()) {
1863 auto DSAIter = IterTarget->SharingMap.find(Val: D);
1864 if (DSAIter != IterTarget->SharingMap.end() &&
1865 isOpenMPPrivate(Kind: DSAIter->getSecond().Attributes)) {
1866 DVar.RefExpr = DSAIter->getSecond().RefExpr.getPointer();
1867 DVar.CKind = OMPC_threadprivate;
1868 return DVar;
1869 }
1870 const_iterator End = end();
1871 if (!SemaRef.OpenMP().isOpenMPCapturedByRef(
1872 D, Level: std::distance(first: ParentIterTarget, last: End),
1873 /*OpenMPCaptureLevel=*/0)) {
1874 DVar.RefExpr =
1875 buildDeclRefExpr(S&: SemaRef, D: VD, Ty: D->getType().getNonReferenceType(),
1876 Loc: IterTarget->ConstructLoc);
1877 DVar.CKind = OMPC_threadprivate;
1878 return DVar;
1879 }
1880 }
1881 }
1882 }
1883
1884 if (isStackEmpty())
1885 // Not in OpenMP execution region and top scope was already checked.
1886 return DVar;
1887
1888 // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
1889 // in a Construct, C/C++, predetermined, p.4]
1890 // Static data members are shared.
1891 // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
1892 // in a Construct, C/C++, predetermined, p.7]
1893 // Variables with static storage duration that are declared in a scope
1894 // inside the construct are shared.
1895 if (VD && VD->isStaticDataMember()) {
1896 // Check for explicitly specified attributes.
1897 const_iterator I = begin();
1898 const_iterator EndI = end();
1899 if (FromParent && I != EndI)
1900 ++I;
1901 if (I != EndI) {
1902 auto It = I->SharingMap.find(Val: D);
1903 if (It != I->SharingMap.end()) {
1904 const DSAInfo &Data = It->getSecond();
1905 DVar.RefExpr = Data.RefExpr.getPointer();
1906 DVar.PrivateCopy = Data.PrivateCopy;
1907 DVar.CKind = Data.Attributes;
1908 DVar.ImplicitDSALoc = I->DefaultAttrLoc;
1909 DVar.DKind = I->Directive;
1910 DVar.Modifier = Data.Modifier;
1911 DVar.AppliedToPointee = Data.AppliedToPointee;
1912 return DVar;
1913 }
1914 }
1915
1916 DVar.CKind = OMPC_shared;
1917 return DVar;
1918 }
1919
1920 auto &&MatchesAlways = [](OpenMPDirectiveKind) { return true; };
1921 // The predetermined shared attribute for const-qualified types having no
1922 // mutable members was removed after OpenMP 3.1.
1923 if (SemaRef.LangOpts.OpenMP <= 31) {
1924 // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
1925 // in a Construct, C/C++, predetermined, p.6]
1926 // Variables with const qualified type having no mutable member are
1927 // shared.
1928 if (isConstNotMutableType(SemaRef, Type: D->getType())) {
1929 // Variables with const-qualified type having no mutable member may be
1930 // listed in a firstprivate clause, even if they are static data members.
1931 DSAVarData DVarTemp = hasInnermostDSA(
1932 D,
1933 CPred: [](OpenMPClauseKind C, bool) {
1934 return C == OMPC_firstprivate || C == OMPC_shared;
1935 },
1936 DPred: MatchesAlways, FromParent);
1937 if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr)
1938 return DVarTemp;
1939
1940 DVar.CKind = OMPC_shared;
1941 return DVar;
1942 }
1943 }
1944
1945 // Explicitly specified attributes and local variables with predetermined
1946 // attributes.
1947 const_iterator I = begin();
1948 const_iterator EndI = end();
1949 if (FromParent && I != EndI)
1950 ++I;
1951 if (I == EndI)
1952 return DVar;
1953 auto It = I->SharingMap.find(Val: D);
1954 if (It != I->SharingMap.end()) {
1955 const DSAInfo &Data = It->getSecond();
1956 DVar.RefExpr = Data.RefExpr.getPointer();
1957 DVar.PrivateCopy = Data.PrivateCopy;
1958 DVar.CKind = Data.Attributes;
1959 DVar.ImplicitDSALoc = I->DefaultAttrLoc;
1960 DVar.DKind = I->Directive;
1961 DVar.Modifier = Data.Modifier;
1962 DVar.AppliedToPointee = Data.AppliedToPointee;
1963 }
1964
1965 return DVar;
1966}
1967
1968const DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D,
1969 bool FromParent) const {
1970 if (isStackEmpty()) {
1971 const_iterator I;
1972 return getDSA(Iter&: I, D);
1973 }
1974 D = getCanonicalDecl(D);
1975 const_iterator StartI = begin();
1976 const_iterator EndI = end();
1977 if (FromParent && StartI != EndI)
1978 ++StartI;
1979 return getDSA(Iter&: StartI, D);
1980}
1981
1982const DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D,
1983 unsigned Level) const {
1984 if (getStackSize() <= Level)
1985 return DSAVarData();
1986 D = getCanonicalDecl(D);
1987 const_iterator StartI = std::next(x: begin(), n: getStackSize() - 1 - Level);
1988 return getDSA(Iter&: StartI, D);
1989}
1990
1991const DSAStackTy::DSAVarData
1992DSAStackTy::hasDSA(ValueDecl *D,
1993 const llvm::function_ref<bool(OpenMPClauseKind, bool,
1994 DefaultDataSharingAttributes)>
1995 CPred,
1996 const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred,
1997 bool FromParent) const {
1998 if (isStackEmpty())
1999 return {};
2000 D = getCanonicalDecl(D);
2001 const_iterator I = begin();
2002 const_iterator EndI = end();
2003 if (FromParent && I != EndI)
2004 ++I;
2005 for (; I != EndI; ++I) {
2006 if (!DPred(I->Directive) &&
2007 !isImplicitOrExplicitTaskingRegion(DKind: I->Directive))
2008 continue;
2009 const_iterator NewI = I;
2010 DSAVarData DVar = getDSA(Iter&: NewI, D);
2011 if (I == NewI && CPred(DVar.CKind, DVar.AppliedToPointee, I->DefaultAttr))
2012 return DVar;
2013 }
2014 return {};
2015}
2016
2017const DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA(
2018 ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind, bool)> CPred,
2019 const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred,
2020 bool FromParent) const {
2021 if (isStackEmpty())
2022 return {};
2023 D = getCanonicalDecl(D);
2024 const_iterator StartI = begin();
2025 const_iterator EndI = end();
2026 if (FromParent && StartI != EndI)
2027 ++StartI;
2028 if (StartI == EndI || !DPred(StartI->Directive))
2029 return {};
2030 const_iterator NewI = StartI;
2031 DSAVarData DVar = getDSA(Iter&: NewI, D);
2032 return (NewI == StartI && CPred(DVar.CKind, DVar.AppliedToPointee))
2033 ? DVar
2034 : DSAVarData();
2035}
2036
2037bool DSAStackTy::hasExplicitDSA(
2038 const ValueDecl *D,
2039 const llvm::function_ref<bool(OpenMPClauseKind, bool)> CPred,
2040 unsigned Level, bool NotLastprivate) const {
2041 if (getStackSize() <= Level)
2042 return false;
2043 D = getCanonicalDecl(D);
2044 const SharingMapTy &StackElem = getStackElemAtLevel(Level);
2045 auto I = StackElem.SharingMap.find(Val: D);
2046 if (I != StackElem.SharingMap.end() && I->getSecond().RefExpr.getPointer() &&
2047 CPred(I->getSecond().Attributes, I->getSecond().AppliedToPointee) &&
2048 (!NotLastprivate || !I->getSecond().RefExpr.getInt()))
2049 return true;
2050 // Check predetermined rules for the loop control variables.
2051 auto LI = StackElem.LCVMap.find(Val: D);
2052 if (LI != StackElem.LCVMap.end())
2053 return CPred(OMPC_private, /*AppliedToPointee=*/false);
2054 return false;
2055}
2056
2057bool DSAStackTy::hasExplicitDirective(
2058 const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred,
2059 unsigned Level) const {
2060 if (getStackSize() <= Level)
2061 return false;
2062 const SharingMapTy &StackElem = getStackElemAtLevel(Level);
2063 return DPred(StackElem.Directive);
2064}
2065
2066bool DSAStackTy::hasDirective(
2067 const llvm::function_ref<bool(OpenMPDirectiveKind,
2068 const DeclarationNameInfo &, SourceLocation)>
2069 DPred,
2070 bool FromParent) const {
2071 // We look only in the enclosing region.
2072 size_t Skip = FromParent ? 2 : 1;
2073 for (const_iterator I = begin() + std::min(a: Skip, b: getStackSize()), E = end();
2074 I != E; ++I) {
2075 if (DPred(I->Directive, I->DirectiveName, I->ConstructLoc))
2076 return true;
2077 }
2078 return false;
2079}
2080
2081void SemaOpenMP::InitDataSharingAttributesStack() {
2082 VarDataSharingAttributesStack = new DSAStackTy(SemaRef);
2083}
2084
2085#define DSAStack static_cast<DSAStackTy *>(VarDataSharingAttributesStack)
2086
2087void SemaOpenMP::addRequiresDecl(OMPRequiresDecl *D) {
2088 DSAStack->addRequiresDecl(RD: D);
2089}
2090
2091ArrayRef<const OMPRequiresDecl *> SemaOpenMP::getRequiresDecls() const {
2092 return DSAStack->getRequiresDecls();
2093}
2094
2095void SemaOpenMP::pushOpenMPFunctionRegion() { DSAStack->pushFunction(); }
2096
2097void SemaOpenMP::popOpenMPFunctionRegion(const FunctionScopeInfo *OldFSI) {
2098 DSAStack->popFunction(OldFSI);
2099}
2100
2101static bool isOpenMPDeviceDelayedContext(Sema &S) {
2102 assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsTargetDevice &&
2103 "Expected OpenMP device compilation.");
2104 return !S.OpenMP().isInOpenMPTargetExecutionDirective();
2105}
2106
2107namespace {
2108/// Status of the function emission on the host/device.
2109enum class FunctionEmissionStatus {
2110 Emitted,
2111 Discarded,
2112 Unknown,
2113};
2114} // anonymous namespace
2115
2116SemaBase::SemaDiagnosticBuilder
2117SemaOpenMP::diagIfOpenMPDeviceCode(SourceLocation Loc, unsigned DiagID,
2118 const FunctionDecl *FD) {
2119 assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsTargetDevice &&
2120 "Expected OpenMP device compilation.");
2121
2122 SemaDiagnosticBuilder::Kind Kind = SemaDiagnosticBuilder::K_Nop;
2123 if (FD) {
2124 Sema::FunctionEmissionStatus FES = SemaRef.getEmissionStatus(Decl: FD);
2125 switch (FES) {
2126 case Sema::FunctionEmissionStatus::Emitted:
2127 Kind = SemaDiagnosticBuilder::K_Immediate;
2128 break;
2129 case Sema::FunctionEmissionStatus::Unknown:
2130 // TODO: We should always delay diagnostics here in case a target
2131 // region is in a function we do not emit. However, as the
2132 // current diagnostics are associated with the function containing
2133 // the target region and we do not emit that one, we would miss out
2134 // on diagnostics for the target region itself. We need to anchor
2135 // the diagnostics with the new generated function *or* ensure we
2136 // emit diagnostics associated with the surrounding function.
2137 Kind = isOpenMPDeviceDelayedContext(S&: SemaRef)
2138 ? SemaDiagnosticBuilder::K_Deferred
2139 : SemaDiagnosticBuilder::K_Immediate;
2140 break;
2141 case Sema::FunctionEmissionStatus::TemplateDiscarded:
2142 case Sema::FunctionEmissionStatus::OMPDiscarded:
2143 Kind = SemaDiagnosticBuilder::K_Nop;
2144 break;
2145 case Sema::FunctionEmissionStatus::CUDADiscarded:
2146 llvm_unreachable("CUDADiscarded unexpected in OpenMP device compilation");
2147 break;
2148 }
2149 }
2150
2151 return SemaDiagnosticBuilder(Kind, Loc, DiagID, FD, SemaRef);
2152}
2153
2154SemaBase::SemaDiagnosticBuilder
2155SemaOpenMP::diagIfOpenMPHostCode(SourceLocation Loc, unsigned DiagID,
2156 const FunctionDecl *FD) {
2157 assert(getLangOpts().OpenMP && !getLangOpts().OpenMPIsTargetDevice &&
2158 "Expected OpenMP host compilation.");
2159
2160 SemaDiagnosticBuilder::Kind Kind = SemaDiagnosticBuilder::K_Nop;
2161 if (FD) {
2162 Sema::FunctionEmissionStatus FES = SemaRef.getEmissionStatus(Decl: FD);
2163 switch (FES) {
2164 case Sema::FunctionEmissionStatus::Emitted:
2165 Kind = SemaDiagnosticBuilder::K_Immediate;
2166 break;
2167 case Sema::FunctionEmissionStatus::Unknown:
2168 Kind = SemaDiagnosticBuilder::K_Deferred;
2169 break;
2170 case Sema::FunctionEmissionStatus::TemplateDiscarded:
2171 case Sema::FunctionEmissionStatus::OMPDiscarded:
2172 case Sema::FunctionEmissionStatus::CUDADiscarded:
2173 Kind = SemaDiagnosticBuilder::K_Nop;
2174 break;
2175 }
2176 }
2177
2178 return SemaDiagnosticBuilder(Kind, Loc, DiagID, FD, SemaRef);
2179}
2180
2181static OpenMPDefaultmapClauseKind
2182getVariableCategoryFromDecl(const LangOptions &LO, const ValueDecl *VD) {
2183 if (LO.OpenMP <= 45) {
2184 if (VD->getType().getNonReferenceType()->isScalarType())
2185 return OMPC_DEFAULTMAP_scalar;
2186 return OMPC_DEFAULTMAP_aggregate;
2187 }
2188 if (VD->getType().getNonReferenceType()->isAnyPointerType())
2189 return OMPC_DEFAULTMAP_pointer;
2190 if (VD->getType().getNonReferenceType()->isScalarType())
2191 return OMPC_DEFAULTMAP_scalar;
2192 return OMPC_DEFAULTMAP_aggregate;
2193}
2194
2195bool SemaOpenMP::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
2196 unsigned OpenMPCaptureLevel) const {
2197 assert(getLangOpts().OpenMP && "OpenMP is not allowed");
2198
2199 ASTContext &Ctx = getASTContext();
2200 bool IsByRef = true;
2201
2202 // Find the directive that is associated with the provided scope.
2203 D = cast<ValueDecl>(Val: D->getCanonicalDecl());
2204 QualType Ty = D->getType();
2205 if (const auto *BD = dyn_cast<BindingDecl>(Val: D))
2206 Ty = BD->getDecomposedDecl()->getType();
2207
2208 bool IsVariableUsedInMapClause = false;
2209 if (DSAStack->hasExplicitDirective(DPred: isOpenMPTargetExecutionDirective, Level)) {
2210 // This table summarizes how a given variable should be passed to the device
2211 // given its type and the clauses where it appears. This table is based on
2212 // the description in OpenMP 4.5 [2.10.4, target Construct] and
2213 // OpenMP 4.5 [2.15.5, Data-mapping Attribute Rules and Clauses].
2214 //
2215 // =========================================================================
2216 // | type | defaultmap | pvt | first | is_device_ptr | map | res. |
2217 // | |(tofrom:scalar)| | pvt | |has_dv_adr| |
2218 // =========================================================================
2219 // | scl | | | | - | | bycopy|
2220 // | scl | | - | x | - | - | bycopy|
2221 // | scl | | x | - | - | - | null |
2222 // | scl | x | | | - | | byref |
2223 // | scl | x | - | x | - | - | bycopy|
2224 // | scl | x | x | - | - | - | null |
2225 // | scl | | - | - | - | x | byref |
2226 // | scl | x | - | - | - | x | byref |
2227 //
2228 // | agg | n.a. | | | - | | byref |
2229 // | agg | n.a. | - | x | - | - | byref |
2230 // | agg | n.a. | x | - | - | - | null |
2231 // | agg | n.a. | - | - | - | x | byref |
2232 // | agg | n.a. | - | - | - | x[] | byref |
2233 //
2234 // | ptr | n.a. | | | - | | bycopy|
2235 // | ptr | n.a. | - | x | - | - | bycopy|
2236 // | ptr | n.a. | x | - | - | - | null |
2237 // | ptr | n.a. | - | - | - | x | byref |
2238 // | ptr | n.a. | - | - | - | x, x[] | bycopy|
2239 // | ptr | n.a. | - | - | - | x[] | bycopy|
2240 // | ptr | n.a. | - | - | x | | bycopy|
2241 // | ptr | n.a. | - | - | x | x | bycopy|
2242 // | ptr | n.a. | - | - | x | x[] | bycopy|
2243 // =========================================================================
2244 // Legend:
2245 // scl - scalar
2246 // ptr - pointer
2247 // agg - aggregate
2248 // x - applies
2249 // - - invalid in this combination
2250 // [] - mapped with an array section
2251 // byref - should be mapped by reference
2252 // byval - should be mapped by value
2253 // null - initialize a local variable to null on the device
2254 //
2255 // Observations:
2256 // - All scalar declarations that show up in a map clause have to be passed
2257 // by reference, because they may have been mapped in the enclosing data
2258 // environment.
2259 // - If the scalar value does not fit the size of uintptr, it has to be
2260 // passed by reference, regardless the result in the table above.
2261 // - For pointers mapped by value that have either an implicit map or an
2262 // array section, the runtime library may pass the NULL value to the
2263 // device instead of the value passed to it by the compiler.
2264 // - If both a pointer and a dereference of it are mapped, then the pointer
2265 // should be passed by reference.
2266
2267 if (Ty->isReferenceType())
2268 Ty = Ty->castAs<ReferenceType>()->getPointeeType();
2269
2270 // Locate map clauses and see if the variable being captured is mapped by
2271 // itself, or referred to, in any of those clauses. Here we only care about
2272 // variables, not fields, because fields are part of aggregates.
2273 bool IsVariableAssociatedWithSection = false;
2274 bool IsVariableItselfMapped = false;
2275
2276 DSAStack->checkMappableExprComponentListsForDeclAtLevel(
2277 VD: D, Level,
2278 Check: [&IsVariableUsedInMapClause, &IsVariableAssociatedWithSection,
2279 &IsVariableItselfMapped,
2280 D](OMPClauseMappableExprCommon::MappableExprComponentListRef
2281 MapExprComponents,
2282 OpenMPClauseKind WhereFoundClauseKind) {
2283 // Both map and has_device_addr clauses information influences how a
2284 // variable is captured. E.g. is_device_ptr does not require changing
2285 // the default behavior.
2286 if (WhereFoundClauseKind != OMPC_map &&
2287 WhereFoundClauseKind != OMPC_has_device_addr)
2288 return false;
2289
2290 auto EI = MapExprComponents.rbegin();
2291 auto EE = MapExprComponents.rend();
2292
2293 assert(EI != EE && "Invalid map expression!");
2294
2295 if (isa<DeclRefExpr>(Val: EI->getAssociatedExpression()) &&
2296 EI->getAssociatedDeclaration() == D) {
2297 IsVariableUsedInMapClause = true;
2298
2299 // If the component list has only one element, it's for mapping the
2300 // variable itself, like map(p). This takes precedence in
2301 // determining how it's captured, so we don't need to look further
2302 // for any other maps that use the variable (like map(p[0]) etc.)
2303 if (MapExprComponents.size() == 1) {
2304 IsVariableItselfMapped = true;
2305 return true;
2306 }
2307 }
2308
2309 ++EI;
2310 if (EI == EE)
2311 return false;
2312 auto Last = std::prev(x: EE);
2313 const auto *UO =
2314 dyn_cast<UnaryOperator>(Val: Last->getAssociatedExpression());
2315 if ((UO && UO->getOpcode() == UO_Deref) ||
2316 isa<ArraySubscriptExpr>(Val: Last->getAssociatedExpression()) ||
2317 isa<ArraySectionExpr>(Val: Last->getAssociatedExpression()) ||
2318 isa<MemberExpr>(Val: EI->getAssociatedExpression()) ||
2319 isa<OMPArrayShapingExpr>(Val: Last->getAssociatedExpression())) {
2320 IsVariableAssociatedWithSection = true;
2321 // We've found a case like map(p[0]) or map(p->a) or map(*p),
2322 // so we are done with this particular map, but we need to keep
2323 // looking in case we find a map(p).
2324 return false;
2325 }
2326
2327 // Keep looking for more map info.
2328 return false;
2329 });
2330
2331 if (IsVariableUsedInMapClause) {
2332 // If variable is identified in a map clause it is always captured by
2333 // reference except if it is a pointer that is dereferenced somehow, but
2334 // not itself mapped.
2335 //
2336 // OpenMP 6.0, 7.1.1: Data sharing attribute rules, variables referenced
2337 // in a construct::
2338 // If a list item in a has_device_addr clause or in a map clause on the
2339 // target construct has a base pointer, and the base pointer is a scalar
2340 // variable *that is not a list item in a map clause on the construct*,
2341 // the base pointer is firstprivate.
2342 //
2343 // OpenMP 4.5, 2.15.1.1: Data-sharing Attribute Rules for Variables
2344 // Referenced in a Construct:
2345 // If an array section is a list item in a map clause on the target
2346 // construct and the array section is derived from a variable for which
2347 // the type is pointer then that variable is firstprivate.
2348 IsByRef = IsVariableItselfMapped ||
2349 !(Ty->isPointerType() && IsVariableAssociatedWithSection);
2350 } else {
2351 // By default, all the data that has a scalar type is mapped by copy
2352 // (except for reduction variables).
2353 // Defaultmap scalar is mutual exclusive to defaultmap pointer
2354 IsByRef = (DSAStack->isForceCaptureByReferenceInTargetExecutable() &&
2355 !Ty->isAnyPointerType()) ||
2356 !Ty->isScalarType() ||
2357 DSAStack->isDefaultmapCapturedByRef(
2358 Level, Kind: getVariableCategoryFromDecl(LO: getLangOpts(), VD: D)) ||
2359 DSAStack->hasExplicitDSA(
2360 D,
2361 CPred: [](OpenMPClauseKind K, bool AppliedToPointee) {
2362 return K == OMPC_reduction && !AppliedToPointee;
2363 },
2364 Level);
2365 }
2366 }
2367
2368 if (IsByRef && Ty.getNonReferenceType()->isScalarType()) {
2369 IsByRef =
2370 ((IsVariableUsedInMapClause &&
2371 DSAStack->getCaptureRegion(Level, OpenMPCaptureLevel) ==
2372 OMPD_target) ||
2373 !(DSAStack->hasExplicitDSA(
2374 D,
2375 CPred: [](OpenMPClauseKind K, bool AppliedToPointee) -> bool {
2376 return K == OMPC_firstprivate ||
2377 (K == OMPC_reduction && AppliedToPointee);
2378 },
2379 Level, /*NotLastprivate=*/true) ||
2380 DSAStack->isUsesAllocatorsDecl(Level, D))) &&
2381 // If the variable is artificial and must be captured by value - try to
2382 // capture by value.
2383 !(isa<OMPCapturedExprDecl>(Val: D) && !D->hasAttr<OMPCaptureNoInitAttr>() &&
2384 !cast<OMPCapturedExprDecl>(Val: D)->getInit()->isGLValue()) &&
2385 // If the variable is implicitly firstprivate and scalar - capture by
2386 // copy
2387 !((DSAStack->getDefaultDSA() == DSA_firstprivate ||
2388 DSAStack->getDefaultDSA() == DSA_private) &&
2389 !DSAStack->hasExplicitDSA(
2390 D, CPred: [](OpenMPClauseKind K, bool) { return K != OMPC_unknown; },
2391 Level) &&
2392 !DSAStack->isLoopControlVariable(D, Level).first);
2393 }
2394
2395 // When passing data by copy, we need to make sure it fits the uintptr size
2396 // and alignment, because the runtime library only deals with uintptr types.
2397 // If it does not fit the uintptr size, we need to pass the data by reference
2398 // instead.
2399 if (!IsByRef && (Ctx.getTypeSizeInChars(T: Ty) >
2400 Ctx.getTypeSizeInChars(T: Ctx.getUIntPtrType()) ||
2401 Ctx.getAlignOfGlobalVarInChars(T: Ty, VD: dyn_cast<VarDecl>(Val: D)) >
2402 Ctx.getTypeAlignInChars(T: Ctx.getUIntPtrType()))) {
2403 IsByRef = true;
2404 }
2405
2406 return IsByRef;
2407}
2408
2409unsigned SemaOpenMP::getOpenMPNestingLevel() const {
2410 assert(getLangOpts().OpenMP);
2411 return DSAStack->getNestingLevel();
2412}
2413
2414bool SemaOpenMP::isInOpenMPTaskUntiedContext() const {
2415 return isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) &&
2416 DSAStack->isUntiedRegion();
2417}
2418
2419bool SemaOpenMP::isInOpenMPTargetExecutionDirective() const {
2420 return (isOpenMPTargetExecutionDirective(DSAStack->getCurrentDirective()) &&
2421 !DSAStack->isClauseParsingMode()) ||
2422 DSAStack->hasDirective(
2423 DPred: [](OpenMPDirectiveKind K, const DeclarationNameInfo &,
2424 SourceLocation) -> bool {
2425 return isOpenMPTargetExecutionDirective(DKind: K);
2426 },
2427 FromParent: false);
2428}
2429
2430bool SemaOpenMP::isOpenMPRebuildMemberExpr(ValueDecl *D) {
2431 // Only rebuild for Field.
2432 if (!isa<FieldDecl>(Val: D))
2433 return false;
2434 DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA(
2435 D,
2436 CPred: [](OpenMPClauseKind C, bool AppliedToPointee,
2437 DefaultDataSharingAttributes DefaultAttr) {
2438 return isOpenMPPrivate(Kind: C) && !AppliedToPointee &&
2439 (DefaultAttr == DSA_firstprivate || DefaultAttr == DSA_private);
2440 },
2441 DPred: [](OpenMPDirectiveKind) { return true; },
2442 DSAStack->isClauseParsingMode());
2443 if (DVarPrivate.CKind != OMPC_unknown)
2444 return true;
2445 return false;
2446}
2447
2448static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id,
2449 Expr *CaptureExpr, bool WithInit,
2450 DeclContext *CurContext,
2451 bool AsExpression);
2452
2453VarDecl *SemaOpenMP::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
2454 unsigned StopAt) {
2455 assert(getLangOpts().OpenMP && "OpenMP is not allowed");
2456 D = getCanonicalDecl(D);
2457
2458 if (auto *BD = dyn_cast<BindingDecl>(Val: D)) {
2459 if (!BD->getHoldingVar())
2460 D = cast<VarDecl>(Val: BD->getDecomposedDecl());
2461 }
2462 auto *VD = dyn_cast<VarDecl>(Val: D);
2463 // Do not capture constexpr variables.
2464 if (VD && VD->isConstexpr())
2465 return nullptr;
2466
2467 // If we want to determine whether the variable should be captured from the
2468 // perspective of the current capturing scope, and we've already left all the
2469 // capturing scopes of the top directive on the stack, check from the
2470 // perspective of its parent directive (if any) instead.
2471 DSAStackTy::ParentDirectiveScope InParentDirectiveRAII(
2472 *DSAStack, CheckScopeInfo && DSAStack->isBodyComplete());
2473
2474 // If we are attempting to capture a global variable in a directive with
2475 // 'target' we return true so that this global is also mapped to the device.
2476 //
2477 if (VD && !VD->hasLocalStorage() &&
2478 (SemaRef.getCurCapturedRegion() || SemaRef.getCurBlock() ||
2479 SemaRef.getCurLambda())) {
2480 if (isInOpenMPTargetExecutionDirective()) {
2481 DSAStackTy::DSAVarData DVarTop =
2482 DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode());
2483 if (DVarTop.CKind != OMPC_unknown && DVarTop.RefExpr)
2484 return VD;
2485 // If the declaration is enclosed in a 'declare target' directive,
2486 // then it should not be captured.
2487 //
2488 if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
2489 return nullptr;
2490 CapturedRegionScopeInfo *CSI = nullptr;
2491 for (FunctionScopeInfo *FSI : llvm::drop_begin(
2492 RangeOrContainer: llvm::reverse(C&: SemaRef.FunctionScopes),
2493 N: CheckScopeInfo ? (SemaRef.FunctionScopes.size() - (StopAt + 1))
2494 : 0)) {
2495 if (!isa<CapturingScopeInfo>(Val: FSI))
2496 return nullptr;
2497 if (auto *RSI = dyn_cast<CapturedRegionScopeInfo>(Val: FSI))
2498 if (RSI->CapRegionKind == CR_OpenMP) {
2499 CSI = RSI;
2500 break;
2501 }
2502 }
2503 // Lambdas and blocks at namespace scope have no enclosing function scope.
2504 if (!CSI)
2505 return nullptr;
2506 SmallVector<OpenMPDirectiveKind, 4> Regions;
2507 getOpenMPCaptureRegions(CaptureRegions&: Regions,
2508 DSAStack->getDirective(Level: CSI->OpenMPLevel));
2509 if (Regions[CSI->OpenMPCaptureLevel] != OMPD_task)
2510 return VD;
2511 }
2512 if (isInOpenMPDeclareTargetContext()) {
2513 // Try to mark variable as declare target if it is used in capturing
2514 // regions.
2515 if (getLangOpts().OpenMP <= 45 &&
2516 !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
2517 checkDeclIsAllowedInOpenMPTarget(E: nullptr, D: VD);
2518 return nullptr;
2519 }
2520 }
2521
2522 if (CheckScopeInfo) {
2523 bool OpenMPFound = false;
2524 for (unsigned I = StopAt + 1; I > 0; --I) {
2525 FunctionScopeInfo *FSI = SemaRef.FunctionScopes[I - 1];
2526 if (!isa<CapturingScopeInfo>(Val: FSI))
2527 return nullptr;
2528 if (auto *RSI = dyn_cast<CapturedRegionScopeInfo>(Val: FSI))
2529 if (RSI->CapRegionKind == CR_OpenMP) {
2530 OpenMPFound = true;
2531 break;
2532 }
2533 }
2534 if (!OpenMPFound)
2535 return nullptr;
2536 }
2537
2538 if (DSAStack->getCurrentDirective() != OMPD_unknown &&
2539 (!DSAStack->isClauseParsingMode() ||
2540 DSAStack->getParentDirective() != OMPD_unknown)) {
2541 auto &&Info = DSAStack->isLoopControlVariable(D);
2542 if (Info.first ||
2543 (VD && VD->hasLocalStorage() &&
2544 isImplicitOrExplicitTaskingRegion(DSAStack->getCurrentDirective())) ||
2545 (VD && DSAStack->isForceVarCapturing()))
2546 return VD ? VD : Info.second;
2547 DSAStackTy::DSAVarData DVarTop =
2548 DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode());
2549 if (DVarTop.CKind != OMPC_unknown && isOpenMPPrivate(Kind: DVarTop.CKind) &&
2550 (!VD || VD->hasLocalStorage() ||
2551 !(DVarTop.AppliedToPointee && DVarTop.CKind != OMPC_reduction)))
2552 return VD ? VD : cast<VarDecl>(Val: DVarTop.PrivateCopy->getDecl());
2553 // Threadprivate variables must not be captured.
2554 if (isOpenMPThreadPrivate(Kind: DVarTop.CKind))
2555 return nullptr;
2556 // The variable is not private or it is the variable in the directive with
2557 // default(none) clause and not used in any clause.
2558 DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA(
2559 D,
2560 CPred: [](OpenMPClauseKind C, bool AppliedToPointee, bool) {
2561 return isOpenMPPrivate(Kind: C) && !AppliedToPointee;
2562 },
2563 DPred: [](OpenMPDirectiveKind) { return true; },
2564 DSAStack->isClauseParsingMode());
2565 // Global shared must not be captured.
2566 if (VD && !VD->hasLocalStorage() && DVarPrivate.CKind == OMPC_unknown &&
2567 ((DSAStack->getDefaultDSA() != DSA_none &&
2568 DSAStack->getDefaultDSA() != DSA_private &&
2569 DSAStack->getDefaultDSA() != DSA_firstprivate) ||
2570 DVarTop.CKind == OMPC_shared))
2571 return nullptr;
2572 auto *FD = dyn_cast<FieldDecl>(Val: D);
2573 if (DVarPrivate.CKind != OMPC_unknown && !VD && FD &&
2574 !DVarPrivate.PrivateCopy) {
2575 DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA(
2576 D,
2577 CPred: [](OpenMPClauseKind C, bool AppliedToPointee,
2578 DefaultDataSharingAttributes DefaultAttr) {
2579 return isOpenMPPrivate(Kind: C) && !AppliedToPointee &&
2580 (DefaultAttr == DSA_firstprivate ||
2581 DefaultAttr == DSA_private);
2582 },
2583 DPred: [](OpenMPDirectiveKind) { return true; },
2584 DSAStack->isClauseParsingMode());
2585 if (DVarPrivate.CKind == OMPC_unknown)
2586 return nullptr;
2587
2588 VarDecl *VD = DSAStack->getImplicitFDCapExprDecl(FD);
2589 if (VD)
2590 return VD;
2591 if (SemaRef.getCurrentThisType().isNull())
2592 return nullptr;
2593 Expr *ThisExpr = SemaRef.BuildCXXThisExpr(Loc: SourceLocation(),
2594 Type: SemaRef.getCurrentThisType(),
2595 /*IsImplicit=*/true);
2596 const CXXScopeSpec CS = CXXScopeSpec();
2597 Expr *ME = SemaRef.BuildMemberExpr(
2598 Base: ThisExpr, /*IsArrow=*/true, OpLoc: SourceLocation(),
2599 NNS: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), Member: FD,
2600 FoundDecl: DeclAccessPair::make(D: FD, AS: FD->getAccess()),
2601 /*HadMultipleCandidates=*/false, MemberNameInfo: DeclarationNameInfo(), Ty: FD->getType(),
2602 VK: VK_LValue, OK: OK_Ordinary);
2603 OMPCapturedExprDecl *CD = buildCaptureDecl(
2604 S&: SemaRef, Id: FD->getIdentifier(), CaptureExpr: ME, WithInit: DVarPrivate.CKind != OMPC_private,
2605 CurContext: SemaRef.CurContext->getParent(), /*AsExpression=*/false);
2606 DeclRefExpr *VDPrivateRefExpr = buildDeclRefExpr(
2607 S&: SemaRef, D: CD, Ty: CD->getType().getNonReferenceType(), Loc: SourceLocation());
2608 VD = cast<VarDecl>(Val: VDPrivateRefExpr->getDecl());
2609 DSAStack->addImplicitDefaultFirstprivateFD(FD, VD);
2610 return VD;
2611 }
2612 if (DVarPrivate.CKind != OMPC_unknown ||
2613 (VD && (DSAStack->getDefaultDSA() == DSA_none ||
2614 DSAStack->getDefaultDSA() == DSA_private ||
2615 DSAStack->getDefaultDSA() == DSA_firstprivate)))
2616 return VD ? VD : cast<VarDecl>(Val: DVarPrivate.PrivateCopy->getDecl());
2617 }
2618 return nullptr;
2619}
2620
2621void SemaOpenMP::adjustOpenMPTargetScopeIndex(unsigned &FunctionScopesIndex,
2622 unsigned Level) const {
2623 FunctionScopesIndex -= getOpenMPCaptureLevels(DSAStack->getDirective(Level));
2624}
2625
2626void SemaOpenMP::startOpenMPLoop() {
2627 assert(getLangOpts().OpenMP && "OpenMP must be enabled.");
2628 if (isOpenMPLoopDirective(DSAStack->getCurrentDirective()))
2629 DSAStack->loopInit();
2630}
2631
2632void SemaOpenMP::startOpenMPCXXRangeFor() {
2633 assert(getLangOpts().OpenMP && "OpenMP must be enabled.");
2634 if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
2635 DSAStack->resetPossibleLoopCounter();
2636 DSAStack->loopStart();
2637 }
2638}
2639
2640OpenMPClauseKind SemaOpenMP::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level,
2641 unsigned CapLevel) const {
2642 assert(getLangOpts().OpenMP && "OpenMP is not allowed");
2643 if (DSAStack->getCurrentDirective() != OMPD_unknown &&
2644 (!DSAStack->isClauseParsingMode() ||
2645 DSAStack->getParentDirective() != OMPD_unknown)) {
2646 DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA(
2647 D,
2648 CPred: [](OpenMPClauseKind C, bool AppliedToPointee,
2649 DefaultDataSharingAttributes DefaultAttr) {
2650 return isOpenMPPrivate(Kind: C) && !AppliedToPointee &&
2651 DefaultAttr == DSA_private;
2652 },
2653 DPred: [](OpenMPDirectiveKind) { return true; },
2654 DSAStack->isClauseParsingMode());
2655 if (DVarPrivate.CKind == OMPC_private && isa<OMPCapturedExprDecl>(Val: D) &&
2656 DSAStack->isImplicitDefaultFirstprivateFD(VD: cast<VarDecl>(Val: D)) &&
2657 !DSAStack->isLoopControlVariable(D).first)
2658 return OMPC_private;
2659 }
2660 if (DSAStack->hasExplicitDirective(DPred: isOpenMPTaskingDirective, Level)) {
2661 bool IsTriviallyCopyable =
2662 D->getType().getNonReferenceType().isTriviallyCopyableType(
2663 Context: getASTContext()) &&
2664 !D->getType()
2665 .getNonReferenceType()
2666 .getCanonicalType()
2667 ->getAsCXXRecordDecl();
2668 OpenMPDirectiveKind DKind = DSAStack->getDirective(Level);
2669 SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
2670 getOpenMPCaptureRegions(CaptureRegions, DKind);
2671 if (isOpenMPTaskingDirective(Kind: CaptureRegions[CapLevel]) &&
2672 (IsTriviallyCopyable ||
2673 !isOpenMPTaskLoopDirective(DKind: CaptureRegions[CapLevel]))) {
2674 if (DSAStack->hasExplicitDSA(
2675 D,
2676 CPred: [](OpenMPClauseKind K, bool) { return K == OMPC_firstprivate; },
2677 Level, /*NotLastprivate=*/true))
2678 return OMPC_firstprivate;
2679 DSAStackTy::DSAVarData DVar = DSAStack->getImplicitDSA(D, Level);
2680 if (DVar.CKind != OMPC_shared &&
2681 !DSAStack->isLoopControlVariable(D, Level).first && !DVar.RefExpr) {
2682 DSAStack->addImplicitTaskFirstprivate(Level, D);
2683 return OMPC_firstprivate;
2684 }
2685 }
2686 }
2687 if (isOpenMPLoopDirective(DSAStack->getCurrentDirective()) &&
2688 !isOpenMPLoopTransformationDirective(DSAStack->getCurrentDirective())) {
2689 if (DSAStack->getAssociatedLoops() > 0 && !DSAStack->isLoopStarted()) {
2690 DSAStack->resetPossibleLoopCounter(D);
2691 DSAStack->loopStart();
2692 return OMPC_private;
2693 }
2694 if ((DSAStack->getPossiblyLoopCounter() == D->getCanonicalDecl() ||
2695 DSAStack->isLoopControlVariable(D).first) &&
2696 !DSAStack->hasExplicitDSA(
2697 D, CPred: [](OpenMPClauseKind K, bool) { return K != OMPC_private; },
2698 Level) &&
2699 !isOpenMPSimdDirective(DSAStack->getCurrentDirective()))
2700 return OMPC_private;
2701 }
2702 if (const auto *VD = dyn_cast<VarDecl>(Val: D)) {
2703 if (DSAStack->isThreadPrivate(D: const_cast<VarDecl *>(VD)) &&
2704 DSAStack->isForceVarCapturing() &&
2705 !DSAStack->hasExplicitDSA(
2706 D, CPred: [](OpenMPClauseKind K, bool) { return K == OMPC_copyin; },
2707 Level))
2708 return OMPC_private;
2709 }
2710 // User-defined allocators are private since they must be defined in the
2711 // context of target region.
2712 if (DSAStack->hasExplicitDirective(DPred: isOpenMPTargetExecutionDirective, Level) &&
2713 DSAStack->isUsesAllocatorsDecl(Level, D).value_or(
2714 u: DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait) ==
2715 DSAStackTy::UsesAllocatorsDeclKind::UserDefinedAllocator)
2716 return OMPC_private;
2717 return (DSAStack->hasExplicitDSA(
2718 D, CPred: [](OpenMPClauseKind K, bool) { return K == OMPC_private; },
2719 Level) ||
2720 (DSAStack->isClauseParsingMode() &&
2721 DSAStack->getClauseParsingMode() == OMPC_private) ||
2722 // Consider taskgroup reduction descriptor variable a private
2723 // to avoid possible capture in the region.
2724 (DSAStack->hasExplicitDirective(
2725 DPred: [](OpenMPDirectiveKind K) {
2726 return K == OMPD_taskgroup ||
2727 ((isOpenMPParallelDirective(DKind: K) ||
2728 isOpenMPWorksharingDirective(DKind: K)) &&
2729 !isOpenMPSimdDirective(DKind: K));
2730 },
2731 Level) &&
2732 DSAStack->isTaskgroupReductionRef(VD: D, Level)))
2733 ? OMPC_private
2734 : OMPC_unknown;
2735}
2736
2737void SemaOpenMP::setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D,
2738 unsigned Level) {
2739 assert(getLangOpts().OpenMP && "OpenMP is not allowed");
2740 D = getCanonicalDecl(D);
2741 OpenMPClauseKind OMPC = OMPC_unknown;
2742 for (unsigned I = DSAStack->getNestingLevel() + 1; I > Level; --I) {
2743 const unsigned NewLevel = I - 1;
2744 if (DSAStack->hasExplicitDSA(
2745 D,
2746 CPred: [&OMPC](const OpenMPClauseKind K, bool AppliedToPointee) {
2747 if (isOpenMPPrivate(Kind: K) && !AppliedToPointee) {
2748 OMPC = K;
2749 return true;
2750 }
2751 return false;
2752 },
2753 Level: NewLevel))
2754 break;
2755 if (DSAStack->checkMappableExprComponentListsForDeclAtLevel(
2756 VD: D, Level: NewLevel,
2757 Check: [](OMPClauseMappableExprCommon::MappableExprComponentListRef,
2758 OpenMPClauseKind) { return true; })) {
2759 OMPC = OMPC_map;
2760 break;
2761 }
2762 if (DSAStack->hasExplicitDirective(DPred: isOpenMPTargetExecutionDirective,
2763 Level: NewLevel)) {
2764 OMPC = OMPC_map;
2765 if (DSAStack->mustBeFirstprivateAtLevel(
2766 Level: NewLevel, Kind: getVariableCategoryFromDecl(LO: getLangOpts(), VD: D)))
2767 OMPC = OMPC_firstprivate;
2768 break;
2769 }
2770 }
2771 if (OMPC != OMPC_unknown)
2772 FD->addAttr(
2773 A: OMPCaptureKindAttr::CreateImplicit(Ctx&: getASTContext(), CaptureKindVal: unsigned(OMPC)));
2774}
2775
2776bool SemaOpenMP::isOpenMPTargetCapturedDecl(const ValueDecl *D, unsigned Level,
2777 unsigned CaptureLevel) const {
2778 assert(getLangOpts().OpenMP && "OpenMP is not allowed");
2779 // Return true if the current level is no longer enclosed in a target region.
2780
2781 SmallVector<OpenMPDirectiveKind, 4> Regions;
2782 getOpenMPCaptureRegions(CaptureRegions&: Regions, DSAStack->getDirective(Level));
2783 const auto *VD = dyn_cast<VarDecl>(Val: D);
2784 return VD && !VD->hasLocalStorage() &&
2785 DSAStack->hasExplicitDirective(DPred: isOpenMPTargetExecutionDirective,
2786 Level) &&
2787 Regions[CaptureLevel] != OMPD_task;
2788}
2789
2790bool SemaOpenMP::isOpenMPGlobalCapturedDecl(ValueDecl *D, unsigned Level,
2791 unsigned CaptureLevel) const {
2792 assert(getLangOpts().OpenMP && "OpenMP is not allowed");
2793 // Return true if the current level is no longer enclosed in a target region.
2794
2795 if (const auto *VD = dyn_cast<VarDecl>(Val: D)) {
2796 if (!VD->hasLocalStorage()) {
2797 if (isInOpenMPTargetExecutionDirective())
2798 return true;
2799 DSAStackTy::DSAVarData TopDVar =
2800 DSAStack->getTopDSA(D, /*FromParent=*/false);
2801 unsigned NumLevels =
2802 getOpenMPCaptureLevels(DSAStack->getDirective(Level));
2803 if (Level == 0)
2804 // non-file scope static variable with default(firstprivate)
2805 // should be global captured.
2806 return (NumLevels == CaptureLevel + 1 &&
2807 (TopDVar.CKind != OMPC_shared ||
2808 DSAStack->getDefaultDSA() == DSA_firstprivate));
2809 do {
2810 --Level;
2811 DSAStackTy::DSAVarData DVar = DSAStack->getImplicitDSA(D, Level);
2812 if (DVar.CKind != OMPC_shared)
2813 return true;
2814 } while (Level > 0);
2815 }
2816 }
2817 return true;
2818}
2819
2820void SemaOpenMP::DestroyDataSharingAttributesStack() { delete DSAStack; }
2821
2822void SemaOpenMP::ActOnOpenMPBeginDeclareVariant(SourceLocation Loc,
2823 OMPTraitInfo &TI) {
2824 OMPDeclareVariantScopes.push_back(Elt: OMPDeclareVariantScope(TI));
2825}
2826
2827void SemaOpenMP::ActOnOpenMPEndDeclareVariant() {
2828 assert(isInOpenMPDeclareVariantScope() &&
2829 "Not in OpenMP declare variant scope!");
2830
2831 OMPDeclareVariantScopes.pop_back();
2832}
2833
2834void SemaOpenMP::finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller,
2835 const FunctionDecl *Callee,
2836 SourceLocation Loc) {
2837 assert(getLangOpts().OpenMP && "Expected OpenMP compilation mode.");
2838 std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
2839 OMPDeclareTargetDeclAttr::getDeviceType(VD: Caller->getMostRecentDecl());
2840 // Ignore host functions during device analysis.
2841 if (getLangOpts().OpenMPIsTargetDevice &&
2842 (!DevTy || *DevTy == OMPDeclareTargetDeclAttr::DT_Host))
2843 return;
2844 // Ignore nohost functions during host analysis.
2845 if (!getLangOpts().OpenMPIsTargetDevice && DevTy &&
2846 *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
2847 return;
2848 const FunctionDecl *FD = Callee->getMostRecentDecl();
2849 DevTy = OMPDeclareTargetDeclAttr::getDeviceType(VD: FD);
2850 if (getLangOpts().OpenMPIsTargetDevice && DevTy &&
2851 *DevTy == OMPDeclareTargetDeclAttr::DT_Host) {
2852 // Diagnose host function called during device codegen.
2853 StringRef HostDevTy =
2854 getOpenMPSimpleClauseTypeName(Kind: OMPC_device_type, Type: OMPC_DEVICE_TYPE_host);
2855 Diag(Loc, DiagID: diag::err_omp_wrong_device_function_call) << HostDevTy << 0;
2856 Diag(Loc: *OMPDeclareTargetDeclAttr::getLocation(VD: FD),
2857 DiagID: diag::note_omp_marked_device_type_here)
2858 << HostDevTy;
2859 return;
2860 }
2861 if (!getLangOpts().OpenMPIsTargetDevice &&
2862 !getLangOpts().OpenMPOffloadMandatory && DevTy &&
2863 *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) {
2864 // In OpenMP 5.2 or later, if the function has a host variant then allow
2865 // that to be called instead
2866 auto &&HasHostAttr = [](const FunctionDecl *Callee) {
2867 for (OMPDeclareVariantAttr *A :
2868 Callee->specific_attrs<OMPDeclareVariantAttr>()) {
2869 auto *DeclRefVariant = cast<DeclRefExpr>(Val: A->getVariantFuncRef());
2870 auto *VariantFD = cast<FunctionDecl>(Val: DeclRefVariant->getDecl());
2871 std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
2872 OMPDeclareTargetDeclAttr::getDeviceType(
2873 VD: VariantFD->getMostRecentDecl());
2874 if (!DevTy || *DevTy == OMPDeclareTargetDeclAttr::DT_Host)
2875 return true;
2876 }
2877 return false;
2878 };
2879 if (getLangOpts().OpenMP >= 52 &&
2880 Callee->hasAttr<OMPDeclareVariantAttr>() && HasHostAttr(Callee))
2881 return;
2882 // Diagnose nohost function called during host codegen.
2883 StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName(
2884 Kind: OMPC_device_type, Type: OMPC_DEVICE_TYPE_nohost);
2885 Diag(Loc, DiagID: diag::err_omp_wrong_device_function_call) << NoHostDevTy << 1;
2886 Diag(Loc: *OMPDeclareTargetDeclAttr::getLocation(VD: FD),
2887 DiagID: diag::note_omp_marked_device_type_here)
2888 << NoHostDevTy;
2889 }
2890}
2891
2892void SemaOpenMP::StartOpenMPDSABlock(OpenMPDirectiveKind DKind,
2893 const DeclarationNameInfo &DirName,
2894 Scope *CurScope, SourceLocation Loc) {
2895 DSAStack->push(DKind, DirName, CurScope, Loc);
2896 SemaRef.PushExpressionEvaluationContext(
2897 NewContext: Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
2898}
2899
2900void SemaOpenMP::StartOpenMPClause(OpenMPClauseKind K) {
2901 DSAStack->setClauseParsingMode(K);
2902}
2903
2904void SemaOpenMP::EndOpenMPClause() {
2905 DSAStack->setClauseParsingMode(/*K=*/OMPC_unknown);
2906 SemaRef.CleanupVarDeclMarking();
2907}
2908
2909static std::pair<ValueDecl *, bool>
2910getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
2911 SourceRange &ERange, bool AllowArraySection = false,
2912 bool AllowAssumedSizeArray = false, StringRef DiagType = "");
2913
2914/// Check consistency of the reduction clauses.
2915static void checkReductionClauses(Sema &S, DSAStackTy *Stack,
2916 ArrayRef<OMPClause *> Clauses) {
2917 bool InscanFound = false;
2918 SourceLocation InscanLoc;
2919 // OpenMP 5.0, 2.19.5.4 reduction Clause, Restrictions.
2920 // A reduction clause without the inscan reduction-modifier may not appear on
2921 // a construct on which a reduction clause with the inscan reduction-modifier
2922 // appears.
2923 for (OMPClause *C : Clauses) {
2924 if (C->getClauseKind() != OMPC_reduction)
2925 continue;
2926 auto *RC = cast<OMPReductionClause>(Val: C);
2927 if (RC->getModifier() == OMPC_REDUCTION_inscan) {
2928 InscanFound = true;
2929 InscanLoc = RC->getModifierLoc();
2930 continue;
2931 }
2932 if (RC->getModifier() == OMPC_REDUCTION_task) {
2933 // OpenMP 5.0, 2.19.5.4 reduction Clause.
2934 // A reduction clause with the task reduction-modifier may only appear on
2935 // a parallel construct, a worksharing construct or a combined or
2936 // composite construct for which any of the aforementioned constructs is a
2937 // constituent construct and simd or loop are not constituent constructs.
2938 OpenMPDirectiveKind CurDir = Stack->getCurrentDirective();
2939 if (!(isOpenMPParallelDirective(DKind: CurDir) ||
2940 isOpenMPWorksharingDirective(DKind: CurDir)) ||
2941 isOpenMPSimdDirective(DKind: CurDir))
2942 S.Diag(Loc: RC->getModifierLoc(),
2943 DiagID: diag::err_omp_reduction_task_not_parallel_or_worksharing);
2944 continue;
2945 }
2946 }
2947 if (InscanFound) {
2948 for (OMPClause *C : Clauses) {
2949 if (C->getClauseKind() != OMPC_reduction)
2950 continue;
2951 auto *RC = cast<OMPReductionClause>(Val: C);
2952 if (RC->getModifier() != OMPC_REDUCTION_inscan) {
2953 S.Diag(Loc: RC->getModifier() == OMPC_REDUCTION_unknown
2954 ? RC->getBeginLoc()
2955 : RC->getModifierLoc(),
2956 DiagID: diag::err_omp_inscan_reduction_expected);
2957 S.Diag(Loc: InscanLoc, DiagID: diag::note_omp_previous_inscan_reduction);
2958 continue;
2959 }
2960 for (Expr *Ref : RC->varlist()) {
2961 assert(Ref && "NULL expr in OpenMP reduction clause.");
2962 SourceLocation ELoc;
2963 SourceRange ERange;
2964 Expr *SimpleRefExpr = Ref;
2965 auto Res = getPrivateItem(S, RefExpr&: SimpleRefExpr, ELoc, ERange,
2966 /*AllowArraySection=*/true);
2967 ValueDecl *D = Res.first;
2968 if (!D)
2969 continue;
2970 if (!Stack->isUsedInScanDirective(D: getCanonicalDecl(D))) {
2971 S.Diag(Loc: Ref->getExprLoc(),
2972 DiagID: diag::err_omp_reduction_not_inclusive_exclusive)
2973 << Ref->getSourceRange();
2974 }
2975 }
2976 }
2977 }
2978}
2979
2980static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
2981 ArrayRef<OMPClause *> Clauses);
2982static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr,
2983 bool WithInit);
2984
2985static void reportOriginalDsa(Sema &SemaRef, const DSAStackTy *Stack,
2986 const ValueDecl *D,
2987 const DSAStackTy::DSAVarData &DVar,
2988 bool IsLoopIterVar = false);
2989
2990void SemaOpenMP::EndOpenMPDSABlock(Stmt *CurDirective) {
2991 // OpenMP [2.14.3.5, Restrictions, C/C++, p.1]
2992 // A variable of class type (or array thereof) that appears in a lastprivate
2993 // clause requires an accessible, unambiguous default constructor for the
2994 // class type, unless the list item is also specified in a firstprivate
2995 // clause.
2996
2997 auto FinalizeLastprivate = [&](OMPLastprivateClause *Clause) {
2998 SmallVector<Expr *, 8> PrivateCopies;
2999 for (Expr *DE : Clause->varlist()) {
3000 if (DE->isValueDependent() || DE->isTypeDependent()) {
3001 PrivateCopies.push_back(Elt: nullptr);
3002 continue;
3003 }
3004 auto *DRE = cast<DeclRefExpr>(Val: DE->IgnoreParens());
3005 auto *D = DRE->getDecl();
3006 if (auto *BD = dyn_cast<BindingDecl>(Val: D)) {
3007 QualType Type = BD->getType().getNonReferenceType();
3008 const DSAStackTy::DSAVarData DVar =
3009 DSAStack->getTopDSA(D: BD, /*FromParent=*/false);
3010 if (DVar.CKind != OMPC_lastprivate) {
3011 // The variable is also a firstprivate, so initialization sequence
3012 // for private copy is generated already.
3013 PrivateCopies.push_back(Elt: nullptr);
3014 continue;
3015 }
3016 VarDecl *VDPrivate = buildVarDecl(
3017 SemaRef, Loc: DE->getExprLoc(), Type: Type.getUnqualifiedType(), Name: BD->getName(),
3018 Attrs: BD->hasAttrs() ? &BD->getAttrs() : nullptr, OrigRef: DRE);
3019 SemaRef.ActOnUninitializedDecl(dcl: VDPrivate);
3020 if (VDPrivate->isInvalidDecl()) {
3021 PrivateCopies.push_back(Elt: nullptr);
3022 continue;
3023 }
3024 PrivateCopies.push_back(Elt: buildDeclRefExpr(
3025 S&: SemaRef, D: VDPrivate, Ty: DE->getType(), Loc: DE->getExprLoc()));
3026 continue;
3027 }
3028 auto *VD = cast<VarDecl>(Val: D);
3029 QualType Type = VD->getType().getNonReferenceType();
3030 const DSAStackTy::DSAVarData DVar =
3031 DSAStack->getTopDSA(D: VD, /*FromParent=*/false);
3032 if (DVar.CKind != OMPC_lastprivate) {
3033 // The variable is also a firstprivate, so initialization sequence
3034 // for private copy is generated already.
3035 PrivateCopies.push_back(Elt: nullptr);
3036 continue;
3037 }
3038 // Generate helper private variable and initialize it with the
3039 // default value. The address of the original variable is replaced
3040 // by the address of the new private variable in CodeGen. This new
3041 // variable is not added to IdResolver, so the code in the OpenMP
3042 // region uses original variable for proper diagnostics.
3043 VarDecl *VDPrivate = buildVarDecl(
3044 SemaRef, Loc: DE->getExprLoc(), Type: Type.getUnqualifiedType(), Name: VD->getName(),
3045 Attrs: VD->hasAttrs() ? &VD->getAttrs() : nullptr, OrigRef: DRE);
3046 SemaRef.ActOnUninitializedDecl(dcl: VDPrivate);
3047 if (VDPrivate->isInvalidDecl()) {
3048 PrivateCopies.push_back(Elt: nullptr);
3049 continue;
3050 }
3051 PrivateCopies.push_back(Elt: buildDeclRefExpr(
3052 S&: SemaRef, D: VDPrivate, Ty: DE->getType(), Loc: DE->getExprLoc()));
3053 }
3054 Clause->setPrivateCopies(PrivateCopies);
3055 };
3056
3057 auto FinalizeNontemporal = [&](OMPNontemporalClause *Clause) {
3058 // Finalize nontemporal clause by handling private copies, if any.
3059 SmallVector<Expr *, 8> PrivateRefs;
3060 for (Expr *RefExpr : Clause->varlist()) {
3061 assert(RefExpr && "NULL expr in OpenMP nontemporal clause.");
3062 SourceLocation ELoc;
3063 SourceRange ERange;
3064 Expr *SimpleRefExpr = RefExpr;
3065 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange);
3066 if (Res.second)
3067 // It will be analyzed later.
3068 PrivateRefs.push_back(Elt: RefExpr);
3069 ValueDecl *D = Res.first;
3070 if (!D)
3071 continue;
3072
3073 const DSAStackTy::DSAVarData DVar =
3074 DSAStack->getTopDSA(D, /*FromParent=*/false);
3075 PrivateRefs.push_back(Elt: DVar.PrivateCopy ? DVar.PrivateCopy
3076 : SimpleRefExpr);
3077 }
3078 Clause->setPrivateRefs(PrivateRefs);
3079 };
3080
3081 auto FinalizeAllocators = [&](OMPUsesAllocatorsClause *Clause) {
3082 for (unsigned I = 0, E = Clause->getNumberOfAllocators(); I < E; ++I) {
3083 OMPUsesAllocatorsClause::Data D = Clause->getAllocatorData(I);
3084 auto *DRE = dyn_cast<DeclRefExpr>(Val: D.Allocator->IgnoreParenImpCasts());
3085 if (!DRE)
3086 continue;
3087 ValueDecl *VD = DRE->getDecl();
3088 if (!VD || !isa<VarDecl>(Val: VD))
3089 continue;
3090 DSAStackTy::DSAVarData DVar =
3091 DSAStack->getTopDSA(D: VD, /*FromParent=*/false);
3092 // OpenMP [2.12.5, target Construct]
3093 // Memory allocators that appear in a uses_allocators clause cannot
3094 // appear in other data-sharing attribute clauses or data-mapping
3095 // attribute clauses in the same construct.
3096 Expr *MapExpr = nullptr;
3097 if (DVar.RefExpr ||
3098 DSAStack->checkMappableExprComponentListsForDecl(
3099 VD, /*CurrentRegionOnly=*/true,
3100 Check: [VD, &MapExpr](
3101 OMPClauseMappableExprCommon::MappableExprComponentListRef
3102 MapExprComponents,
3103 OpenMPClauseKind C) {
3104 auto MI = MapExprComponents.rbegin();
3105 auto ME = MapExprComponents.rend();
3106 if (MI != ME &&
3107 MI->getAssociatedDeclaration()->getCanonicalDecl() ==
3108 VD->getCanonicalDecl()) {
3109 MapExpr = MI->getAssociatedExpression();
3110 return true;
3111 }
3112 return false;
3113 })) {
3114 Diag(Loc: D.Allocator->getExprLoc(), DiagID: diag::err_omp_allocator_used_in_clauses)
3115 << D.Allocator->getSourceRange();
3116 if (DVar.RefExpr)
3117 reportOriginalDsa(SemaRef, DSAStack, D: VD, DVar);
3118 else
3119 Diag(Loc: MapExpr->getExprLoc(), DiagID: diag::note_used_here)
3120 << MapExpr->getSourceRange();
3121 }
3122 }
3123 };
3124
3125 if (const auto *D = dyn_cast_or_null<OMPExecutableDirective>(Val: CurDirective)) {
3126 for (OMPClause *C : D->clauses()) {
3127 if (auto *Clause = dyn_cast<OMPLastprivateClause>(Val: C)) {
3128 FinalizeLastprivate(Clause);
3129 } else if (auto *Clause = dyn_cast<OMPNontemporalClause>(Val: C)) {
3130 FinalizeNontemporal(Clause);
3131 } else if (auto *Clause = dyn_cast<OMPUsesAllocatorsClause>(Val: C)) {
3132 FinalizeAllocators(Clause);
3133 }
3134 }
3135 // Check allocate clauses.
3136 if (!SemaRef.CurContext->isDependentContext())
3137 checkAllocateClauses(S&: SemaRef, DSAStack, Clauses: D->clauses());
3138 checkReductionClauses(S&: SemaRef, DSAStack, Clauses: D->clauses());
3139 }
3140
3141 DSAStack->pop();
3142 SemaRef.DiscardCleanupsInEvaluationContext();
3143 SemaRef.PopExpressionEvaluationContext();
3144}
3145
3146static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
3147 Expr *NumIterations, Sema &SemaRef,
3148 Scope *S, DSAStackTy *Stack);
3149
3150static bool finishLinearClauses(Sema &SemaRef, ArrayRef<OMPClause *> Clauses,
3151 OMPLoopBasedDirective::HelperExprs &B,
3152 DSAStackTy *Stack) {
3153 assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) &&
3154 "loop exprs were not built");
3155
3156 if (SemaRef.CurContext->isDependentContext())
3157 return false;
3158
3159 // Finalize the clauses that need pre-built expressions for CodeGen.
3160 for (OMPClause *C : Clauses) {
3161 auto *LC = dyn_cast<OMPLinearClause>(Val: C);
3162 if (!LC)
3163 continue;
3164 if (FinishOpenMPLinearClause(Clause&: *LC, IV: cast<DeclRefExpr>(Val: B.IterationVarRef),
3165 NumIterations: B.NumIterations, SemaRef,
3166 S: SemaRef.getCurScope(), Stack))
3167 return true;
3168 }
3169
3170 return false;
3171}
3172
3173namespace {
3174
3175class VarDeclFilterCCC final : public CorrectionCandidateCallback {
3176private:
3177 Sema &SemaRef;
3178
3179public:
3180 explicit VarDeclFilterCCC(Sema &S) : SemaRef(S) {}
3181 bool ValidateCandidate(const TypoCorrection &Candidate) override {
3182 NamedDecl *ND = Candidate.getCorrectionDecl();
3183 if (const auto *VD = dyn_cast_or_null<VarDecl>(Val: ND)) {
3184 return VD->hasGlobalStorage() &&
3185 SemaRef.isDeclInScope(D: ND, Ctx: SemaRef.getCurLexicalContext(),
3186 S: SemaRef.getCurScope());
3187 }
3188 return false;
3189 }
3190
3191 std::unique_ptr<CorrectionCandidateCallback> clone() override {
3192 return std::make_unique<VarDeclFilterCCC>(args&: *this);
3193 }
3194};
3195
3196class VarOrFuncDeclFilterCCC final : public CorrectionCandidateCallback {
3197private:
3198 Sema &SemaRef;
3199
3200public:
3201 explicit VarOrFuncDeclFilterCCC(Sema &S) : SemaRef(S) {}
3202 bool ValidateCandidate(const TypoCorrection &Candidate) override {
3203 NamedDecl *ND = Candidate.getCorrectionDecl();
3204 if (ND && ((isa<VarDecl>(Val: ND) && ND->getKind() == Decl::Var) ||
3205 isa<FunctionDecl>(Val: ND))) {
3206 return SemaRef.isDeclInScope(D: ND, Ctx: SemaRef.getCurLexicalContext(),
3207 S: SemaRef.getCurScope());
3208 }
3209 return false;
3210 }
3211
3212 std::unique_ptr<CorrectionCandidateCallback> clone() override {
3213 return std::make_unique<VarOrFuncDeclFilterCCC>(args&: *this);
3214 }
3215};
3216
3217} // namespace
3218
3219ExprResult SemaOpenMP::ActOnOpenMPIdExpression(Scope *CurScope,
3220 CXXScopeSpec &ScopeSpec,
3221 const DeclarationNameInfo &Id,
3222 OpenMPDirectiveKind Kind) {
3223 ASTContext &Context = getASTContext();
3224 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
3225 LookupResult Lookup(SemaRef, Id, Sema::LookupOrdinaryName);
3226 SemaRef.LookupParsedName(R&: Lookup, S: CurScope, SS: &ScopeSpec,
3227 /*ObjectType=*/QualType(),
3228 /*AllowBuiltinCreation=*/true);
3229
3230 if (Lookup.isAmbiguous())
3231 return ExprError();
3232
3233 VarDecl *VD;
3234 if (!Lookup.isSingleResult()) {
3235 VarDeclFilterCCC CCC(SemaRef);
3236 if (TypoCorrection Corrected =
3237 SemaRef.CorrectTypo(Typo: Id, LookupKind: Sema::LookupOrdinaryName, S: CurScope, SS: nullptr,
3238 CCC, Mode: CorrectTypoKind::ErrorRecovery)) {
3239 SemaRef.diagnoseTypo(
3240 Correction: Corrected,
3241 TypoDiag: SemaRef.PDiag(DiagID: Lookup.empty() ? diag::err_undeclared_var_use_suggest
3242 : diag::err_omp_expected_var_arg_suggest)
3243 << Id.getName());
3244 VD = Corrected.getCorrectionDeclAs<VarDecl>();
3245 } else {
3246 Diag(Loc: Id.getLoc(), DiagID: Lookup.empty() ? diag::err_undeclared_var_use
3247 : diag::err_omp_expected_var_arg)
3248 << Id.getName();
3249 return ExprError();
3250 }
3251 } else if (!(VD = Lookup.getAsSingle<VarDecl>())) {
3252 Diag(Loc: Id.getLoc(), DiagID: diag::err_omp_expected_var_arg) << Id.getName();
3253 Diag(Loc: Lookup.getFoundDecl()->getLocation(), DiagID: diag::note_declared_at);
3254 return ExprError();
3255 }
3256 Lookup.suppressDiagnostics();
3257
3258 // OpenMP [2.9.2, Syntax, C/C++]
3259 // Variables must be file-scope, namespace-scope, or static block-scope.
3260 if ((Kind == OMPD_threadprivate || Kind == OMPD_groupprivate) &&
3261 !VD->hasGlobalStorage()) {
3262 Diag(Loc: Id.getLoc(), DiagID: diag::err_omp_global_var_arg)
3263 << getOpenMPDirectiveName(D: Kind, V: OMPVersion) << !VD->isStaticLocal();
3264 bool IsDecl =
3265 VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
3266 Diag(Loc: VD->getLocation(),
3267 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
3268 << VD;
3269 return ExprError();
3270 }
3271
3272 VarDecl *CanonicalVD = VD->getCanonicalDecl();
3273 NamedDecl *ND = CanonicalVD;
3274 // OpenMP [2.9.2, Restrictions, C/C++, p.2]
3275 // A threadprivate or groupprivate directive for file-scope variables must
3276 // appear outside any definition or declaration.
3277 if (CanonicalVD->getDeclContext()->isTranslationUnit() &&
3278 !SemaRef.getCurLexicalContext()->isTranslationUnit()) {
3279 Diag(Loc: Id.getLoc(), DiagID: diag::err_omp_var_scope)
3280 << getOpenMPDirectiveName(D: Kind, V: OMPVersion) << VD;
3281 bool IsDecl =
3282 VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
3283 Diag(Loc: VD->getLocation(),
3284 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
3285 << VD;
3286 return ExprError();
3287 }
3288 // OpenMP [2.9.2, Restrictions, C/C++, p.3]
3289 // A threadprivate or groupprivate directive for static class member
3290 // variables must appear in the class definition, in the same scope in which
3291 // the member variables are declared.
3292 if (CanonicalVD->isStaticDataMember() &&
3293 !CanonicalVD->getDeclContext()->Equals(DC: SemaRef.getCurLexicalContext())) {
3294 Diag(Loc: Id.getLoc(), DiagID: diag::err_omp_var_scope)
3295 << getOpenMPDirectiveName(D: Kind, V: OMPVersion) << VD;
3296 bool IsDecl =
3297 VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
3298 Diag(Loc: VD->getLocation(),
3299 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
3300 << VD;
3301 return ExprError();
3302 }
3303 // OpenMP [2.9.2, Restrictions, C/C++, p.4]
3304 // A threadprivate or groupprivate directive for namespace-scope variables
3305 // must appear outside any definition or declaration other than the
3306 // namespace definition itself.
3307 if (CanonicalVD->getDeclContext()->isNamespace() &&
3308 (!SemaRef.getCurLexicalContext()->isFileContext() ||
3309 !SemaRef.getCurLexicalContext()->Encloses(
3310 DC: CanonicalVD->getDeclContext()))) {
3311 Diag(Loc: Id.getLoc(), DiagID: diag::err_omp_var_scope)
3312 << getOpenMPDirectiveName(D: Kind, V: OMPVersion) << VD;
3313 bool IsDecl =
3314 VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
3315 Diag(Loc: VD->getLocation(),
3316 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
3317 << VD;
3318 return ExprError();
3319 }
3320 // OpenMP [2.9.2, Restrictions, C/C++, p.6]
3321 // A threadprivate or groupprivate directive for static block-scope
3322 // variables must appear in the scope of the variable and not in a nested
3323 // scope.
3324 if (CanonicalVD->isLocalVarDecl() && CurScope &&
3325 !SemaRef.isDeclInScope(D: ND, Ctx: SemaRef.getCurLexicalContext(), S: CurScope)) {
3326 Diag(Loc: Id.getLoc(), DiagID: diag::err_omp_var_scope)
3327 << getOpenMPDirectiveName(D: Kind, V: OMPVersion) << VD;
3328 bool IsDecl =
3329 VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
3330 Diag(Loc: VD->getLocation(),
3331 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
3332 << VD;
3333 return ExprError();
3334 }
3335
3336 // OpenMP [2.9.2, Restrictions, C/C++, p.2-6]
3337 // A threadprivate or groupprivate directive must lexically precede all
3338 // references to any of the variables in its list.
3339 if ((Kind == OMPD_threadprivate && VD->isUsed() &&
3340 !DSAStack->isThreadPrivate(D: VD)) ||
3341 (Kind == OMPD_groupprivate && VD->isUsed())) {
3342 Diag(Loc: Id.getLoc(), DiagID: diag::err_omp_var_used)
3343 << getOpenMPDirectiveName(D: Kind, V: OMPVersion) << VD;
3344 return ExprError();
3345 }
3346
3347 QualType ExprType = VD->getType().getNonReferenceType();
3348 return DeclRefExpr::Create(Context, QualifierLoc: NestedNameSpecifierLoc(),
3349 TemplateKWLoc: SourceLocation(), D: VD,
3350 /*RefersToEnclosingVariableOrCapture=*/false,
3351 NameLoc: Id.getLoc(), T: ExprType, VK: VK_LValue);
3352}
3353
3354SemaOpenMP::DeclGroupPtrTy
3355SemaOpenMP::ActOnOpenMPThreadprivateDirective(SourceLocation Loc,
3356 ArrayRef<Expr *> VarList) {
3357 if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, VarList)) {
3358 SemaRef.CurContext->addDecl(D);
3359 return DeclGroupPtrTy::make(P: DeclGroupRef(D));
3360 }
3361 return nullptr;
3362}
3363
3364SemaOpenMP::DeclGroupPtrTy
3365SemaOpenMP::ActOnOpenMPGroupPrivateDirective(SourceLocation Loc,
3366 ArrayRef<Expr *> VarList) {
3367 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
3368 if (!OMPVersion || OMPVersion < 60) {
3369 Diag(Loc, DiagID: diag::err_omp_unexpected_directive)
3370 << getOpenMPDirectiveName(D: OMPD_groupprivate, V: OMPVersion);
3371 return nullptr;
3372 }
3373 if (OMPGroupPrivateDecl *D = CheckOMPGroupPrivateDecl(Loc, VarList)) {
3374 SemaRef.CurContext->addDecl(D);
3375 return DeclGroupPtrTy::make(P: DeclGroupRef(D));
3376 }
3377 return nullptr;
3378}
3379
3380namespace {
3381class LocalVarRefChecker final
3382 : public ConstStmtVisitor<LocalVarRefChecker, bool> {
3383 Sema &SemaRef;
3384
3385public:
3386 bool VisitDeclRefExpr(const DeclRefExpr *E) {
3387 if (const auto *VD = dyn_cast<VarDecl>(Val: E->getDecl())) {
3388 if (VD->hasLocalStorage()) {
3389 SemaRef.Diag(Loc: E->getBeginLoc(),
3390 DiagID: diag::err_omp_local_var_in_threadprivate_init)
3391 << E->getSourceRange();
3392 SemaRef.Diag(Loc: VD->getLocation(), DiagID: diag::note_defined_here)
3393 << VD << VD->getSourceRange();
3394 return true;
3395 }
3396 }
3397 return false;
3398 }
3399 bool VisitStmt(const Stmt *S) {
3400 for (const Stmt *Child : S->children()) {
3401 if (Child && Visit(S: Child))
3402 return true;
3403 }
3404 return false;
3405 }
3406 explicit LocalVarRefChecker(Sema &SemaRef) : SemaRef(SemaRef) {}
3407};
3408} // namespace
3409
3410OMPThreadPrivateDecl *
3411SemaOpenMP::CheckOMPThreadPrivateDecl(SourceLocation Loc,
3412 ArrayRef<Expr *> VarList) {
3413 ASTContext &Context = getASTContext();
3414 SmallVector<Expr *, 8> Vars;
3415 for (Expr *RefExpr : VarList) {
3416 auto *DE = cast<DeclRefExpr>(Val: RefExpr);
3417 auto *VD = cast<VarDecl>(Val: DE->getDecl());
3418 SourceLocation ILoc = DE->getExprLoc();
3419
3420 // Mark variable as used.
3421 VD->setReferenced();
3422 VD->markUsed(C&: Context);
3423
3424 QualType QType = VD->getType();
3425 if (QType->isDependentType() || QType->isInstantiationDependentType()) {
3426 // It will be analyzed later.
3427 Vars.push_back(Elt: DE);
3428 continue;
3429 }
3430
3431 // OpenMP [2.9.2, Restrictions, C/C++, p.10]
3432 // A threadprivate variable must not have an incomplete type.
3433 if (SemaRef.RequireCompleteType(
3434 Loc: ILoc, T: VD->getType(), DiagID: diag::err_omp_threadprivate_incomplete_type)) {
3435 continue;
3436 }
3437
3438 // OpenMP [2.9.2, Restrictions, C/C++, p.10]
3439 // A threadprivate variable must not have a reference type.
3440 if (VD->getType()->isReferenceType()) {
3441 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
3442 Diag(Loc: ILoc, DiagID: diag::err_omp_ref_type_arg)
3443 << getOpenMPDirectiveName(D: OMPD_threadprivate, V: OMPVersion)
3444 << VD->getType();
3445 bool IsDecl =
3446 VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
3447 Diag(Loc: VD->getLocation(),
3448 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
3449 << VD;
3450 continue;
3451 }
3452
3453 // Check if this is a TLS variable. If TLS is not being supported, produce
3454 // the corresponding diagnostic.
3455 if ((VD->getTLSKind() != VarDecl::TLS_None &&
3456 !(VD->hasAttr<OMPThreadPrivateDeclAttr>() &&
3457 getLangOpts().OpenMPUseTLS &&
3458 getASTContext().getTargetInfo().isTLSSupported())) ||
3459 (VD->getStorageClass() == SC_Register && VD->hasAttr<AsmLabelAttr>() &&
3460 !VD->isLocalVarDecl())) {
3461 Diag(Loc: ILoc, DiagID: diag::err_omp_var_thread_local)
3462 << VD << ((VD->getTLSKind() != VarDecl::TLS_None) ? 0 : 1);
3463 bool IsDecl =
3464 VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
3465 Diag(Loc: VD->getLocation(),
3466 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
3467 << VD;
3468 continue;
3469 }
3470
3471 // Check if initial value of threadprivate variable reference variable with
3472 // local storage (it is not supported by runtime).
3473 if (const Expr *Init = VD->getAnyInitializer()) {
3474 LocalVarRefChecker Checker(SemaRef);
3475 if (Checker.Visit(S: Init))
3476 continue;
3477 }
3478
3479 Vars.push_back(Elt: RefExpr);
3480 DSAStack->addDSA(D: VD, E: DE, A: OMPC_threadprivate);
3481 VD->addAttr(A: OMPThreadPrivateDeclAttr::CreateImplicit(
3482 Ctx&: Context, Range: SourceRange(Loc, Loc)));
3483 if (ASTMutationListener *ML = Context.getASTMutationListener())
3484 ML->DeclarationMarkedOpenMPThreadPrivate(D: VD);
3485 }
3486 OMPThreadPrivateDecl *D = nullptr;
3487 if (!Vars.empty()) {
3488 D = OMPThreadPrivateDecl::Create(C&: Context, DC: SemaRef.getCurLexicalContext(),
3489 L: Loc, VL: Vars);
3490 D->setAccess(AS_public);
3491 }
3492 return D;
3493}
3494
3495OMPGroupPrivateDecl *
3496SemaOpenMP::CheckOMPGroupPrivateDecl(SourceLocation Loc,
3497 ArrayRef<Expr *> VarList) {
3498 ASTContext &Context = getASTContext();
3499 SmallVector<Expr *, 8> Vars;
3500 for (Expr *RefExpr : VarList) {
3501 auto *DE = cast<DeclRefExpr>(Val: RefExpr);
3502 auto *VD = cast<VarDecl>(Val: DE->getDecl());
3503 SourceLocation ILoc = DE->getExprLoc();
3504
3505 // Mark variable as used.
3506 VD->setReferenced();
3507 VD->markUsed(C&: Context);
3508
3509 QualType QType = VD->getType();
3510 if (QType->isDependentType() || QType->isInstantiationDependentType()) {
3511 // It will be analyzed later.
3512 Vars.push_back(Elt: DE);
3513 continue;
3514 }
3515
3516 // OpenMP groupprivate restrictions:
3517 // A groupprivate variable must not have an incomplete type.
3518 if (SemaRef.RequireCompleteType(
3519 Loc: ILoc, T: VD->getType(), DiagID: diag::err_omp_groupprivate_incomplete_type)) {
3520 continue;
3521 }
3522
3523 // A groupprivate variable must not have a reference type.
3524 if (VD->getType()->isReferenceType()) {
3525 Diag(Loc: ILoc, DiagID: diag::err_omp_ref_type_arg)
3526 << getOpenMPDirectiveName(D: OMPD_groupprivate) << VD->getType();
3527 bool IsDecl =
3528 VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
3529 Diag(Loc: VD->getLocation(),
3530 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
3531 << VD;
3532 continue;
3533 }
3534
3535 // A variable that is declared with an initializer must not appear in a
3536 // groupprivate directive.
3537 if (VD->getAnyInitializer()) {
3538 Diag(Loc: ILoc, DiagID: diag::err_omp_groupprivate_with_initializer)
3539 << VD->getDeclName();
3540 bool IsDecl =
3541 VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
3542 Diag(Loc: VD->getLocation(),
3543 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
3544 << VD;
3545 continue;
3546 }
3547
3548 Vars.push_back(Elt: RefExpr);
3549 DSAStack->addDSA(D: VD, E: DE, A: OMPC_groupprivate);
3550 VD->addAttr(A: OMPGroupPrivateDeclAttr::CreateImplicit(Ctx&: Context,
3551 Range: SourceRange(Loc, Loc)));
3552 if (ASTMutationListener *ML = Context.getASTMutationListener())
3553 ML->DeclarationMarkedOpenMPGroupPrivate(D: VD);
3554 }
3555 OMPGroupPrivateDecl *D = nullptr;
3556 if (!Vars.empty()) {
3557 D = OMPGroupPrivateDecl::Create(C&: Context, DC: SemaRef.getCurLexicalContext(),
3558 L: Loc, VL: Vars);
3559 D->setAccess(AS_public);
3560 }
3561 return D;
3562}
3563
3564static OMPAllocateDeclAttr::AllocatorTypeTy
3565getAllocatorKind(Sema &S, DSAStackTy *Stack, Expr *Allocator) {
3566 if (!Allocator)
3567 return OMPAllocateDeclAttr::OMPNullMemAlloc;
3568 if (Allocator->isTypeDependent() || Allocator->isValueDependent() ||
3569 Allocator->isInstantiationDependent() ||
3570 Allocator->containsUnexpandedParameterPack())
3571 return OMPAllocateDeclAttr::OMPUserDefinedMemAlloc;
3572 auto AllocatorKindRes = OMPAllocateDeclAttr::OMPUserDefinedMemAlloc;
3573 llvm::FoldingSetNodeID AEId;
3574 const Expr *AE = Allocator->IgnoreParenImpCasts();
3575 AE->IgnoreImpCasts()->Profile(ID&: AEId, Context: S.getASTContext(), /*Canonical=*/true);
3576 for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
3577 auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
3578 const Expr *DefAllocator = Stack->getAllocator(AllocatorKind);
3579 llvm::FoldingSetNodeID DAEId;
3580 DefAllocator->IgnoreImpCasts()->Profile(ID&: DAEId, Context: S.getASTContext(),
3581 /*Canonical=*/true);
3582 if (AEId == DAEId) {
3583 AllocatorKindRes = AllocatorKind;
3584 break;
3585 }
3586 }
3587 return AllocatorKindRes;
3588}
3589
3590static bool checkPreviousOMPAllocateAttribute(
3591 Sema &S, DSAStackTy *Stack, Expr *RefExpr, VarDecl *VD,
3592 OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind, Expr *Allocator) {
3593 if (!VD->hasAttr<OMPAllocateDeclAttr>())
3594 return false;
3595 const auto *A = VD->getAttr<OMPAllocateDeclAttr>();
3596 Expr *PrevAllocator = A->getAllocator();
3597 OMPAllocateDeclAttr::AllocatorTypeTy PrevAllocatorKind =
3598 getAllocatorKind(S, Stack, Allocator: PrevAllocator);
3599 bool AllocatorsMatch = AllocatorKind == PrevAllocatorKind;
3600 if (AllocatorsMatch &&
3601 AllocatorKind == OMPAllocateDeclAttr::OMPUserDefinedMemAlloc &&
3602 Allocator && PrevAllocator) {
3603 const Expr *AE = Allocator->IgnoreParenImpCasts();
3604 const Expr *PAE = PrevAllocator->IgnoreParenImpCasts();
3605 llvm::FoldingSetNodeID AEId, PAEId;
3606 AE->Profile(ID&: AEId, Context: S.Context, /*Canonical=*/true);
3607 PAE->Profile(ID&: PAEId, Context: S.Context, /*Canonical=*/true);
3608 AllocatorsMatch = AEId == PAEId;
3609 }
3610 if (!AllocatorsMatch) {
3611 SmallString<256> AllocatorBuffer;
3612 llvm::raw_svector_ostream AllocatorStream(AllocatorBuffer);
3613 if (Allocator)
3614 Allocator->printPretty(OS&: AllocatorStream, Helper: nullptr, Policy: S.getPrintingPolicy());
3615 SmallString<256> PrevAllocatorBuffer;
3616 llvm::raw_svector_ostream PrevAllocatorStream(PrevAllocatorBuffer);
3617 if (PrevAllocator)
3618 PrevAllocator->printPretty(OS&: PrevAllocatorStream, Helper: nullptr,
3619 Policy: S.getPrintingPolicy());
3620
3621 SourceLocation AllocatorLoc =
3622 Allocator ? Allocator->getExprLoc() : RefExpr->getExprLoc();
3623 SourceRange AllocatorRange =
3624 Allocator ? Allocator->getSourceRange() : RefExpr->getSourceRange();
3625 SourceLocation PrevAllocatorLoc =
3626 PrevAllocator ? PrevAllocator->getExprLoc() : A->getLocation();
3627 SourceRange PrevAllocatorRange =
3628 PrevAllocator ? PrevAllocator->getSourceRange() : A->getRange();
3629 S.Diag(Loc: AllocatorLoc, DiagID: diag::warn_omp_used_different_allocator)
3630 << (Allocator ? 1 : 0) << AllocatorStream.str()
3631 << (PrevAllocator ? 1 : 0) << PrevAllocatorStream.str()
3632 << AllocatorRange;
3633 S.Diag(Loc: PrevAllocatorLoc, DiagID: diag::note_omp_previous_allocator)
3634 << PrevAllocatorRange;
3635 return true;
3636 }
3637 return false;
3638}
3639
3640static void
3641applyOMPAllocateAttribute(Sema &S, VarDecl *VD,
3642 OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind,
3643 Expr *Allocator, Expr *Alignment, SourceRange SR) {
3644 if (VD->hasAttr<OMPAllocateDeclAttr>())
3645 return;
3646 if (Alignment &&
3647 (Alignment->isTypeDependent() || Alignment->isValueDependent() ||
3648 Alignment->isInstantiationDependent() ||
3649 Alignment->containsUnexpandedParameterPack()))
3650 // Apply later when we have a usable value.
3651 return;
3652 if (Allocator &&
3653 (Allocator->isTypeDependent() || Allocator->isValueDependent() ||
3654 Allocator->isInstantiationDependent() ||
3655 Allocator->containsUnexpandedParameterPack()))
3656 return;
3657 auto *A = OMPAllocateDeclAttr::CreateImplicit(Ctx&: S.Context, AllocatorType: AllocatorKind,
3658 Allocator, Alignment, Range: SR);
3659 VD->addAttr(A);
3660 if (ASTMutationListener *ML = S.Context.getASTMutationListener())
3661 ML->DeclarationMarkedOpenMPAllocate(D: VD, A);
3662}
3663
3664SemaOpenMP::DeclGroupPtrTy SemaOpenMP::ActOnOpenMPAllocateDirective(
3665 SourceLocation Loc, ArrayRef<Expr *> VarList, ArrayRef<OMPClause *> Clauses,
3666 DeclContext *Owner) {
3667 assert(Clauses.size() <= 2 && "Expected at most two clauses.");
3668 Expr *Alignment = nullptr;
3669 Expr *Allocator = nullptr;
3670 if (Clauses.empty()) {
3671 // OpenMP 5.0, 2.11.3 allocate Directive, Restrictions.
3672 // allocate directives that appear in a target region must specify an
3673 // allocator clause unless a requires directive with the dynamic_allocators
3674 // clause is present in the same compilation unit.
3675 if (getLangOpts().OpenMPIsTargetDevice &&
3676 !DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>())
3677 SemaRef.targetDiag(Loc, DiagID: diag::err_expected_allocator_clause);
3678 } else {
3679 for (const OMPClause *C : Clauses)
3680 if (const auto *AC = dyn_cast<OMPAllocatorClause>(Val: C))
3681 Allocator = AC->getAllocator();
3682 else if (const auto *AC = dyn_cast<OMPAlignClause>(Val: C))
3683 Alignment = AC->getAlignment();
3684 else
3685 llvm_unreachable("Unexpected clause on allocate directive");
3686 }
3687 OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind =
3688 getAllocatorKind(S&: SemaRef, DSAStack, Allocator);
3689 SmallVector<Expr *, 8> Vars;
3690 for (Expr *RefExpr : VarList) {
3691 auto *DE = cast<DeclRefExpr>(Val: RefExpr);
3692 auto *VD = cast<VarDecl>(Val: DE->getDecl());
3693
3694 // Check if this is a TLS variable or global register.
3695 if (VD->getTLSKind() != VarDecl::TLS_None ||
3696 VD->hasAttr<OMPThreadPrivateDeclAttr>() ||
3697 (VD->getStorageClass() == SC_Register && VD->hasAttr<AsmLabelAttr>() &&
3698 !VD->isLocalVarDecl()))
3699 continue;
3700
3701 // If the used several times in the allocate directive, the same allocator
3702 // must be used.
3703 if (checkPreviousOMPAllocateAttribute(S&: SemaRef, DSAStack, RefExpr, VD,
3704 AllocatorKind, Allocator))
3705 continue;
3706
3707 // OpenMP, 2.11.3 allocate Directive, Restrictions, C / C++
3708 // If a list item has a static storage type, the allocator expression in the
3709 // allocator clause must be a constant expression that evaluates to one of
3710 // the predefined memory allocator values.
3711 if (Allocator && VD->hasGlobalStorage()) {
3712 if (AllocatorKind == OMPAllocateDeclAttr::OMPUserDefinedMemAlloc) {
3713 Diag(Loc: Allocator->getExprLoc(),
3714 DiagID: diag::err_omp_expected_predefined_allocator)
3715 << Allocator->getSourceRange();
3716 bool IsDecl = VD->isThisDeclarationADefinition(getASTContext()) ==
3717 VarDecl::DeclarationOnly;
3718 Diag(Loc: VD->getLocation(),
3719 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
3720 << VD;
3721 continue;
3722 }
3723 }
3724
3725 Vars.push_back(Elt: RefExpr);
3726 applyOMPAllocateAttribute(S&: SemaRef, VD, AllocatorKind, Allocator, Alignment,
3727 SR: DE->getSourceRange());
3728 }
3729 if (Vars.empty())
3730 return nullptr;
3731 if (!Owner)
3732 Owner = SemaRef.getCurLexicalContext();
3733 auto *D = OMPAllocateDecl::Create(C&: getASTContext(), DC: Owner, L: Loc, VL: Vars, CL: Clauses);
3734 D->setAccess(AS_public);
3735 Owner->addDecl(D);
3736 return DeclGroupPtrTy::make(P: DeclGroupRef(D));
3737}
3738
3739SemaOpenMP::DeclGroupPtrTy
3740SemaOpenMP::ActOnOpenMPRequiresDirective(SourceLocation Loc,
3741 ArrayRef<OMPClause *> ClauseList) {
3742 OMPRequiresDecl *D = nullptr;
3743 if (!SemaRef.CurContext->isFileContext()) {
3744 Diag(Loc, DiagID: diag::err_omp_invalid_scope) << "requires";
3745 } else {
3746 D = CheckOMPRequiresDecl(Loc, Clauses: ClauseList);
3747 if (D) {
3748 SemaRef.CurContext->addDecl(D);
3749 DSAStack->addRequiresDecl(RD: D);
3750 }
3751 }
3752 return DeclGroupPtrTy::make(P: DeclGroupRef(D));
3753}
3754
3755void SemaOpenMP::ActOnOpenMPAssumesDirective(SourceLocation Loc,
3756 OpenMPDirectiveKind DKind,
3757 ArrayRef<std::string> Assumptions,
3758 bool SkippedClauses) {
3759 if (!SkippedClauses && Assumptions.empty()) {
3760 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
3761 Diag(Loc, DiagID: diag::err_omp_no_clause_for_directive)
3762 << llvm::omp::getAllAssumeClauseOptions()
3763 << llvm::omp::getOpenMPDirectiveName(D: DKind, V: OMPVersion);
3764 }
3765
3766 auto *AA =
3767 OMPAssumeAttr::Create(Ctx&: getASTContext(), Assumption: llvm::join(R&: Assumptions, Separator: ","), Range: Loc);
3768 if (DKind == llvm::omp::Directive::OMPD_begin_assumes) {
3769 OMPAssumeScoped.push_back(Elt: AA);
3770 return;
3771 }
3772
3773 // Global assumes without assumption clauses are ignored.
3774 if (Assumptions.empty())
3775 return;
3776
3777 assert(DKind == llvm::omp::Directive::OMPD_assumes &&
3778 "Unexpected omp assumption directive!");
3779 OMPAssumeGlobal.push_back(Elt: AA);
3780
3781 // The OMPAssumeGlobal scope above will take care of new declarations but
3782 // we also want to apply the assumption to existing ones, e.g., to
3783 // declarations in included headers. To this end, we traverse all existing
3784 // declaration contexts and annotate function declarations here.
3785 SmallVector<DeclContext *, 8> DeclContexts;
3786 auto *Ctx = SemaRef.CurContext;
3787 while (Ctx->getLexicalParent())
3788 Ctx = Ctx->getLexicalParent();
3789 DeclContexts.push_back(Elt: Ctx);
3790 while (!DeclContexts.empty()) {
3791 DeclContext *DC = DeclContexts.pop_back_val();
3792 for (auto *SubDC : DC->decls()) {
3793 if (SubDC->isInvalidDecl())
3794 continue;
3795 if (auto *CTD = dyn_cast<ClassTemplateDecl>(Val: SubDC)) {
3796 DeclContexts.push_back(Elt: CTD->getTemplatedDecl());
3797 llvm::append_range(C&: DeclContexts, R: CTD->specializations());
3798 continue;
3799 }
3800 if (auto *DC = dyn_cast<DeclContext>(Val: SubDC))
3801 DeclContexts.push_back(Elt: DC);
3802 if (auto *F = dyn_cast<FunctionDecl>(Val: SubDC)) {
3803 F->addAttr(A: AA);
3804 continue;
3805 }
3806 }
3807 }
3808}
3809
3810void SemaOpenMP::ActOnOpenMPEndAssumesDirective() {
3811 assert(isInOpenMPAssumeScope() && "Not in OpenMP assumes scope!");
3812 OMPAssumeScoped.pop_back();
3813}
3814
3815StmtResult SemaOpenMP::ActOnOpenMPAssumeDirective(ArrayRef<OMPClause *> Clauses,
3816 Stmt *AStmt,
3817 SourceLocation StartLoc,
3818 SourceLocation EndLoc) {
3819 if (!AStmt)
3820 return StmtError();
3821
3822 return OMPAssumeDirective::Create(Ctx: getASTContext(), StartLoc, EndLoc, Clauses,
3823 AStmt);
3824}
3825
3826OMPRequiresDecl *
3827SemaOpenMP::CheckOMPRequiresDecl(SourceLocation Loc,
3828 ArrayRef<OMPClause *> ClauseList) {
3829 /// For target specific clauses, the requires directive cannot be
3830 /// specified after the handling of any of the target regions in the
3831 /// current compilation unit.
3832 ArrayRef<SourceLocation> TargetLocations =
3833 DSAStack->getEncounteredTargetLocs();
3834 SourceLocation AtomicLoc = DSAStack->getAtomicDirectiveLoc();
3835 if (!TargetLocations.empty() || !AtomicLoc.isInvalid()) {
3836 for (const OMPClause *CNew : ClauseList) {
3837 // Check if any of the requires clauses affect target regions.
3838 if (isa<OMPUnifiedSharedMemoryClause>(Val: CNew) ||
3839 isa<OMPUnifiedAddressClause>(Val: CNew) ||
3840 isa<OMPReverseOffloadClause>(Val: CNew) ||
3841 isa<OMPDynamicAllocatorsClause>(Val: CNew)) {
3842 Diag(Loc, DiagID: diag::err_omp_directive_before_requires)
3843 << "target" << getOpenMPClauseNameForDiag(C: CNew->getClauseKind());
3844 for (SourceLocation TargetLoc : TargetLocations) {
3845 Diag(Loc: TargetLoc, DiagID: diag::note_omp_requires_encountered_directive)
3846 << "target";
3847 }
3848 } else if (!AtomicLoc.isInvalid() &&
3849 isa<OMPAtomicDefaultMemOrderClause>(Val: CNew)) {
3850 Diag(Loc, DiagID: diag::err_omp_directive_before_requires)
3851 << "atomic" << getOpenMPClauseNameForDiag(C: CNew->getClauseKind());
3852 Diag(Loc: AtomicLoc, DiagID: diag::note_omp_requires_encountered_directive)
3853 << "atomic";
3854 }
3855 }
3856 }
3857
3858 if (!DSAStack->hasDuplicateRequiresClause(ClauseList))
3859 return OMPRequiresDecl::Create(
3860 C&: getASTContext(), DC: SemaRef.getCurLexicalContext(), L: Loc, CL: ClauseList);
3861 return nullptr;
3862}
3863
3864static void reportOriginalDsa(Sema &SemaRef, const DSAStackTy *Stack,
3865 const ValueDecl *D,
3866 const DSAStackTy::DSAVarData &DVar,
3867 bool IsLoopIterVar) {
3868 if (DVar.RefExpr) {
3869 SemaRef.Diag(Loc: DVar.RefExpr->getExprLoc(), DiagID: diag::note_omp_explicit_dsa)
3870 << getOpenMPClauseNameForDiag(C: DVar.CKind);
3871 return;
3872 }
3873 enum {
3874 PDSA_StaticMemberShared,
3875 PDSA_StaticLocalVarShared,
3876 PDSA_LoopIterVarPrivate,
3877 PDSA_LoopIterVarLinear,
3878 PDSA_LoopIterVarLastprivate,
3879 PDSA_ConstVarShared,
3880 PDSA_GlobalVarShared,
3881 PDSA_TaskVarFirstprivate,
3882 PDSA_LocalVarPrivate,
3883 PDSA_Implicit
3884 } Reason = PDSA_Implicit;
3885 bool ReportHint = false;
3886 auto ReportLoc = D->getLocation();
3887 auto *VD = dyn_cast<VarDecl>(Val: D);
3888 if (IsLoopIterVar) {
3889 if (DVar.CKind == OMPC_private)
3890 Reason = PDSA_LoopIterVarPrivate;
3891 else if (DVar.CKind == OMPC_lastprivate)
3892 Reason = PDSA_LoopIterVarLastprivate;
3893 else
3894 Reason = PDSA_LoopIterVarLinear;
3895 } else if (isOpenMPTaskingDirective(Kind: DVar.DKind) &&
3896 DVar.CKind == OMPC_firstprivate) {
3897 Reason = PDSA_TaskVarFirstprivate;
3898 ReportLoc = DVar.ImplicitDSALoc;
3899 } else if (VD && VD->isStaticLocal())
3900 Reason = PDSA_StaticLocalVarShared;
3901 else if (VD && VD->isStaticDataMember())
3902 Reason = PDSA_StaticMemberShared;
3903 else if (VD && VD->isFileVarDecl())
3904 Reason = PDSA_GlobalVarShared;
3905 else if (D->getType().isConstant(Ctx: SemaRef.getASTContext()))
3906 Reason = PDSA_ConstVarShared;
3907 else if (VD && VD->isLocalVarDecl() && DVar.CKind == OMPC_private) {
3908 ReportHint = true;
3909 Reason = PDSA_LocalVarPrivate;
3910 }
3911 if (Reason != PDSA_Implicit) {
3912 llvm::omp::Version OMPVersion = SemaRef.getLangOpts().getOpenMPVersion();
3913 SemaRef.Diag(Loc: ReportLoc, DiagID: diag::note_omp_predetermined_dsa)
3914 << Reason << ReportHint
3915 << getOpenMPDirectiveName(D: Stack->getCurrentDirective(), V: OMPVersion);
3916 } else if (DVar.ImplicitDSALoc.isValid()) {
3917 SemaRef.Diag(Loc: DVar.ImplicitDSALoc, DiagID: diag::note_omp_implicit_dsa)
3918 << getOpenMPClauseNameForDiag(C: DVar.CKind);
3919 }
3920}
3921
3922namespace {
3923/// Visitor to collect variables used in a statement.
3924class VarUsageVisitor : public DynamicRecursiveASTVisitor {
3925 llvm::SmallPtrSet<const VarDecl *, 8> &UsedVars;
3926 llvm::SmallPtrSet<const BindingDecl *, 8> &UsedBindings;
3927
3928public:
3929 VarUsageVisitor(llvm::SmallPtrSet<const VarDecl *, 8> &UsedVars,
3930 llvm::SmallPtrSet<const BindingDecl *, 8> &UsedBindings)
3931 : UsedVars(UsedVars), UsedBindings(UsedBindings) {}
3932
3933 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
3934 if (auto *VD = dyn_cast<VarDecl>(Val: DRE->getDecl()))
3935 UsedVars.insert(Ptr: cast<VarDecl>(Val: VD->getCanonicalDecl()));
3936 else if (auto *BD = dyn_cast<BindingDecl>(Val: DRE->getDecl()))
3937 UsedBindings.insert(Ptr: cast<BindingDecl>(Val: BD->getCanonicalDecl()));
3938 return true;
3939 }
3940};
3941} // namespace
3942
3943/// Check if bindings from the same structured binding have conflicting
3944/// capture kinds (by-ref vs by-copy). Bindings share the underlying
3945/// DecompositionDecl storage, so mixing by-ref and by-copy clauses on
3946/// different bindings from the same decomposition is not representable.
3947/// For example: map(a) creates by-ref, firstprivate(b) creates by-copy.
3948static bool checkDecompositionCaptureConflict(
3949 Sema &SemaRef, OpenMPDirectiveKind DKind,
3950 llvm::SmallDenseMap<const DecompositionDecl *,
3951 std::pair<bool, SourceLocation>, 4> &SeenDecompositions,
3952 const ValueDecl *D, SourceLocation ELoc, OpenMPClauseKind ClauseKind) {
3953 const auto *BD = dyn_cast<BindingDecl>(Val: D);
3954 if (!BD)
3955 return false;
3956
3957 const auto *DD = dyn_cast<DecompositionDecl>(Val: BD->getDecomposedDecl());
3958 if (!DD)
3959 return false;
3960
3961 // Determine if this clause creates by-ref or by-copy capture.
3962 bool IsByRef = false;
3963 switch (ClauseKind) {
3964 case OMPC_map:
3965 case OMPC_shared:
3966 // Map and shared clauses are by-reference.
3967 IsByRef = true;
3968 break;
3969 case OMPC_firstprivate:
3970 case OMPC_private:
3971 case OMPC_lastprivate:
3972 // These are by-copy.
3973 IsByRef = false;
3974 break;
3975 default:
3976 // Other clauses don't create capture conflicts.
3977 return false;
3978 }
3979 auto [It, Inserted] = SeenDecompositions.insert(KV: {DD, {IsByRef, ELoc}});
3980 if (!Inserted && It->second.first != IsByRef) {
3981 // Conflict: same DecompositionDecl needs both by-ref and by-copy
3982 // Emit diagnostic showing the binding name, not the decomposition.
3983 SemaRef.Diag(Loc: ELoc,
3984 DiagID: diag::err_omp_decomposition_bindings_different_capture_kinds)
3985 << BD;
3986 return true;
3987 }
3988 return false;
3989}
3990
3991/// Helper to check all clauses in a directive for structured binding
3992/// capture conflicts. Returns true if an error was found. If Body is
3993/// provided and the directive has default(shared), bindings used in the
3994/// body but not listed in explicit clauses are treated as implicit
3995/// shared (by-reference).
3996static bool checkClausesForDecompositionConflicts(Sema &SemaRef,
3997 OpenMPDirectiveKind DKind,
3998 ArrayRef<OMPClause *> Clauses,
3999 Stmt *Body = nullptr) {
4000 llvm::SmallDenseMap<const DecompositionDecl *,
4001 std::pair<bool, SourceLocation>, 4>
4002 SeenDecompositions;
4003 llvm::SmallPtrSet<const BindingDecl *, 8> ExplicitBindings;
4004 bool HasError = false;
4005 bool HasDefaultShared = false;
4006 SourceLocation DefaultSharedLoc;
4007 for (OMPClause *C : Clauses) {
4008 if (auto *DC = dyn_cast<OMPDefaultClause>(Val: C)) {
4009 if (DC->getDefaultKind() == llvm::omp::DefaultKind::OMP_DEFAULT_shared) {
4010 HasDefaultShared = true;
4011 DefaultSharedLoc = DC->getBeginLoc();
4012 }
4013 continue;
4014 }
4015 OpenMPClauseKind CK = C->getClauseKind();
4016 if (CK != OMPC_map && CK != OMPC_firstprivate && CK != OMPC_private &&
4017 CK != OMPC_shared && CK != OMPC_lastprivate)
4018 continue;
4019 ArrayRef<Expr *> Varlist;
4020 if (auto *MPC = dyn_cast<OMPMapClause>(Val: C))
4021 Varlist = MPC->varlist();
4022 else if (auto *FPC = dyn_cast<OMPFirstprivateClause>(Val: C))
4023 Varlist = FPC->varlist();
4024 else if (auto *PC = dyn_cast<OMPPrivateClause>(Val: C))
4025 Varlist = PC->varlist();
4026 else if (auto *SC = dyn_cast<OMPSharedClause>(Val: C))
4027 Varlist = SC->varlist();
4028 else if (auto *LPC = dyn_cast<OMPLastprivateClause>(Val: C))
4029 Varlist = LPC->varlist();
4030
4031 for (Expr *VE : Varlist) {
4032 if (auto *DRE = dyn_cast<DeclRefExpr>(Val: VE->IgnoreParenImpCasts())) {
4033 ValueDecl *D = DRE->getDecl();
4034 // Look through OMPCapturedExprDecl (used when clauses reference
4035 // variables from an enclosing captured region) to find the
4036 // underlying BindingDecl.
4037 if (auto *CED = dyn_cast<OMPCapturedExprDecl>(Val: D)) {
4038 if (auto *InitDRE =
4039 dyn_cast<DeclRefExpr>(Val: CED->getInit()->IgnoreParenImpCasts()))
4040 D = InitDRE->getDecl();
4041 }
4042 if (auto *BD = dyn_cast<BindingDecl>(Val: D))
4043 ExplicitBindings.insert(Ptr: cast<BindingDecl>(Val: BD->getCanonicalDecl()));
4044 if (checkDecompositionCaptureConflict(
4045 SemaRef, DKind, SeenDecompositions, D, ELoc: VE->getExprLoc(), ClauseKind: CK))
4046 HasError = true;
4047 }
4048 }
4049 }
4050
4051 // With default(shared), bindings used in the body but not in an explicit
4052 // clause become implicit shared (by-reference). Check those for conflicts
4053 // with explicit by-copy clauses on the same decomposition.
4054 if (HasDefaultShared && Body) {
4055 llvm::SmallPtrSet<const VarDecl *, 8> UsedVars;
4056 llvm::SmallPtrSet<const BindingDecl *, 8> UsedBindings;
4057 VarUsageVisitor Visitor(UsedVars, UsedBindings);
4058 Visitor.TraverseStmt(S: Body);
4059 for (const BindingDecl *BD : UsedBindings) {
4060 if (ExplicitBindings.contains(Ptr: BD))
4061 continue;
4062 if (checkDecompositionCaptureConflict(SemaRef, DKind, SeenDecompositions,
4063 D: BD, ELoc: DefaultSharedLoc, ClauseKind: OMPC_shared))
4064 HasError = true;
4065 }
4066 }
4067 return HasError;
4068}
4069
4070/// Check if original variable is explicitly mapped but only bindings are used.
4071/// Returns true if an error was found.
4072static bool checkOriginalVarMappedButOnlyBindingsUsed(
4073 Sema &SemaRef, ArrayRef<OMPClause *> Clauses, Stmt *Body) {
4074 llvm::SmallDenseMap<const VarDecl *, SourceLocation, 4> MappedOrigVars;
4075
4076 for (OMPClause *C : Clauses) {
4077 if (auto *MPC = dyn_cast<OMPMapClause>(Val: C)) {
4078 for (Expr *VE : MPC->varlist()) {
4079 if (auto *DRE = dyn_cast<DeclRefExpr>(Val: VE->IgnoreParenImpCasts())) {
4080 if (auto *VD = dyn_cast<VarDecl>(Val: DRE->getDecl())) {
4081 MappedOrigVars[VD->getCanonicalDecl()] = VE->getExprLoc();
4082 }
4083 }
4084 }
4085 }
4086 }
4087 if (MappedOrigVars.empty())
4088 return false;
4089
4090 llvm::SmallPtrSet<const VarDecl *, 8> UsedVars;
4091 llvm::SmallPtrSet<const BindingDecl *, 8> UsedBindings;
4092 VarUsageVisitor Visitor(UsedVars, UsedBindings);
4093 Visitor.TraverseStmt(S: Body);
4094 bool HasError = false;
4095 for (const auto &Entry : MappedOrigVars) {
4096 const VarDecl *OrigVar = Entry.first;
4097 SourceLocation Loc = Entry.second;
4098
4099 // Check if this original variable has bindings that are used.
4100 // For reference bindings (`auto &[a, b] = p`), the bindings alias the
4101 // original variable, so mapping `p` covers them correctly.
4102 bool BindingsFromThisVarUsed = false;
4103 for (const BindingDecl *BD : UsedBindings) {
4104 if (auto *DD = dyn_cast<DecompositionDecl>(Val: BD->getDecomposedDecl())) {
4105 if (DD->getType()->isReferenceType())
4106 continue;
4107 if (auto *OrigFromDD = DD->getOriginalVar().Var) {
4108 if (OrigFromDD->getCanonicalDecl() == OrigVar) {
4109 BindingsFromThisVarUsed = true;
4110 break;
4111 }
4112 }
4113 }
4114 }
4115
4116 // Error if: original is mapped, bindings are used, but original is not
4117 // used.
4118 if (BindingsFromThisVarUsed && !UsedVars.count(Ptr: OrigVar)) {
4119 SemaRef.Diag(Loc, DiagID: diag::err_omp_original_var_mapped_bindings_only_used)
4120 << OrigVar;
4121 HasError = true;
4122 }
4123 }
4124
4125 return HasError;
4126}
4127
4128static OpenMPMapClauseKind
4129getMapClauseKindFromModifier(OpenMPDefaultmapClauseModifier M,
4130 bool IsAggregateOrDeclareTarget,
4131 bool HasConstQualifier) {
4132 OpenMPMapClauseKind Kind = OMPC_MAP_unknown;
4133 switch (M) {
4134 case OMPC_DEFAULTMAP_MODIFIER_alloc:
4135 case OMPC_DEFAULTMAP_MODIFIER_storage:
4136 Kind = OMPC_MAP_alloc;
4137 break;
4138 case OMPC_DEFAULTMAP_MODIFIER_to:
4139 Kind = OMPC_MAP_to;
4140 break;
4141 case OMPC_DEFAULTMAP_MODIFIER_from:
4142 Kind = OMPC_MAP_from;
4143 break;
4144 case OMPC_DEFAULTMAP_MODIFIER_tofrom:
4145 Kind = OMPC_MAP_tofrom;
4146 break;
4147 case OMPC_DEFAULTMAP_MODIFIER_present:
4148 // OpenMP 5.1 [2.21.7.3] defaultmap clause, Description]
4149 // If implicit-behavior is present, each variable referenced in the
4150 // construct in the category specified by variable-category is treated as if
4151 // it had been listed in a map clause with the map-type of alloc and
4152 // map-type-modifier of present.
4153 Kind = OMPC_MAP_alloc;
4154 break;
4155 case OMPC_DEFAULTMAP_MODIFIER_firstprivate:
4156 case OMPC_DEFAULTMAP_MODIFIER_private:
4157 case OMPC_DEFAULTMAP_MODIFIER_last:
4158 llvm_unreachable("Unexpected defaultmap implicit behavior");
4159 case OMPC_DEFAULTMAP_MODIFIER_none:
4160 case OMPC_DEFAULTMAP_MODIFIER_default:
4161 case OMPC_DEFAULTMAP_MODIFIER_unknown:
4162 // IsAggregateOrDeclareTarget could be true if:
4163 // 1. the implicit behavior for aggregate is tofrom
4164 // 2. it's a declare target link
4165 if (IsAggregateOrDeclareTarget) {
4166 if (HasConstQualifier)
4167 Kind = OMPC_MAP_to;
4168 else
4169 Kind = OMPC_MAP_tofrom;
4170 break;
4171 }
4172 llvm_unreachable("Unexpected defaultmap implicit behavior");
4173 }
4174 assert(Kind != OMPC_MAP_unknown && "Expect map kind to be known");
4175 return Kind;
4176}
4177
4178static bool hasNoMutableFields(const CXXRecordDecl *RD) {
4179 for (const auto *FD : RD->fields()) {
4180 if (FD->isMutable())
4181 return false;
4182 QualType FT = FD->getType();
4183 while (FT->isArrayType())
4184 FT = FT->getAsArrayTypeUnsafe()->getElementType();
4185 if (const auto *NestedRD = FT->getAsCXXRecordDecl())
4186 if (!hasNoMutableFields(RD: NestedRD))
4187 return false;
4188 }
4189 return true;
4190}
4191
4192static bool hasConstQualifiedMappingType(QualType T) {
4193 while (T->isArrayType())
4194 T = T->getAsArrayTypeUnsafe()->getElementType();
4195 if (!T.isConstQualified())
4196 return false;
4197 if (const auto *RD = T->getAsCXXRecordDecl())
4198 // TODO : Per OpenMP 6.0 p299 lines 3-4, non-mutable members of a
4199 // const-qualified struct should also be ignored for 'from'. This
4200 // requires per-member mapping granularity via compiler-generated
4201 // default mappers and a mechanism to ensure constness to the mapper.
4202 // For now we conservatively treat any struct with mutable members as
4203 // requiring full 'tofrom'.
4204 return hasNoMutableFields(RD);
4205 return true;
4206}
4207
4208namespace {
4209/// Try to extract the original variable from a DecompositionDecl.
4210/// If extraction fails, emit a diagnostic. Returns the original VarDecl* on
4211/// success, nullptr on failure.
4212static const VarDecl *getOriginalVarOrDiagnose(Sema &S,
4213 const DecompositionDecl *DD,
4214 SourceLocation Loc) {
4215 auto Result = DD->getOriginalVar();
4216 if (!Result.Var)
4217 S.Diag(Loc, DiagID: diag::err_omp_unsupported_structured_binding_init)
4218 << Result.DiagKind;
4219 return Result.Var;
4220}
4221
4222struct VariableImplicitInfo {
4223 static const unsigned MapKindNum = OMPC_MAP_unknown;
4224 static const unsigned DefaultmapKindNum = OMPC_DEFAULTMAP_unknown + 1;
4225
4226 llvm::SetVector<Expr *> Privates;
4227 llvm::SetVector<Expr *> Firstprivates;
4228 llvm::SetVector<Expr *> Mappings[DefaultmapKindNum][MapKindNum];
4229 llvm::SmallVector<OpenMPMapModifierKind, NumberOfOMPMapClauseModifiers>
4230 MapModifiers[DefaultmapKindNum];
4231};
4232
4233class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
4234 DSAStackTy *Stack;
4235 Sema &SemaRef;
4236 OpenMPDirectiveKind DKind = OMPD_unknown;
4237 bool ErrorFound = false;
4238 bool TryCaptureCXXThisMembers = false;
4239 CapturedStmt *CS = nullptr;
4240
4241 VariableImplicitInfo ImpInfo;
4242 SemaOpenMP::VarsWithInheritedDSAType VarsWithInheritedDSA;
4243 llvm::SmallDenseSet<const ValueDecl *, 4> ImplicitDeclarations;
4244
4245 void VisitSubCaptures(OMPExecutableDirective *S) {
4246 // Check implicitly captured variables.
4247 if (!S->hasAssociatedStmt() || !S->getAssociatedStmt())
4248 return;
4249 if (S->getDirectiveKind() == OMPD_atomic ||
4250 S->getDirectiveKind() == OMPD_critical ||
4251 S->getDirectiveKind() == OMPD_section ||
4252 S->getDirectiveKind() == OMPD_master ||
4253 S->getDirectiveKind() == OMPD_masked ||
4254 S->getDirectiveKind() == OMPD_scope ||
4255 S->getDirectiveKind() == OMPD_assume ||
4256 isOpenMPLoopTransformationDirective(DKind: S->getDirectiveKind())) {
4257 Visit(S: S->getAssociatedStmt());
4258 return;
4259 }
4260 visitSubCaptures(S: S->getInnermostCapturedStmt());
4261 // Try to capture inner this->member references to generate correct mappings
4262 // and diagnostics.
4263 if (TryCaptureCXXThisMembers ||
4264 (isOpenMPTargetExecutionDirective(DKind) &&
4265 llvm::any_of(Range: S->getInnermostCapturedStmt()->captures(),
4266 P: [](const CapturedStmt::Capture &C) {
4267 return C.capturesThis();
4268 }))) {
4269 bool SavedTryCaptureCXXThisMembers = TryCaptureCXXThisMembers;
4270 TryCaptureCXXThisMembers = true;
4271 Visit(S: S->getInnermostCapturedStmt()->getCapturedStmt());
4272 TryCaptureCXXThisMembers = SavedTryCaptureCXXThisMembers;
4273 }
4274 // In tasks firstprivates are not captured anymore, need to analyze them
4275 // explicitly.
4276 if (isOpenMPTaskingDirective(Kind: S->getDirectiveKind()) &&
4277 !isOpenMPTaskLoopDirective(DKind: S->getDirectiveKind())) {
4278 for (OMPClause *C : S->clauses())
4279 if (auto *FC = dyn_cast<OMPFirstprivateClause>(Val: C)) {
4280 for (Expr *Ref : FC->varlist())
4281 Visit(S: Ref);
4282 }
4283 }
4284 }
4285
4286public:
4287 void VisitDeclRefExpr(DeclRefExpr *E) {
4288 if (TryCaptureCXXThisMembers || E->isTypeDependent() ||
4289 E->isValueDependent() || E->containsUnexpandedParameterPack() ||
4290 E->isInstantiationDependent() ||
4291 E->isNonOdrUse() == clang::NOUR_Unevaluated)
4292 return;
4293 ValueDecl *D = const_cast<ValueDecl *>(E->getDecl());
4294 BindingDecl *BD = dyn_cast<BindingDecl>(Val: D);
4295 if (BD)
4296 D = BD->getDecomposedDecl();
4297 if (auto *VD = dyn_cast<VarDecl>(Val: D)) {
4298 // For BindingDecls, use the original binding for DSA lookups;
4299 // fall back to DecompositionDecl if lookup fails.
4300 ValueDecl *LookupDecl = BD ? static_cast<ValueDecl *>(BD) : VD;
4301 // Check the datasharing rules for the expressions in the clauses.
4302 if (!CS || (isa<OMPCapturedExprDecl>(Val: VD) && !CS->capturesVariable(Var: VD) &&
4303 !Stack->getTopDSA(D: LookupDecl, /*FromParent=*/false).RefExpr &&
4304 !Stack->isImplicitDefaultFirstprivateFD(VD))) {
4305 if (auto *CED = dyn_cast<OMPCapturedExprDecl>(Val: VD))
4306 if (!CED->hasAttr<OMPCaptureNoInitAttr>()) {
4307 Visit(S: const_cast<Expr *>(CED->getInit()));
4308 return;
4309 }
4310 } else if (VD->isImplicit() || isa<OMPCapturedExprDecl>(Val: VD))
4311 // Do not analyze internal variables and do not enclose them into
4312 // implicit clauses.
4313 if (!Stack->isImplicitDefaultFirstprivateFD(VD))
4314 return;
4315 VD = VD->getCanonicalDecl();
4316 // Skip DecompositionDecls (but not BindingDecls in DSA contexts) -
4317 // they should be handled through explicit mapping of the original
4318 // variable or as member expressions. When bindings are captured,
4319 // the original variable is what needs to be mapped, not the
4320 // decomposition itself. However, BindingDecls need DSA checking for
4321 // default(none)/private/firstprivate contexts, but NOT in target
4322 // offloading contexts (where map clause handles them).
4323 if (isa<DecompositionDecl>(Val: VD)) {
4324 // For BindingDecls, continue checking only if:
4325 // - We are in a DSA context (tasking/parallel/worksharing/teams), or
4326 // - We are in a target context and the binding is scalar (implicit
4327 // firstprivate).
4328 bool InTargetAndScalar = BD &&
4329 isOpenMPTargetExecutionDirective(DKind) &&
4330 BD->getType()->isScalarType();
4331 if (!BD ||
4332 (isOpenMPTargetExecutionDirective(DKind) && !InTargetAndScalar) ||
4333 (!InTargetAndScalar && !isImplicitOrExplicitTaskingRegion(DKind) &&
4334 !isOpenMPParallelDirective(DKind) &&
4335 !isOpenMPWorksharingDirective(DKind) &&
4336 !isOpenMPTeamsDirective(DKind)))
4337 return;
4338 }
4339 // Skip internally declared variables.
4340 if (VD->hasLocalStorage() && CS && !CS->capturesVariable(Var: VD) &&
4341 !Stack->isImplicitDefaultFirstprivateFD(VD) &&
4342 !Stack->isImplicitTaskFirstprivate(D: VD))
4343 return;
4344 // Skip allocators in uses_allocators clauses.
4345 if (Stack->isUsesAllocatorsDecl(D: VD))
4346 return;
4347
4348 DSAStackTy::DSAVarData DVar =
4349 Stack->getTopDSA(D: LookupDecl, /*FromParent=*/false);
4350 // If lookup on BindingDecl failed, try on DecompositionDecl.
4351 if (BD && !DVar.RefExpr)
4352 DVar = Stack->getTopDSA(D: VD, /*FromParent=*/false);
4353 // Check if the variable has explicit DSA set and stop analysis if it so.
4354 if (DVar.RefExpr ||
4355 !ImplicitDeclarations
4356 .insert(V: cast<ValueDecl>(Val: LookupDecl->getCanonicalDecl()))
4357 .second)
4358 return;
4359
4360 // Skip internally declared static variables.
4361 std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
4362 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
4363 if (VD->hasGlobalStorage() && CS && !CS->capturesVariable(Var: VD) &&
4364 (Stack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() ||
4365 !Res || *Res != OMPDeclareTargetDeclAttr::MT_Link) &&
4366 !Stack->isImplicitDefaultFirstprivateFD(VD) &&
4367 !Stack->isImplicitTaskFirstprivate(D: VD))
4368 return;
4369
4370 SourceLocation ELoc = E->getExprLoc();
4371 // The default(none) clause requires that each variable that is referenced
4372 // in the construct, and does not have a predetermined data-sharing
4373 // attribute, must have its data-sharing attribute explicitly determined
4374 // by being listed in a data-sharing attribute clause.
4375 if (DVar.CKind == OMPC_unknown &&
4376 (Stack->getDefaultDSA() == DSA_none ||
4377 Stack->getDefaultDSA() == DSA_private ||
4378 Stack->getDefaultDSA() == DSA_firstprivate) &&
4379 isImplicitOrExplicitTaskingRegion(DKind) &&
4380 VarsWithInheritedDSA.count(Val: VD) == 0) {
4381 bool InheritedDSA = Stack->getDefaultDSA() == DSA_none;
4382 if (!InheritedDSA && (Stack->getDefaultDSA() == DSA_firstprivate ||
4383 Stack->getDefaultDSA() == DSA_private)) {
4384 DSAStackTy::DSAVarData DVar =
4385 Stack->getImplicitDSA(D: LookupDecl, /*FromParent=*/false);
4386 if (BD && DVar.CKind == OMPC_unknown)
4387 DVar = Stack->getImplicitDSA(D: VD, /*FromParent=*/false);
4388 InheritedDSA = DVar.CKind == OMPC_unknown;
4389 }
4390 if (InheritedDSA)
4391 VarsWithInheritedDSA[cast<ValueDecl>(
4392 Val: LookupDecl->getCanonicalDecl())] = E;
4393 if (Stack->getDefaultDSA() == DSA_none)
4394 return;
4395 }
4396
4397 // OpenMP 5.0 [2.19.7.2, defaultmap clause, Description]
4398 // If implicit-behavior is none, each variable referenced in the
4399 // construct that does not have a predetermined data-sharing attribute
4400 // and does not appear in a to or link clause on a declare target
4401 // directive must be listed in a data-mapping attribute clause, a
4402 // data-sharing attribute clause (including a data-sharing attribute
4403 // clause on a combined construct where target. is one of the
4404 // constituent constructs), or an is_device_ptr clause.
4405 // For BindingDecls, use the binding's type to determine category.
4406 OpenMPDefaultmapClauseKind ClauseKind = getVariableCategoryFromDecl(
4407 LO: SemaRef.getLangOpts(), VD: BD ? static_cast<const ValueDecl *>(BD)
4408 : static_cast<const ValueDecl *>(VD));
4409 if (SemaRef.getLangOpts().OpenMP >= 50) {
4410 bool IsModifierNone = Stack->getDefaultmapModifier(Kind: ClauseKind) ==
4411 OMPC_DEFAULTMAP_MODIFIER_none;
4412 if (DVar.CKind == OMPC_unknown && IsModifierNone &&
4413 VarsWithInheritedDSA.count(Val: VD) == 0 && !Res) {
4414 // Only check for data-mapping attribute and is_device_ptr here
4415 // since we have already make sure that the declaration does not
4416 // have a data-sharing attribute above
4417 if (!Stack->checkMappableExprComponentListsForDecl(
4418 VD, /*CurrentRegionOnly=*/true,
4419 Check: [VD](OMPClauseMappableExprCommon::MappableExprComponentListRef
4420 MapExprComponents,
4421 OpenMPClauseKind) {
4422 auto MI = MapExprComponents.rbegin();
4423 auto ME = MapExprComponents.rend();
4424 return MI != ME && MI->getAssociatedDeclaration() == VD;
4425 })) {
4426 VarsWithInheritedDSA[cast<ValueDecl>(
4427 Val: LookupDecl->getCanonicalDecl())] = E;
4428 return;
4429 }
4430 }
4431 }
4432 if (SemaRef.getLangOpts().OpenMP > 50) {
4433 bool IsModifierPresent = Stack->getDefaultmapModifier(Kind: ClauseKind) ==
4434 OMPC_DEFAULTMAP_MODIFIER_present;
4435 if (IsModifierPresent) {
4436 if (!llvm::is_contained(Range&: ImpInfo.MapModifiers[ClauseKind],
4437 Element: OMPC_MAP_MODIFIER_present)) {
4438 ImpInfo.MapModifiers[ClauseKind].push_back(
4439 Elt: OMPC_MAP_MODIFIER_present);
4440 }
4441 }
4442 }
4443
4444 if (isOpenMPTargetExecutionDirective(DKind) &&
4445 !Stack->isLoopControlVariable(D: VD).first) {
4446 // Check if VD is already mapped. For DecompositionDecls, also check if
4447 // the original variable they decompose has been mapped (via BindingDecl
4448 // map clauses).
4449 bool AlreadyMapped = Stack->checkMappableExprComponentListsForDecl(
4450 VD, /*CurrentRegionOnly=*/true, Check: [this](auto StackComponents, auto) {
4451 if (SemaRef.LangOpts.OpenMP >= 50)
4452 return !StackComponents.empty();
4453 // Variable is used if it has been marked as an array, array
4454 // section, array shaping or the variable itself.
4455 return StackComponents.size() == 1 ||
4456 llvm::all_of(
4457 llvm::drop_begin(llvm::reverse(StackComponents)),
4458 [](const auto &MC) {
4459 return MC.getAssociatedDeclaration() == nullptr &&
4460 (isa<ArraySectionExpr>(
4461 MC.getAssociatedExpression()) ||
4462 isa<OMPArrayShapingExpr>(
4463 MC.getAssociatedExpression()) ||
4464 isa<ArraySubscriptExpr>(
4465 MC.getAssociatedExpression()));
4466 });
4467 });
4468
4469 // For DecompositionDecls, check if the original variable has been
4470 // mapped.
4471 const auto *DD = dyn_cast<DecompositionDecl>(Val: VD);
4472 if (!AlreadyMapped && DD) {
4473 // Don't diagnose here. Just check if we can extract the original
4474 // var. Diagnostics happen when processing explicit map clauses.
4475 if (const VarDecl *OrigVar = DD->getOriginalVar().Var) {
4476 AlreadyMapped = Stack->checkMappableExprComponentListsForDecl(
4477 VD: OrigVar, /*CurrentRegionOnly=*/true,
4478 Check: [this](auto StackComponents, auto) {
4479 if (SemaRef.LangOpts.OpenMP >= 50)
4480 return !StackComponents.empty();
4481 return StackComponents.size() == 1;
4482 });
4483 }
4484 }
4485 if (!AlreadyMapped) {
4486 bool IsFirstprivate = false;
4487 // By default lambdas are captured as firstprivates.
4488 QualType CheckType = BD ? BD->getType() : VD->getType();
4489 if (const auto *RD =
4490 CheckType.getNonReferenceType()->getAsCXXRecordDecl())
4491 IsFirstprivate = RD->isLambda();
4492 IsFirstprivate =
4493 IsFirstprivate || (Stack->mustBeFirstprivate(Kind: ClauseKind) && !Res);
4494 if (IsFirstprivate) {
4495 ImpInfo.Firstprivates.insert(X: E);
4496 } else {
4497 OpenMPDefaultmapClauseModifier M =
4498 Stack->getDefaultmapModifier(Kind: ClauseKind);
4499 if (M == OMPC_DEFAULTMAP_MODIFIER_private) {
4500 ImpInfo.Privates.insert(X: E);
4501 } else {
4502 OpenMPMapClauseKind Kind = getMapClauseKindFromModifier(
4503 M, IsAggregateOrDeclareTarget: ClauseKind == OMPC_DEFAULTMAP_aggregate || Res,
4504 HasConstQualifier: hasConstQualifiedMappingType(T: E->getType()));
4505 ImpInfo.Mappings[ClauseKind][Kind].insert(X: E);
4506 }
4507 }
4508 return;
4509 }
4510 }
4511
4512 // OpenMP [2.9.3.6, Restrictions, p.2]
4513 // A list item that appears in a reduction clause of the innermost
4514 // enclosing worksharing or parallel construct may not be accessed in an
4515 // explicit task.
4516 DVar = Stack->hasInnermostDSA(
4517 D: LookupDecl,
4518 CPred: [](OpenMPClauseKind C, bool AppliedToPointee) {
4519 return C == OMPC_reduction && !AppliedToPointee;
4520 },
4521 DPred: [](OpenMPDirectiveKind K) {
4522 return isOpenMPParallelDirective(DKind: K) ||
4523 isOpenMPWorksharingDirective(DKind: K) || isOpenMPTeamsDirective(DKind: K);
4524 },
4525 /*FromParent=*/true);
4526 if (isOpenMPTaskingDirective(Kind: DKind) && DVar.CKind == OMPC_reduction) {
4527 ErrorFound = true;
4528 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_reduction_in_task);
4529 reportOriginalDsa(SemaRef, Stack, D: BD ? LookupDecl : VD, DVar);
4530 return;
4531 }
4532
4533 // Define implicit data-sharing attributes for task.
4534 DVar = Stack->getImplicitDSA(D: LookupDecl, /*FromParent=*/false);
4535 if (BD && DVar.CKind == OMPC_unknown)
4536 DVar = Stack->getImplicitDSA(D: VD, /*FromParent=*/false);
4537 if (((isOpenMPTaskingDirective(Kind: DKind) && DVar.CKind != OMPC_shared) ||
4538 (((Stack->getDefaultDSA() == DSA_firstprivate &&
4539 DVar.CKind == OMPC_firstprivate) ||
4540 (Stack->getDefaultDSA() == DSA_private &&
4541 DVar.CKind == OMPC_private)) &&
4542 !DVar.RefExpr)) &&
4543 !Stack->isLoopControlVariable(D: VD).first) {
4544 if (Stack->getDefaultDSA() == DSA_private)
4545 ImpInfo.Privates.insert(X: E);
4546 else
4547 ImpInfo.Firstprivates.insert(X: E);
4548 return;
4549 }
4550
4551 // Store implicitly used globals with declare target link for parent
4552 // target.
4553 if (!isOpenMPTargetExecutionDirective(DKind) && Res &&
4554 *Res == OMPDeclareTargetDeclAttr::MT_Link) {
4555 Stack->addToParentTargetRegionLinkGlobals(E);
4556 return;
4557 }
4558 }
4559 }
4560 void VisitMemberExpr(MemberExpr *E) {
4561 if (E->isTypeDependent() || E->isValueDependent() ||
4562 E->containsUnexpandedParameterPack() || E->isInstantiationDependent())
4563 return;
4564 auto *FD = dyn_cast<FieldDecl>(Val: E->getMemberDecl());
4565 if (auto *TE = dyn_cast<CXXThisExpr>(Val: E->getBase()->IgnoreParenCasts())) {
4566 if (!FD)
4567 return;
4568 DSAStackTy::DSAVarData DVar = Stack->getTopDSA(D: FD, /*FromParent=*/false);
4569 // Check if the variable has explicit DSA set and stop analysis if it
4570 // so.
4571 if (DVar.RefExpr || !ImplicitDeclarations.insert(V: FD).second)
4572 return;
4573
4574 if (isOpenMPTargetExecutionDirective(DKind) &&
4575 !Stack->isLoopControlVariable(D: FD).first &&
4576 !Stack->checkMappableExprComponentListsForDecl(
4577 VD: FD, /*CurrentRegionOnly=*/true,
4578 Check: [](OMPClauseMappableExprCommon::MappableExprComponentListRef
4579 StackComponents,
4580 OpenMPClauseKind) {
4581 return isa<CXXThisExpr>(
4582 Val: cast<MemberExpr>(
4583 Val: StackComponents.back().getAssociatedExpression())
4584 ->getBase()
4585 ->IgnoreParens());
4586 })) {
4587 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.3]
4588 // A bit-field cannot appear in a map clause.
4589 //
4590 if (FD->isBitField())
4591 return;
4592
4593 // Check to see if the member expression is referencing a class that
4594 // has already been explicitly mapped
4595 if (Stack->isClassPreviouslyMapped(QT: TE->getType()))
4596 return;
4597
4598 OpenMPDefaultmapClauseModifier Modifier =
4599 Stack->getDefaultmapModifier(Kind: OMPC_DEFAULTMAP_aggregate);
4600 OpenMPDefaultmapClauseKind ClauseKind =
4601 getVariableCategoryFromDecl(LO: SemaRef.getLangOpts(), VD: FD);
4602 OpenMPMapClauseKind Kind = getMapClauseKindFromModifier(
4603 M: Modifier, /*IsAggregateOrDeclareTarget=*/true,
4604 /*HasConstQualifier=*/false);
4605 ImpInfo.Mappings[ClauseKind][Kind].insert(X: E);
4606 return;
4607 }
4608
4609 SourceLocation ELoc = E->getExprLoc();
4610 // OpenMP [2.9.3.6, Restrictions, p.2]
4611 // A list item that appears in a reduction clause of the innermost
4612 // enclosing worksharing or parallel construct may not be accessed in
4613 // an explicit task.
4614 DVar = Stack->hasInnermostDSA(
4615 D: FD,
4616 CPred: [](OpenMPClauseKind C, bool AppliedToPointee) {
4617 return C == OMPC_reduction && !AppliedToPointee;
4618 },
4619 DPred: [](OpenMPDirectiveKind K) {
4620 return isOpenMPParallelDirective(DKind: K) ||
4621 isOpenMPWorksharingDirective(DKind: K) || isOpenMPTeamsDirective(DKind: K);
4622 },
4623 /*FromParent=*/true);
4624 if (isOpenMPTaskingDirective(Kind: DKind) && DVar.CKind == OMPC_reduction) {
4625 ErrorFound = true;
4626 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_reduction_in_task);
4627 reportOriginalDsa(SemaRef, Stack, D: FD, DVar);
4628 return;
4629 }
4630
4631 // Define implicit data-sharing attributes for task.
4632 DVar = Stack->getImplicitDSA(D: FD, /*FromParent=*/false);
4633 if (isOpenMPTaskingDirective(Kind: DKind) && DVar.CKind != OMPC_shared &&
4634 !Stack->isLoopControlVariable(D: FD).first) {
4635 // Check if there is a captured expression for the current field in the
4636 // region. Do not mark it as firstprivate unless there is no captured
4637 // expression.
4638 // TODO: try to make it firstprivate.
4639 if (DVar.CKind != OMPC_unknown)
4640 ImpInfo.Firstprivates.insert(X: E);
4641 }
4642 return;
4643 }
4644 if (isOpenMPTargetExecutionDirective(DKind)) {
4645 OMPClauseMappableExprCommon::MappableExprComponentList CurComponents;
4646 if (!checkMapClauseExpressionBase(SemaRef, E, CurComponents, CKind: OMPC_map,
4647 DKind, /*NoDiagnose=*/true))
4648 return;
4649 const auto *VD = cast<ValueDecl>(
4650 Val: CurComponents.back().getAssociatedDeclaration()->getCanonicalDecl());
4651 if (!Stack->checkMappableExprComponentListsForDecl(
4652 VD, /*CurrentRegionOnly=*/true,
4653 Check: [&CurComponents](
4654 OMPClauseMappableExprCommon::MappableExprComponentListRef
4655 StackComponents,
4656 OpenMPClauseKind) {
4657 auto CCI = CurComponents.rbegin();
4658 auto CCE = CurComponents.rend();
4659 for (const auto &SC : llvm::reverse(C&: StackComponents)) {
4660 // Do both expressions have the same kind?
4661 if (CCI->getAssociatedExpression()->getStmtClass() !=
4662 SC.getAssociatedExpression()->getStmtClass())
4663 if (!((isa<ArraySectionExpr>(
4664 Val: SC.getAssociatedExpression()) ||
4665 isa<OMPArrayShapingExpr>(
4666 Val: SC.getAssociatedExpression())) &&
4667 isa<ArraySubscriptExpr>(
4668 Val: CCI->getAssociatedExpression())))
4669 return false;
4670
4671 const Decl *CCD = CCI->getAssociatedDeclaration();
4672 const Decl *SCD = SC.getAssociatedDeclaration();
4673 CCD = CCD ? CCD->getCanonicalDecl() : nullptr;
4674 SCD = SCD ? SCD->getCanonicalDecl() : nullptr;
4675 if (SCD != CCD)
4676 return false;
4677 std::advance(i&: CCI, n: 1);
4678 if (CCI == CCE)
4679 break;
4680 }
4681 return true;
4682 })) {
4683 Visit(S: E->getBase());
4684 }
4685 } else if (!TryCaptureCXXThisMembers) {
4686 Visit(S: E->getBase());
4687 }
4688 }
4689 void VisitOMPExecutableDirective(OMPExecutableDirective *S) {
4690 for (OMPClause *C : S->clauses()) {
4691 // Skip analysis of arguments of private clauses for task|target
4692 // directives.
4693 if (isa_and_nonnull<OMPPrivateClause>(Val: C))
4694 continue;
4695 // Skip analysis of arguments of implicitly defined firstprivate clause
4696 // for task|target directives.
4697 // Skip analysis of arguments of implicitly defined map clause for target
4698 // directives.
4699 if (C && !((isa<OMPFirstprivateClause>(Val: C) || isa<OMPMapClause>(Val: C)) &&
4700 C->isImplicit() && !isOpenMPTaskingDirective(Kind: DKind))) {
4701 for (Stmt *CC : C->children()) {
4702 if (CC)
4703 Visit(S: CC);
4704 }
4705 }
4706 }
4707 // Check implicitly captured variables.
4708 VisitSubCaptures(S);
4709 }
4710
4711 void VisitOMPCanonicalLoopNestTransformationDirective(
4712 OMPCanonicalLoopNestTransformationDirective *S) {
4713 // Loop transformation directives do not introduce data sharing
4714 VisitStmt(S);
4715 }
4716
4717 void VisitCallExpr(CallExpr *S) {
4718 for (Stmt *C : S->arguments()) {
4719 if (C) {
4720 // Check implicitly captured variables in the task-based directives to
4721 // check if they must be firstprivatized.
4722 Visit(S: C);
4723 }
4724 }
4725 if (Expr *Callee = S->getCallee()) {
4726 auto *CI = Callee->IgnoreParenImpCasts();
4727 if (auto *CE = dyn_cast<MemberExpr>(Val: CI))
4728 Visit(S: CE->getBase());
4729 else if (auto *CE = dyn_cast<DeclRefExpr>(Val: CI))
4730 Visit(S: CE);
4731 }
4732 }
4733 void VisitStmt(Stmt *S) {
4734 for (Stmt *C : S->children()) {
4735 if (C) {
4736 // Check implicitly captured variables in the task-based directives to
4737 // check if they must be firstprivatized.
4738 Visit(S: C);
4739 }
4740 }
4741 }
4742
4743 void visitSubCaptures(CapturedStmt *S) {
4744 for (const CapturedStmt::Capture &Cap : S->captures()) {
4745 if (!Cap.capturesVariable() && !Cap.capturesVariableByCopy())
4746 continue;
4747 VarDecl *VD = Cap.getCapturedVar();
4748 // Do not try to map the variable if it or its sub-component was mapped
4749 // already.
4750 if (isOpenMPTargetExecutionDirective(DKind) &&
4751 Stack->checkMappableExprComponentListsForDecl(
4752 VD, /*CurrentRegionOnly=*/true,
4753 Check: [](OMPClauseMappableExprCommon::MappableExprComponentListRef,
4754 OpenMPClauseKind) { return true; }))
4755 continue;
4756 DeclRefExpr *DRE = buildDeclRefExpr(
4757 S&: SemaRef, D: VD, Ty: VD->getType().getNonLValueExprType(Context: SemaRef.Context),
4758 Loc: Cap.getLocation(), /*RefersToCapture=*/true);
4759 Visit(S: DRE);
4760 }
4761 }
4762 bool isErrorFound() const { return ErrorFound; }
4763 const VariableImplicitInfo &getImplicitInfo() const { return ImpInfo; }
4764 const SemaOpenMP::VarsWithInheritedDSAType &getVarsWithInheritedDSA() const {
4765 return VarsWithInheritedDSA;
4766 }
4767
4768 DSAAttrChecker(DSAStackTy *S, Sema &SemaRef, CapturedStmt *CS)
4769 : Stack(S), SemaRef(SemaRef), ErrorFound(false), CS(CS) {
4770 DKind = S->getCurrentDirective();
4771 // Process declare target link variables for the target directives.
4772 if (isOpenMPTargetExecutionDirective(DKind)) {
4773 for (DeclRefExpr *E : Stack->getLinkGlobals())
4774 Visit(S: E);
4775 }
4776 }
4777};
4778} // namespace
4779
4780static void handleDeclareVariantConstructTrait(DSAStackTy *Stack,
4781 OpenMPDirectiveKind DKind,
4782 bool ScopeEntry) {
4783 SmallVector<llvm::omp::TraitProperty, 8> Traits;
4784 if (isOpenMPTargetExecutionDirective(DKind))
4785 Traits.emplace_back(Args: llvm::omp::TraitProperty::construct_target_target);
4786 if (isOpenMPTeamsDirective(DKind))
4787 Traits.emplace_back(Args: llvm::omp::TraitProperty::construct_teams_teams);
4788 if (isOpenMPParallelDirective(DKind))
4789 Traits.emplace_back(Args: llvm::omp::TraitProperty::construct_parallel_parallel);
4790 if (isOpenMPWorksharingDirective(DKind))
4791 Traits.emplace_back(Args: llvm::omp::TraitProperty::construct_for_for);
4792 if (isOpenMPSimdDirective(DKind))
4793 Traits.emplace_back(Args: llvm::omp::TraitProperty::construct_simd_simd);
4794 Stack->handleConstructTrait(Traits, ScopeEntry);
4795}
4796
4797static SmallVector<SemaOpenMP::CapturedParamNameType>
4798getParallelRegionParams(Sema &SemaRef, bool LoopBoundSharing) {
4799 ASTContext &Context = SemaRef.getASTContext();
4800 QualType KmpInt32Ty =
4801 Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1).withConst();
4802 QualType KmpInt32PtrTy =
4803 Context.getPointerType(T: KmpInt32Ty).withConst().withRestrict();
4804 SmallVector<SemaOpenMP::CapturedParamNameType> Params{
4805 std::make_pair(x: ".global_tid.", y&: KmpInt32PtrTy),
4806 std::make_pair(x: ".bound_tid.", y&: KmpInt32PtrTy),
4807 };
4808 if (LoopBoundSharing) {
4809 QualType KmpSizeTy = Context.getSizeType().withConst();
4810 Params.push_back(Elt: std::make_pair(x: ".previous.lb.", y&: KmpSizeTy));
4811 Params.push_back(Elt: std::make_pair(x: ".previous.ub.", y&: KmpSizeTy));
4812 }
4813
4814 // __context with shared vars
4815 Params.push_back(Elt: std::make_pair(x: StringRef(), y: QualType()));
4816 return Params;
4817}
4818
4819static SmallVector<SemaOpenMP::CapturedParamNameType>
4820getTeamsRegionParams(Sema &SemaRef) {
4821 return getParallelRegionParams(SemaRef, /*LoopBoundSharing=*/false);
4822}
4823
4824static SmallVector<SemaOpenMP::CapturedParamNameType>
4825getTaskRegionParams(Sema &SemaRef) {
4826 ASTContext &Context = SemaRef.getASTContext();
4827 QualType KmpInt32Ty = Context.getIntTypeForBitwidth(DestWidth: 32, Signed: 1).withConst();
4828 QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict();
4829 QualType KmpInt32PtrTy =
4830 Context.getPointerType(T: KmpInt32Ty).withConst().withRestrict();
4831 QualType Args[] = {VoidPtrTy};
4832 FunctionProtoType::ExtProtoInfo EPI;
4833 EPI.Variadic = true;
4834 QualType CopyFnType = Context.getFunctionType(ResultTy: Context.VoidTy, Args, EPI);
4835 SmallVector<SemaOpenMP::CapturedParamNameType> Params{
4836 std::make_pair(x: ".global_tid.", y&: KmpInt32Ty),
4837 std::make_pair(x: ".part_id.", y&: KmpInt32PtrTy),
4838 std::make_pair(x: ".privates.", y&: VoidPtrTy),
4839 std::make_pair(
4840 x: ".copy_fn.",
4841 y: Context.getPointerType(T: CopyFnType).withConst().withRestrict()),
4842 std::make_pair(x: ".task_t.", y: Context.VoidPtrTy.withConst()),
4843 std::make_pair(x: StringRef(), y: QualType()) // __context with shared vars
4844 };
4845 return Params;
4846}
4847
4848static SmallVector<SemaOpenMP::CapturedParamNameType>
4849getTargetRegionParams(Sema &SemaRef) {
4850 ASTContext &Context = SemaRef.getASTContext();
4851 SmallVector<SemaOpenMP::CapturedParamNameType> Params;
4852 // __context with shared vars
4853 Params.push_back(Elt: std::make_pair(x: StringRef(), y: QualType()));
4854 // Implicit dyn_ptr argument, appended as the last parameter. Present on both
4855 // host and device so argument counts match without runtime manipulation.
4856 QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict();
4857 Params.push_back(Elt: std::make_pair(x: StringRef("dyn_ptr"), y&: VoidPtrTy));
4858 return Params;
4859}
4860
4861static SmallVector<SemaOpenMP::CapturedParamNameType>
4862getUnknownRegionParams(Sema &SemaRef) {
4863 SmallVector<SemaOpenMP::CapturedParamNameType> Params{
4864 std::make_pair(x: StringRef(), y: QualType()) // __context with shared vars
4865 };
4866 return Params;
4867}
4868
4869static SmallVector<SemaOpenMP::CapturedParamNameType>
4870getTaskloopRegionParams(Sema &SemaRef) {
4871 ASTContext &Context = SemaRef.getASTContext();
4872 QualType KmpInt32Ty =
4873 Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1).withConst();
4874 QualType KmpUInt64Ty =
4875 Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0).withConst();
4876 QualType KmpInt64Ty =
4877 Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1).withConst();
4878 QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict();
4879 QualType KmpInt32PtrTy =
4880 Context.getPointerType(T: KmpInt32Ty).withConst().withRestrict();
4881 QualType Args[] = {VoidPtrTy};
4882 FunctionProtoType::ExtProtoInfo EPI;
4883 EPI.Variadic = true;
4884 QualType CopyFnType = Context.getFunctionType(ResultTy: Context.VoidTy, Args, EPI);
4885 SmallVector<SemaOpenMP::CapturedParamNameType> Params{
4886 std::make_pair(x: ".global_tid.", y&: KmpInt32Ty),
4887 std::make_pair(x: ".part_id.", y&: KmpInt32PtrTy),
4888 std::make_pair(x: ".privates.", y&: VoidPtrTy),
4889 std::make_pair(
4890 x: ".copy_fn.",
4891 y: Context.getPointerType(T: CopyFnType).withConst().withRestrict()),
4892 std::make_pair(x: ".task_t.", y: Context.VoidPtrTy.withConst()),
4893 std::make_pair(x: ".lb.", y&: KmpUInt64Ty),
4894 std::make_pair(x: ".ub.", y&: KmpUInt64Ty),
4895 std::make_pair(x: ".st.", y&: KmpInt64Ty),
4896 std::make_pair(x: ".liter.", y&: KmpInt32Ty),
4897 std::make_pair(x: ".reductions.", y&: VoidPtrTy),
4898 std::make_pair(x: StringRef(), y: QualType()) // __context with shared vars
4899 };
4900 return Params;
4901}
4902
4903static void processCapturedRegions(Sema &SemaRef, OpenMPDirectiveKind DKind,
4904 Scope *CurScope, SourceLocation Loc) {
4905 SmallVector<OpenMPDirectiveKind> Regions;
4906 getOpenMPCaptureRegions(CaptureRegions&: Regions, DKind);
4907
4908 bool LoopBoundSharing = isOpenMPLoopBoundSharingDirective(Kind: DKind);
4909
4910 auto MarkAsInlined = [&](CapturedRegionScopeInfo *CSI) {
4911 CSI->TheCapturedDecl->addAttr(A: AlwaysInlineAttr::CreateImplicit(
4912 Ctx&: SemaRef.getASTContext(), Range: {}, S: AlwaysInlineAttr::Keyword_forceinline));
4913 };
4914
4915 for (auto [Level, RKind] : llvm::enumerate(First&: Regions)) {
4916 switch (RKind) {
4917 // All region kinds that can be returned from `getOpenMPCaptureRegions`
4918 // are listed here.
4919 case OMPD_parallel:
4920 SemaRef.ActOnCapturedRegionStart(
4921 Loc, CurScope, Kind: CR_OpenMP,
4922 Params: getParallelRegionParams(SemaRef, LoopBoundSharing), OpenMPCaptureLevel: Level);
4923 break;
4924 case OMPD_teams:
4925 SemaRef.ActOnCapturedRegionStart(Loc, CurScope, Kind: CR_OpenMP,
4926 Params: getTeamsRegionParams(SemaRef), OpenMPCaptureLevel: Level);
4927 break;
4928 case OMPD_task:
4929 SemaRef.ActOnCapturedRegionStart(Loc, CurScope, Kind: CR_OpenMP,
4930 Params: getTaskRegionParams(SemaRef), OpenMPCaptureLevel: Level);
4931 // Mark this captured region as inlined, because we don't use outlined
4932 // function directly.
4933 MarkAsInlined(SemaRef.getCurCapturedRegion());
4934 break;
4935 case OMPD_taskloop:
4936 SemaRef.ActOnCapturedRegionStart(Loc, CurScope, Kind: CR_OpenMP,
4937 Params: getTaskloopRegionParams(SemaRef), OpenMPCaptureLevel: Level);
4938 // Mark this captured region as inlined, because we don't use outlined
4939 // function directly.
4940 MarkAsInlined(SemaRef.getCurCapturedRegion());
4941 break;
4942 case OMPD_target:
4943 SemaRef.ActOnCapturedRegionStart(Loc, CurScope, Kind: CR_OpenMP,
4944 Params: getTargetRegionParams(SemaRef), OpenMPCaptureLevel: Level);
4945 break;
4946 case OMPD_unknown:
4947 SemaRef.ActOnCapturedRegionStart(Loc, CurScope, Kind: CR_OpenMP,
4948 Params: getUnknownRegionParams(SemaRef));
4949 break;
4950 case OMPD_metadirective:
4951 case OMPD_nothing:
4952 default:
4953 llvm_unreachable("Unexpected capture region");
4954 }
4955 }
4956}
4957
4958void SemaOpenMP::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind,
4959 Scope *CurScope) {
4960 if (DKind == OMPD_ordered_blockassoc &&
4961 DSAStack->getCurrentDirective() == OMPD_ordered_standalone) {
4962 DSAStack->setOrderedToBlockAssociated();
4963 }
4964 switch (DKind) {
4965 case OMPD_atomic:
4966 case OMPD_critical:
4967 case OMPD_masked:
4968 case OMPD_master:
4969 case OMPD_section:
4970 case OMPD_tile:
4971 case OMPD_stripe:
4972 case OMPD_unroll:
4973 case OMPD_reverse:
4974 case OMPD_split:
4975 case OMPD_interchange:
4976 case OMPD_flatten:
4977 case OMPD_fuse:
4978 case OMPD_assume:
4979 break;
4980 default:
4981 processCapturedRegions(SemaRef, DKind, CurScope,
4982 DSAStack->getConstructLoc());
4983 break;
4984 }
4985
4986 DSAStack->setContext(SemaRef.CurContext);
4987 handleDeclareVariantConstructTrait(DSAStack, DKind, /*ScopeEntry=*/true);
4988}
4989
4990int SemaOpenMP::getNumberOfConstructScopes(unsigned Level) const {
4991 return getOpenMPCaptureLevels(DSAStack->getDirective(Level));
4992}
4993
4994int SemaOpenMP::getOpenMPCaptureLevels(OpenMPDirectiveKind DKind) {
4995 SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
4996 getOpenMPCaptureRegions(CaptureRegions, DKind);
4997 return CaptureRegions.size();
4998}
4999
5000static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id,
5001 Expr *CaptureExpr, bool WithInit,
5002 DeclContext *CurContext,
5003 bool AsExpression) {
5004 assert(CaptureExpr);
5005 ASTContext &C = S.getASTContext();
5006 Expr *Init = AsExpression ? CaptureExpr : CaptureExpr->IgnoreImpCasts();
5007 QualType Ty = Init->getType();
5008 if (CaptureExpr->getObjectKind() == OK_Ordinary && CaptureExpr->isGLValue()) {
5009 if (S.getLangOpts().CPlusPlus) {
5010 Ty = C.getLValueReferenceType(T: Ty);
5011 } else {
5012 Ty = C.getPointerType(T: Ty);
5013 ExprResult Res =
5014 S.CreateBuiltinUnaryOp(OpLoc: CaptureExpr->getExprLoc(), Opc: UO_AddrOf, InputExpr: Init);
5015 if (!Res.isUsable())
5016 return nullptr;
5017 Init = Res.get();
5018 }
5019 WithInit = true;
5020 }
5021 auto *CED = OMPCapturedExprDecl::Create(C, DC: CurContext, Id, T: Ty,
5022 StartLoc: CaptureExpr->getBeginLoc());
5023 if (!WithInit)
5024 CED->addAttr(A: OMPCaptureNoInitAttr::CreateImplicit(Ctx&: C));
5025 CurContext->addHiddenDecl(D: CED);
5026 Sema::TentativeAnalysisScope Trap(S);
5027 S.AddInitializerToDecl(dcl: CED, init: Init, /*DirectInit=*/false);
5028 return CED;
5029}
5030
5031static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr,
5032 bool WithInit) {
5033 OMPCapturedExprDecl *CD;
5034 // For BindingDecls, always create a new capture instead of reusing the
5035 // decomposed decl, since the decomposed decl is a regular VarDecl, not an
5036 // OMPCapturedExprDecl.
5037 if (!isa<BindingDecl>(Val: D)) {
5038 if (VarDecl *VD = S.OpenMP().isOpenMPCapturedDecl(D))
5039 CD = cast<OMPCapturedExprDecl>(Val: VD);
5040 else
5041 CD = buildCaptureDecl(S, Id: D->getIdentifier(), CaptureExpr, WithInit,
5042 CurContext: S.CurContext,
5043 /*AsExpression=*/false);
5044 } else {
5045 CD = buildCaptureDecl(S, Id: D->getIdentifier(), CaptureExpr, WithInit,
5046 CurContext: S.CurContext,
5047 /*AsExpression=*/false);
5048 }
5049 return buildDeclRefExpr(S, D: CD, Ty: CD->getType().getNonReferenceType(),
5050 Loc: CaptureExpr->getExprLoc());
5051}
5052
5053static ExprResult buildCapture(Sema &S, Expr *CaptureExpr, DeclRefExpr *&Ref,
5054 StringRef Name) {
5055 CaptureExpr = S.DefaultLvalueConversion(E: CaptureExpr).get();
5056 if (!Ref) {
5057 OMPCapturedExprDecl *CD = buildCaptureDecl(
5058 S, Id: &S.getASTContext().Idents.get(Name), CaptureExpr,
5059 /*WithInit=*/true, CurContext: S.CurContext, /*AsExpression=*/true);
5060 Ref = buildDeclRefExpr(S, D: CD, Ty: CD->getType().getNonReferenceType(),
5061 Loc: CaptureExpr->getExprLoc());
5062 }
5063 ExprResult Res = Ref;
5064 if (!S.getLangOpts().CPlusPlus &&
5065 CaptureExpr->getObjectKind() == OK_Ordinary && CaptureExpr->isGLValue() &&
5066 Ref->getType()->isPointerType()) {
5067 Res = S.CreateBuiltinUnaryOp(OpLoc: CaptureExpr->getExprLoc(), Opc: UO_Deref, InputExpr: Ref);
5068 if (!Res.isUsable())
5069 return ExprError();
5070 }
5071 return S.DefaultLvalueConversion(E: Res.get());
5072}
5073
5074namespace {
5075// OpenMP directives parsed in this section are represented as a
5076// CapturedStatement with an associated statement. If a syntax error
5077// is detected during the parsing of the associated statement, the
5078// compiler must abort processing and close the CapturedStatement.
5079//
5080// Combined directives such as 'target parallel' have more than one
5081// nested CapturedStatements. This RAII ensures that we unwind out
5082// of all the nested CapturedStatements when an error is found.
5083class CaptureRegionUnwinderRAII {
5084private:
5085 Sema &S;
5086 bool &ErrorFound;
5087 OpenMPDirectiveKind DKind = OMPD_unknown;
5088
5089public:
5090 CaptureRegionUnwinderRAII(Sema &S, bool &ErrorFound,
5091 OpenMPDirectiveKind DKind)
5092 : S(S), ErrorFound(ErrorFound), DKind(DKind) {}
5093 ~CaptureRegionUnwinderRAII() {
5094 if (ErrorFound) {
5095 int ThisCaptureLevel = S.OpenMP().getOpenMPCaptureLevels(DKind);
5096 while (--ThisCaptureLevel >= 0)
5097 S.ActOnCapturedRegionError();
5098 }
5099 }
5100};
5101} // namespace
5102
5103void SemaOpenMP::tryCaptureOpenMPLambdas(ValueDecl *V) {
5104 // Capture variables captured by reference in lambdas for target-based
5105 // directives.
5106 if (!SemaRef.CurContext->isDependentContext() &&
5107 (isOpenMPTargetExecutionDirective(DSAStack->getCurrentDirective()) ||
5108 isOpenMPTargetDataManagementDirective(
5109 DSAStack->getCurrentDirective()))) {
5110 QualType Type = V->getType();
5111 if (const auto *RD = Type.getCanonicalType()
5112 .getNonReferenceType()
5113 ->getAsCXXRecordDecl()) {
5114 bool SavedForceCaptureByReferenceInTargetExecutable =
5115 DSAStack->isForceCaptureByReferenceInTargetExecutable();
5116 DSAStack->setForceCaptureByReferenceInTargetExecutable(
5117 /*V=*/true);
5118 if (RD->isLambda()) {
5119 llvm::DenseMap<const ValueDecl *, FieldDecl *> Captures;
5120 FieldDecl *ThisCapture;
5121 RD->getCaptureFields(Captures, ThisCapture);
5122 for (const LambdaCapture &LC : RD->captures()) {
5123 if (LC.getCaptureKind() == LCK_ByRef) {
5124 VarDecl *VD = cast<VarDecl>(Val: LC.getCapturedVar());
5125 DeclContext *VDC = VD->getDeclContext();
5126 if (!VDC->Encloses(DC: SemaRef.CurContext))
5127 continue;
5128 SemaRef.MarkVariableReferenced(Loc: LC.getLocation(), Var: VD);
5129 } else if (LC.getCaptureKind() == LCK_This) {
5130 QualType ThisTy = SemaRef.getCurrentThisType();
5131 if (!ThisTy.isNull() && getASTContext().typesAreCompatible(
5132 T1: ThisTy, T2: ThisCapture->getType()))
5133 SemaRef.CheckCXXThisCapture(Loc: LC.getLocation());
5134 }
5135 }
5136 }
5137 DSAStack->setForceCaptureByReferenceInTargetExecutable(
5138 SavedForceCaptureByReferenceInTargetExecutable);
5139 }
5140 }
5141}
5142
5143static bool checkOrderedOrderSpecified(Sema &S,
5144 const ArrayRef<OMPClause *> Clauses) {
5145 const OMPOrderedClause *Ordered = nullptr;
5146 const OMPOrderClause *Order = nullptr;
5147
5148 for (const OMPClause *Clause : Clauses) {
5149 if (Clause->getClauseKind() == OMPC_ordered)
5150 Ordered = cast<OMPOrderedClause>(Val: Clause);
5151 else if (Clause->getClauseKind() == OMPC_order) {
5152 Order = cast<OMPOrderClause>(Val: Clause);
5153 if (Order->getKind() != OMPC_ORDER_concurrent)
5154 Order = nullptr;
5155 }
5156 if (Ordered && Order)
5157 break;
5158 }
5159
5160 if (Ordered && Order) {
5161 S.Diag(Loc: Order->getKindKwLoc(),
5162 DiagID: diag::err_omp_simple_clause_incompatible_with_ordered)
5163 << getOpenMPClauseNameForDiag(C: OMPC_order)
5164 << getOpenMPSimpleClauseTypeName(Kind: OMPC_order, Type: OMPC_ORDER_concurrent)
5165 << SourceRange(Order->getBeginLoc(), Order->getEndLoc());
5166 S.Diag(Loc: Ordered->getBeginLoc(), DiagID: diag::note_omp_ordered_param)
5167 << 0 << SourceRange(Ordered->getBeginLoc(), Ordered->getEndLoc());
5168 return true;
5169 }
5170 return false;
5171}
5172
5173StmtResult SemaOpenMP::ActOnOpenMPRegionEnd(StmtResult S,
5174 ArrayRef<OMPClause *> Clauses) {
5175 handleDeclareVariantConstructTrait(DSAStack, DSAStack->getCurrentDirective(),
5176 /*ScopeEntry=*/false);
5177 if (!isOpenMPCapturingDirective(DSAStack->getCurrentDirective()))
5178 return S;
5179
5180 bool ErrorFound = false;
5181 CaptureRegionUnwinderRAII CaptureRegionUnwinder(
5182 SemaRef, ErrorFound, DSAStack->getCurrentDirective());
5183 if (!S.isUsable()) {
5184 ErrorFound = true;
5185 return StmtError();
5186 }
5187
5188 SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
5189 getOpenMPCaptureRegions(CaptureRegions, DSAStack->getCurrentDirective());
5190 OMPOrderedClause *OC = nullptr;
5191 OMPScheduleClause *SC = nullptr;
5192 SmallVector<const OMPLinearClause *, 4> LCs;
5193 SmallVector<const OMPClauseWithPreInit *, 4> PICs;
5194 // This is required for proper codegen.
5195 for (OMPClause *Clause : Clauses) {
5196 if (!getLangOpts().OpenMPSimd &&
5197 (isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) ||
5198 DSAStack->getCurrentDirective() == OMPD_target) &&
5199 Clause->getClauseKind() == OMPC_in_reduction) {
5200 // Capture taskgroup task_reduction descriptors inside the tasking regions
5201 // with the corresponding in_reduction items.
5202 auto *IRC = cast<OMPInReductionClause>(Val: Clause);
5203 for (Expr *E : IRC->taskgroup_descriptors())
5204 if (E)
5205 SemaRef.MarkDeclarationsReferencedInExpr(E);
5206 }
5207 if (isOpenMPPrivate(Kind: Clause->getClauseKind()) ||
5208 Clause->getClauseKind() == OMPC_copyprivate ||
5209 (getLangOpts().OpenMPUseTLS &&
5210 getASTContext().getTargetInfo().isTLSSupported() &&
5211 Clause->getClauseKind() == OMPC_copyin)) {
5212 DSAStack->setForceVarCapturing(Clause->getClauseKind() == OMPC_copyin);
5213 // Mark all variables in private list clauses as used in inner region.
5214 for (Stmt *VarRef : Clause->children()) {
5215 if (auto *E = cast_or_null<Expr>(Val: VarRef)) {
5216 SemaRef.MarkDeclarationsReferencedInExpr(E);
5217 }
5218 }
5219 DSAStack->setForceVarCapturing(/*V=*/false);
5220 } else if (CaptureRegions.size() > 1 ||
5221 CaptureRegions.back() != OMPD_unknown) {
5222 if (auto *C = OMPClauseWithPreInit::get(C: Clause))
5223 PICs.push_back(Elt: C);
5224 if (auto *C = OMPClauseWithPostUpdate::get(C: Clause)) {
5225 if (Expr *E = C->getPostUpdateExpr())
5226 SemaRef.MarkDeclarationsReferencedInExpr(E);
5227 }
5228 }
5229 if (Clause->getClauseKind() == OMPC_schedule)
5230 SC = cast<OMPScheduleClause>(Val: Clause);
5231 else if (Clause->getClauseKind() == OMPC_ordered)
5232 OC = cast<OMPOrderedClause>(Val: Clause);
5233 else if (Clause->getClauseKind() == OMPC_linear)
5234 LCs.push_back(Elt: cast<OMPLinearClause>(Val: Clause));
5235 }
5236 // Capture allocator expressions if used.
5237 for (Expr *E : DSAStack->getInnerAllocators())
5238 SemaRef.MarkDeclarationsReferencedInExpr(E);
5239 // OpenMP, 2.7.1 Loop Construct, Restrictions
5240 // The nonmonotonic modifier cannot be specified if an ordered clause is
5241 // specified.
5242 if (SC &&
5243 (SC->getFirstScheduleModifier() == OMPC_SCHEDULE_MODIFIER_nonmonotonic ||
5244 SC->getSecondScheduleModifier() ==
5245 OMPC_SCHEDULE_MODIFIER_nonmonotonic) &&
5246 OC) {
5247 Diag(Loc: SC->getFirstScheduleModifier() == OMPC_SCHEDULE_MODIFIER_nonmonotonic
5248 ? SC->getFirstScheduleModifierLoc()
5249 : SC->getSecondScheduleModifierLoc(),
5250 DiagID: diag::err_omp_simple_clause_incompatible_with_ordered)
5251 << getOpenMPClauseNameForDiag(C: OMPC_schedule)
5252 << getOpenMPSimpleClauseTypeName(Kind: OMPC_schedule,
5253 Type: OMPC_SCHEDULE_MODIFIER_nonmonotonic)
5254 << SourceRange(OC->getBeginLoc(), OC->getEndLoc());
5255 ErrorFound = true;
5256 }
5257 // OpenMP 5.0, 2.9.2 Worksharing-Loop Construct, Restrictions.
5258 // If an order(concurrent) clause is present, an ordered clause may not appear
5259 // on the same directive.
5260 if (checkOrderedOrderSpecified(S&: SemaRef, Clauses))
5261 ErrorFound = true;
5262 if (!LCs.empty() && OC && OC->getNumForLoops()) {
5263 for (const OMPLinearClause *C : LCs) {
5264 Diag(Loc: C->getBeginLoc(), DiagID: diag::err_omp_linear_ordered)
5265 << SourceRange(OC->getBeginLoc(), OC->getEndLoc());
5266 }
5267 ErrorFound = true;
5268 }
5269 if (isOpenMPWorksharingDirective(DSAStack->getCurrentDirective()) &&
5270 isOpenMPSimdDirective(DSAStack->getCurrentDirective()) && OC &&
5271 OC->getNumForLoops()) {
5272 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
5273 Diag(Loc: OC->getBeginLoc(), DiagID: diag::err_omp_ordered_simd)
5274 << getOpenMPDirectiveName(DSAStack->getCurrentDirective(), V: OMPVersion);
5275 ErrorFound = true;
5276 }
5277 if (ErrorFound) {
5278 return StmtError();
5279 }
5280 StmtResult SR = S;
5281 unsigned CompletedRegions = 0;
5282 for (OpenMPDirectiveKind ThisCaptureRegion : llvm::reverse(C&: CaptureRegions)) {
5283 // Mark all variables in private list clauses as used in inner region.
5284 // Required for proper codegen of combined directives.
5285 // TODO: add processing for other clauses.
5286 if (ThisCaptureRegion != OMPD_unknown) {
5287 for (const clang::OMPClauseWithPreInit *C : PICs) {
5288 OpenMPDirectiveKind CaptureRegion = C->getCaptureRegion();
5289 // Find the particular capture region for the clause if the
5290 // directive is a combined one with multiple capture regions.
5291 // If the directive is not a combined one, the capture region
5292 // associated with the clause is OMPD_unknown and is generated
5293 // only once.
5294 if (CaptureRegion == ThisCaptureRegion ||
5295 CaptureRegion == OMPD_unknown) {
5296 if (auto *DS = cast_or_null<DeclStmt>(Val: C->getPreInitStmt())) {
5297 for (Decl *D : DS->decls())
5298 SemaRef.MarkVariableReferenced(Loc: D->getLocation(),
5299 Var: cast<VarDecl>(Val: D));
5300 }
5301 }
5302 }
5303 }
5304 if (ThisCaptureRegion == OMPD_target) {
5305 // Capture allocator traits in the target region. They are used implicitly
5306 // and, thus, are not captured by default.
5307 for (OMPClause *C : Clauses) {
5308 if (const auto *UAC = dyn_cast<OMPUsesAllocatorsClause>(Val: C)) {
5309 for (unsigned I = 0, End = UAC->getNumberOfAllocators(); I < End;
5310 ++I) {
5311 OMPUsesAllocatorsClause::Data D = UAC->getAllocatorData(I);
5312 if (Expr *E = D.AllocatorTraits)
5313 SemaRef.MarkDeclarationsReferencedInExpr(E);
5314 }
5315 continue;
5316 }
5317 }
5318 }
5319 if (ThisCaptureRegion == OMPD_parallel) {
5320 // Capture temp arrays for inscan reductions and locals in aligned
5321 // clauses.
5322 for (OMPClause *C : Clauses) {
5323 if (auto *RC = dyn_cast<OMPReductionClause>(Val: C)) {
5324 if (RC->getModifier() != OMPC_REDUCTION_inscan)
5325 continue;
5326 for (Expr *E : RC->copy_array_temps())
5327 if (E)
5328 SemaRef.MarkDeclarationsReferencedInExpr(E);
5329 }
5330 if (auto *AC = dyn_cast<OMPAlignedClause>(Val: C)) {
5331 for (Expr *E : AC->varlist())
5332 SemaRef.MarkDeclarationsReferencedInExpr(E);
5333 }
5334 }
5335 }
5336 if (++CompletedRegions == CaptureRegions.size())
5337 DSAStack->setBodyComplete();
5338 SR = SemaRef.ActOnCapturedRegionEnd(S: SR.get());
5339 }
5340 return SR;
5341}
5342
5343static bool checkCancelRegion(Sema &SemaRef, OpenMPDirectiveKind CurrentRegion,
5344 OpenMPDirectiveKind CancelRegion,
5345 SourceLocation StartLoc) {
5346 // CancelRegion is only needed for cancel and cancellation_point.
5347 if (CurrentRegion != OMPD_cancel && CurrentRegion != OMPD_cancellation_point)
5348 return false;
5349
5350 if (CancelRegion == OMPD_parallel || CancelRegion == OMPD_for ||
5351 CancelRegion == OMPD_sections || CancelRegion == OMPD_taskgroup)
5352 return false;
5353
5354 llvm::omp::Version OMPVersion = SemaRef.getLangOpts().getOpenMPVersion();
5355 SemaRef.Diag(Loc: StartLoc, DiagID: diag::err_omp_wrong_cancel_region)
5356 << getOpenMPDirectiveName(D: CancelRegion, V: OMPVersion);
5357 return true;
5358}
5359
5360static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
5361 OpenMPDirectiveKind CurrentRegion,
5362 const DeclarationNameInfo &CurrentName,
5363 OpenMPDirectiveKind CancelRegion,
5364 OpenMPBindClauseKind BindKind,
5365 SourceLocation StartLoc) {
5366 if (!Stack->getCurScope())
5367 return false;
5368
5369 OpenMPDirectiveKind ParentRegion = Stack->getParentDirective();
5370 OpenMPDirectiveKind OffendingRegion = ParentRegion;
5371 bool NestingProhibited = false;
5372 bool CloseNesting = true;
5373 bool OrphanSeen = false;
5374 enum {
5375 NoRecommend,
5376 ShouldBeInParallelRegion,
5377 ShouldBeInOrderedRegion,
5378 ShouldBeInTargetRegion,
5379 ShouldBeInTeamsRegion,
5380 ShouldBeInLoopSimdRegion,
5381 } Recommend = NoRecommend;
5382
5383 SmallVector<OpenMPDirectiveKind, 4> LeafOrComposite;
5384 ArrayRef<OpenMPDirectiveKind> ParentLOC =
5385 getLeafOrCompositeConstructs(D: ParentRegion, Output&: LeafOrComposite);
5386 OpenMPDirectiveKind EnclosingConstruct = ParentLOC.back();
5387 llvm::omp::Version OMPVersion = SemaRef.getLangOpts().getOpenMPVersion();
5388
5389 if (OMPVersion >= 50 && Stack->isParentOrderConcurrent() &&
5390 !isOpenMPOrderConcurrentNestableDirective(DKind: CurrentRegion,
5391 LangOpts: SemaRef.LangOpts)) {
5392 SemaRef.Diag(Loc: StartLoc, DiagID: diag::err_omp_prohibited_region_order)
5393 << getOpenMPDirectiveName(D: CurrentRegion, V: OMPVersion);
5394 return true;
5395 }
5396 if (isOpenMPSimdDirective(DKind: ParentRegion) &&
5397 ((OMPVersion <= 45 && CurrentRegion != OMPD_ordered_blockassoc) ||
5398 (OMPVersion >= 50 && CurrentRegion != OMPD_ordered_blockassoc &&
5399 CurrentRegion != OMPD_simd && CurrentRegion != OMPD_atomic &&
5400 CurrentRegion != OMPD_scan))) {
5401 // OpenMP [2.16, Nesting of Regions]
5402 // OpenMP constructs may not be nested inside a simd region.
5403 // OpenMP [2.8.1,simd Construct, Restrictions]
5404 // An ordered construct with the simd clause is the only OpenMP
5405 // construct that can appear in the simd region.
5406 // Allowing a SIMD construct nested in another SIMD construct is an
5407 // extension. The OpenMP 4.5 spec does not allow it. Issue a warning
5408 // message.
5409 // OpenMP 5.0 [2.9.3.1, simd Construct, Restrictions]
5410 // The only OpenMP constructs that can be encountered during execution of
5411 // a simd region are the atomic construct, the loop construct, the simd
5412 // construct and the ordered construct with the simd clause.
5413 SemaRef.Diag(Loc: StartLoc, DiagID: (CurrentRegion != OMPD_simd)
5414 ? diag::err_omp_prohibited_region_simd
5415 : diag::warn_omp_nesting_simd)
5416 << (OMPVersion >= 50 ? 1 : 0);
5417 return CurrentRegion != OMPD_simd;
5418 }
5419 if (EnclosingConstruct == OMPD_atomic) {
5420 // OpenMP [2.16, Nesting of Regions]
5421 // OpenMP constructs may not be nested inside an atomic region.
5422 SemaRef.Diag(Loc: StartLoc, DiagID: diag::err_omp_prohibited_region_atomic);
5423 return true;
5424 }
5425 if (CurrentRegion == OMPD_section) {
5426 // OpenMP [2.7.2, sections Construct, Restrictions]
5427 // Orphaned section directives are prohibited. That is, the section
5428 // directives must appear within the sections construct and must not be
5429 // encountered elsewhere in the sections region.
5430 if (EnclosingConstruct != OMPD_sections) {
5431 SemaRef.Diag(Loc: StartLoc, DiagID: diag::err_omp_orphaned_section_directive)
5432 << (ParentRegion != OMPD_unknown)
5433 << getOpenMPDirectiveName(D: ParentRegion, V: OMPVersion);
5434 return true;
5435 }
5436 return false;
5437 }
5438 // Allow some constructs (except teams and cancellation constructs) to be
5439 // orphaned (they could be used in functions, called from OpenMP regions
5440 // with the required preconditions).
5441 if (ParentRegion == OMPD_unknown &&
5442 !isOpenMPNestingTeamsDirective(DKind: CurrentRegion) &&
5443 CurrentRegion != OMPD_cancellation_point &&
5444 CurrentRegion != OMPD_cancel && CurrentRegion != OMPD_scan)
5445 return false;
5446 // Checks needed for mapping "loop" construct. Please check mapLoopConstruct
5447 // for a detailed explanation
5448 if (OMPVersion >= 50 && CurrentRegion == OMPD_loop &&
5449 (BindKind == OMPC_BIND_parallel || BindKind == OMPC_BIND_teams) &&
5450 (isOpenMPWorksharingDirective(DKind: ParentRegion) ||
5451 EnclosingConstruct == OMPD_loop)) {
5452 int ErrorMsgNumber = (BindKind == OMPC_BIND_parallel) ? 1 : 4;
5453 SemaRef.Diag(Loc: StartLoc, DiagID: diag::err_omp_prohibited_region)
5454 << true << getOpenMPDirectiveName(D: ParentRegion, V: OMPVersion)
5455 << ErrorMsgNumber << getOpenMPDirectiveName(D: CurrentRegion, V: OMPVersion);
5456 return true;
5457 }
5458 if (CurrentRegion == OMPD_cancellation_point ||
5459 CurrentRegion == OMPD_cancel) {
5460 // OpenMP [2.16, Nesting of Regions]
5461 // A cancellation point construct for which construct-type-clause is
5462 // taskgroup must be nested inside a task construct. A cancellation
5463 // point construct for which construct-type-clause is not taskgroup must
5464 // be closely nested inside an OpenMP construct that matches the type
5465 // specified in construct-type-clause.
5466 // A cancel construct for which construct-type-clause is taskgroup must be
5467 // nested inside a task construct. A cancel construct for which
5468 // construct-type-clause is not taskgroup must be closely nested inside an
5469 // OpenMP construct that matches the type specified in
5470 // construct-type-clause.
5471 ArrayRef<OpenMPDirectiveKind> Leafs = getLeafConstructsOrSelf(D: ParentRegion);
5472 if (CancelRegion == OMPD_taskgroup) {
5473 NestingProhibited =
5474 EnclosingConstruct != OMPD_task &&
5475 (OMPVersion < 50 || EnclosingConstruct != OMPD_taskloop);
5476 } else if (CancelRegion == OMPD_sections) {
5477 NestingProhibited = EnclosingConstruct != OMPD_section &&
5478 EnclosingConstruct != OMPD_sections;
5479 } else {
5480 NestingProhibited = CancelRegion != Leafs.back();
5481 }
5482 OrphanSeen = ParentRegion == OMPD_unknown;
5483 } else if (CurrentRegion == OMPD_master || CurrentRegion == OMPD_masked) {
5484 // OpenMP 5.1 [2.22, Nesting of Regions]
5485 // A masked region may not be closely nested inside a worksharing, loop,
5486 // atomic, task, or taskloop region.
5487 NestingProhibited = isOpenMPWorksharingDirective(DKind: ParentRegion) ||
5488 isOpenMPGenericLoopDirective(DKind: ParentRegion) ||
5489 isOpenMPTaskingDirective(Kind: ParentRegion);
5490 } else if (CurrentRegion == OMPD_critical && CurrentName.getName()) {
5491 // OpenMP [2.16, Nesting of Regions]
5492 // A critical region may not be nested (closely or otherwise) inside a
5493 // critical region with the same name. Note that this restriction is not
5494 // sufficient to prevent deadlock.
5495 SourceLocation PreviousCriticalLoc;
5496 bool DeadLock = Stack->hasDirective(
5497 DPred: [CurrentName, &PreviousCriticalLoc](OpenMPDirectiveKind K,
5498 const DeclarationNameInfo &DNI,
5499 SourceLocation Loc) {
5500 if (K == OMPD_critical && DNI.getName() == CurrentName.getName()) {
5501 PreviousCriticalLoc = Loc;
5502 return true;
5503 }
5504 return false;
5505 },
5506 FromParent: false /* skip top directive */);
5507 if (DeadLock) {
5508 SemaRef.Diag(Loc: StartLoc, DiagID: diag::err_omp_prohibited_region_critical_same_name)
5509 << CurrentName.getName();
5510 if (PreviousCriticalLoc.isValid())
5511 SemaRef.Diag(Loc: PreviousCriticalLoc,
5512 DiagID: diag::note_omp_previous_critical_region);
5513 return true;
5514 }
5515 } else if (CurrentRegion == OMPD_barrier || CurrentRegion == OMPD_scope) {
5516 // OpenMP 5.1 [2.22, Nesting of Regions]
5517 // A scope region may not be closely nested inside a worksharing, loop,
5518 // task, taskloop, critical, ordered, atomic, or masked region.
5519 // OpenMP 5.1 [2.22, Nesting of Regions]
5520 // A barrier region may not be closely nested inside a worksharing, loop,
5521 // task, taskloop, critical, ordered, atomic, or masked region.
5522 NestingProhibited =
5523 isOpenMPWorksharingDirective(DKind: ParentRegion) ||
5524 isOpenMPGenericLoopDirective(DKind: ParentRegion) ||
5525 isOpenMPTaskingDirective(Kind: ParentRegion) ||
5526 llvm::is_contained(
5527 Set: {OMPD_masked, OMPD_master, OMPD_critical, OMPD_ordered_blockassoc},
5528 Element: EnclosingConstruct);
5529 } else if (isOpenMPWorksharingDirective(DKind: CurrentRegion) &&
5530 !isOpenMPParallelDirective(DKind: CurrentRegion) &&
5531 !isOpenMPTeamsDirective(DKind: CurrentRegion)) {
5532 // OpenMP 5.1 [2.22, Nesting of Regions]
5533 // A loop region that binds to a parallel region or a worksharing region
5534 // may not be closely nested inside a worksharing, loop, task, taskloop,
5535 // critical, ordered, atomic, or masked region.
5536 NestingProhibited =
5537 isOpenMPWorksharingDirective(DKind: ParentRegion) ||
5538 isOpenMPGenericLoopDirective(DKind: ParentRegion) ||
5539 isOpenMPTaskingDirective(Kind: ParentRegion) ||
5540 llvm::is_contained(
5541 Set: {OMPD_masked, OMPD_master, OMPD_critical, OMPD_ordered_blockassoc},
5542 Element: EnclosingConstruct);
5543 Recommend = ShouldBeInParallelRegion;
5544 } else if (CurrentRegion == OMPD_ordered_blockassoc ||
5545 CurrentRegion == OMPD_ordered_standalone) {
5546 // OpenMP [2.16, Nesting of Regions]
5547 // An ordered region may not be closely nested inside a critical,
5548 // atomic, or explicit task region.
5549 // An ordered region must be closely nested inside a loop region (or
5550 // parallel loop region) with an ordered clause.
5551 // OpenMP [2.8.1,simd Construct, Restrictions]
5552 // An ordered construct with the simd clause is the only OpenMP construct
5553 // that can appear in the simd region.
5554 NestingProhibited = EnclosingConstruct == OMPD_critical ||
5555 isOpenMPTaskingDirective(Kind: ParentRegion) ||
5556 !(isOpenMPSimdDirective(DKind: ParentRegion) ||
5557 Stack->isParentOrderedRegion());
5558 Recommend = ShouldBeInOrderedRegion;
5559 } else if (isOpenMPNestingTeamsDirective(DKind: CurrentRegion)) {
5560 // OpenMP [2.16, Nesting of Regions]
5561 // If specified, a teams construct must be contained within a target
5562 // construct.
5563 NestingProhibited =
5564 (OMPVersion <= 45 && EnclosingConstruct != OMPD_target) ||
5565 (OMPVersion >= 50 && EnclosingConstruct != OMPD_unknown &&
5566 EnclosingConstruct != OMPD_target);
5567 OrphanSeen = ParentRegion == OMPD_unknown;
5568 Recommend = ShouldBeInTargetRegion;
5569 } else if (CurrentRegion == OMPD_scan) {
5570 if (OMPVersion >= 50) {
5571 // OpenMP spec 5.0 and 5.1 require scan to be directly enclosed by for,
5572 // simd, or for simd. This has to take into account combined directives.
5573 // In 5.2 this seems to be implied by the fact that the specified
5574 // separated constructs are do, for, and simd.
5575 NestingProhibited = !llvm::is_contained(
5576 Set: {OMPD_for, OMPD_simd, OMPD_for_simd}, Element: EnclosingConstruct);
5577 } else {
5578 NestingProhibited = true;
5579 }
5580 OrphanSeen = ParentRegion == OMPD_unknown;
5581 Recommend = ShouldBeInLoopSimdRegion;
5582 }
5583 if (!NestingProhibited && !isOpenMPTargetExecutionDirective(DKind: CurrentRegion) &&
5584 !isOpenMPTargetDataManagementDirective(DKind: CurrentRegion) &&
5585 EnclosingConstruct == OMPD_teams) {
5586 // OpenMP [5.1, 2.22, Nesting of Regions]
5587 // distribute, distribute simd, distribute parallel worksharing-loop,
5588 // distribute parallel worksharing-loop SIMD, loop, parallel regions,
5589 // including any parallel regions arising from combined constructs,
5590 // omp_get_num_teams() regions, and omp_get_team_num() regions are the
5591 // only OpenMP regions that may be strictly nested inside the teams
5592 // region.
5593 //
5594 // As an extension, we permit atomic within teams as well.
5595 NestingProhibited = !isOpenMPParallelDirective(DKind: CurrentRegion) &&
5596 !isOpenMPDistributeDirective(DKind: CurrentRegion) &&
5597 CurrentRegion != OMPD_loop &&
5598 !(SemaRef.getLangOpts().OpenMPExtensions &&
5599 CurrentRegion == OMPD_atomic);
5600 Recommend = ShouldBeInParallelRegion;
5601 }
5602 if (!NestingProhibited && CurrentRegion == OMPD_loop) {
5603 // OpenMP [5.1, 2.11.7, loop Construct, Restrictions]
5604 // If the bind clause is present on the loop construct and binding is
5605 // teams then the corresponding loop region must be strictly nested inside
5606 // a teams region.
5607 NestingProhibited =
5608 BindKind == OMPC_BIND_teams && EnclosingConstruct != OMPD_teams;
5609 Recommend = ShouldBeInTeamsRegion;
5610 }
5611 if (!NestingProhibited && isOpenMPNestingDistributeDirective(DKind: CurrentRegion)) {
5612 // OpenMP 4.5 [2.17 Nesting of Regions]
5613 // The region associated with the distribute construct must be strictly
5614 // nested inside a teams region
5615 NestingProhibited = EnclosingConstruct != OMPD_teams;
5616 Recommend = ShouldBeInTeamsRegion;
5617 }
5618 if (!NestingProhibited &&
5619 (isOpenMPTargetExecutionDirective(DKind: CurrentRegion) ||
5620 isOpenMPTargetDataManagementDirective(DKind: CurrentRegion))) {
5621 // OpenMP 4.5 [2.17 Nesting of Regions]
5622 // If a target, target update, target data, target enter data, or
5623 // target exit data construct is encountered during execution of a
5624 // target region, the behavior is unspecified.
5625 NestingProhibited = Stack->hasDirective(
5626 DPred: [&OffendingRegion](OpenMPDirectiveKind K, const DeclarationNameInfo &,
5627 SourceLocation) {
5628 if (isOpenMPTargetExecutionDirective(DKind: K)) {
5629 OffendingRegion = K;
5630 return true;
5631 }
5632 return false;
5633 },
5634 FromParent: false /* don't skip top directive */);
5635 CloseNesting = false;
5636 }
5637 if (NestingProhibited) {
5638 if (OrphanSeen) {
5639 SemaRef.Diag(Loc: StartLoc, DiagID: diag::err_omp_orphaned_device_directive)
5640 << getOpenMPDirectiveName(D: CurrentRegion, V: OMPVersion) << Recommend;
5641 } else {
5642 SemaRef.Diag(Loc: StartLoc, DiagID: diag::err_omp_prohibited_region)
5643 << CloseNesting << getOpenMPDirectiveName(D: OffendingRegion, V: OMPVersion)
5644 << Recommend << getOpenMPDirectiveName(D: CurrentRegion, V: OMPVersion);
5645 }
5646 return true;
5647 }
5648 return false;
5649}
5650
5651struct Kind2Unsigned {
5652 using argument_type = OpenMPDirectiveKind;
5653 unsigned operator()(argument_type DK) { return unsigned(DK); }
5654};
5655static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind,
5656 ArrayRef<OMPClause *> Clauses,
5657 ArrayRef<OpenMPDirectiveKind> AllowedNameModifiers) {
5658 bool ErrorFound = false;
5659 unsigned NamedModifiersNumber = 0;
5660 llvm::IndexedMap<const OMPIfClause *, Kind2Unsigned> FoundNameModifiers;
5661 FoundNameModifiers.resize(S: llvm::omp::Directive_enumSize + 1);
5662 SmallVector<SourceLocation, 4> NameModifierLoc;
5663 llvm::omp::Version OMPVersion = S.getLangOpts().getOpenMPVersion();
5664 for (const OMPClause *C : Clauses) {
5665 if (const auto *IC = dyn_cast_or_null<OMPIfClause>(Val: C)) {
5666 // At most one if clause without a directive-name-modifier can appear on
5667 // the directive.
5668 OpenMPDirectiveKind CurNM = IC->getNameModifier();
5669 auto &FNM = FoundNameModifiers[CurNM];
5670 if (FNM) {
5671 S.Diag(Loc: C->getBeginLoc(), DiagID: diag::err_omp_more_one_clause)
5672 << getOpenMPDirectiveName(D: Kind, V: OMPVersion)
5673 << getOpenMPClauseNameForDiag(C: OMPC_if) << (CurNM != OMPD_unknown)
5674 << getOpenMPDirectiveName(D: CurNM, V: OMPVersion);
5675 ErrorFound = true;
5676 } else if (CurNM != OMPD_unknown) {
5677 NameModifierLoc.push_back(Elt: IC->getNameModifierLoc());
5678 ++NamedModifiersNumber;
5679 }
5680 FNM = IC;
5681 if (CurNM == OMPD_unknown)
5682 continue;
5683 // Check if the specified name modifier is allowed for the current
5684 // directive.
5685 // At most one if clause with the particular directive-name-modifier can
5686 // appear on the directive.
5687 if (!llvm::is_contained(Range&: AllowedNameModifiers, Element: CurNM)) {
5688 S.Diag(Loc: IC->getNameModifierLoc(),
5689 DiagID: diag::err_omp_wrong_if_directive_name_modifier)
5690 << getOpenMPDirectiveName(D: CurNM, V: OMPVersion)
5691 << getOpenMPDirectiveName(D: Kind, V: OMPVersion);
5692 ErrorFound = true;
5693 }
5694 }
5695 }
5696 // If any if clause on the directive includes a directive-name-modifier then
5697 // all if clauses on the directive must include a directive-name-modifier.
5698 if (FoundNameModifiers[OMPD_unknown] && NamedModifiersNumber > 0) {
5699 if (NamedModifiersNumber == AllowedNameModifiers.size()) {
5700 S.Diag(Loc: FoundNameModifiers[OMPD_unknown]->getBeginLoc(),
5701 DiagID: diag::err_omp_no_more_if_clause);
5702 } else {
5703 std::string Values;
5704 std::string Sep(", ");
5705 unsigned AllowedCnt = 0;
5706 unsigned TotalAllowedNum =
5707 AllowedNameModifiers.size() - NamedModifiersNumber;
5708 for (unsigned Cnt = 0, End = AllowedNameModifiers.size(); Cnt < End;
5709 ++Cnt) {
5710 OpenMPDirectiveKind NM = AllowedNameModifiers[Cnt];
5711 if (!FoundNameModifiers[NM]) {
5712 Values += "'";
5713 Values += getOpenMPDirectiveName(D: NM, V: OMPVersion);
5714 Values += "'";
5715 if (AllowedCnt + 2 == TotalAllowedNum)
5716 Values += " or ";
5717 else if (AllowedCnt + 1 != TotalAllowedNum)
5718 Values += Sep;
5719 ++AllowedCnt;
5720 }
5721 }
5722 S.Diag(Loc: FoundNameModifiers[OMPD_unknown]->getCondition()->getBeginLoc(),
5723 DiagID: diag::err_omp_unnamed_if_clause)
5724 << (TotalAllowedNum > 1) << Values;
5725 }
5726 for (SourceLocation Loc : NameModifierLoc) {
5727 S.Diag(Loc, DiagID: diag::note_omp_previous_named_if_clause);
5728 }
5729 ErrorFound = true;
5730 }
5731 return ErrorFound;
5732}
5733
5734static std::pair<ValueDecl *, bool>
5735getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
5736 SourceRange &ERange, bool AllowArraySection,
5737 bool AllowAssumedSizeArray, StringRef DiagType) {
5738 if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
5739 RefExpr->containsUnexpandedParameterPack())
5740 return std::make_pair(x: nullptr, y: true);
5741
5742 // OpenMP [3.1, C/C++]
5743 // A list item is a variable name.
5744 // OpenMP [2.9.3.3, Restrictions, p.1]
5745 // A variable that is part of another variable (as an array or
5746 // structure element) cannot appear in a private clause.
5747 //
5748 // OpenMP [6.0]
5749 // 5.2.5 Array Sections, p. 166, L28-29
5750 // When the length is absent and the size of the dimension is not known,
5751 // the array section is an assumed-size array.
5752 // 2 Glossary, p. 23, L4-6
5753 // assumed-size array
5754 // For C/C++, an array section for which the length is absent and the
5755 // size of the dimensions is not known.
5756 // 5.2.5 Array Sections, p. 168, L11
5757 // An assumed-size array can appear only in clauses for which it is
5758 // explicitly allowed.
5759 // 7.4 List Item Privatization, Restrictions, p. 222, L15
5760 // Assumed-size arrays must not be privatized.
5761 RefExpr = RefExpr->IgnoreParens();
5762 enum {
5763 NoArrayExpr = -1,
5764 ArraySubscript = 0,
5765 OMPArraySection = 1
5766 } IsArrayExpr = NoArrayExpr;
5767 if (AllowArraySection) {
5768 if (auto *ASE = dyn_cast_or_null<ArraySubscriptExpr>(Val: RefExpr)) {
5769 Expr *Base = ASE->getBase()->IgnoreParenImpCasts();
5770 while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Val: Base))
5771 Base = TempASE->getBase()->IgnoreParenImpCasts();
5772 RefExpr = Base;
5773 IsArrayExpr = ArraySubscript;
5774 } else if (auto *OASE = dyn_cast_or_null<ArraySectionExpr>(Val: RefExpr)) {
5775 Expr *Base = OASE->getBase()->IgnoreParenImpCasts();
5776 if (S.getLangOpts().OpenMP >= 60 && !AllowAssumedSizeArray &&
5777 OASE->getColonLocFirst().isValid() && !OASE->getLength()) {
5778 QualType BaseType = ArraySectionExpr::getBaseOriginalType(Base);
5779 if (BaseType.isNull() || (!BaseType->isConstantArrayType() &&
5780 !BaseType->isVariableArrayType())) {
5781 S.Diag(Loc: OASE->getColonLocFirst(),
5782 DiagID: diag::err_omp_section_length_undefined)
5783 << (!BaseType.isNull() && BaseType->isArrayType());
5784 return std::make_pair(x: nullptr, y: false);
5785 }
5786 }
5787 while (auto *TempOASE = dyn_cast<ArraySectionExpr>(Val: Base))
5788 Base = TempOASE->getBase()->IgnoreParenImpCasts();
5789 while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Val: Base))
5790 Base = TempASE->getBase()->IgnoreParenImpCasts();
5791 RefExpr = Base;
5792 IsArrayExpr = OMPArraySection;
5793 }
5794 }
5795 ELoc = RefExpr->getExprLoc();
5796 ERange = RefExpr->getSourceRange();
5797 RefExpr = RefExpr->IgnoreParenImpCasts();
5798 auto *DE = dyn_cast_or_null<DeclRefExpr>(Val: RefExpr);
5799 auto *ME = dyn_cast_or_null<MemberExpr>(Val: RefExpr);
5800 if ((!DE || !isa<VarDecl, BindingDecl>(Val: DE->getDecl())) &&
5801 (S.getCurrentThisType().isNull() || !ME ||
5802 !isa<CXXThisExpr>(Val: ME->getBase()->IgnoreParenImpCasts()) ||
5803 !isa<FieldDecl>(Val: ME->getMemberDecl()))) {
5804 if (IsArrayExpr != NoArrayExpr) {
5805 S.Diag(Loc: ELoc, DiagID: diag::err_omp_expected_base_var_name)
5806 << IsArrayExpr << ERange;
5807 } else if (!DiagType.empty()) {
5808 unsigned DiagSelect = S.getLangOpts().CPlusPlus
5809 ? (S.getCurrentThisType().isNull() ? 1 : 2)
5810 : 0;
5811 S.Diag(Loc: ELoc, DiagID: diag::err_omp_expected_var_name_member_expr_with_type)
5812 << DiagSelect << DiagType << ERange;
5813 } else {
5814 S.Diag(Loc: ELoc,
5815 DiagID: AllowArraySection
5816 ? diag::err_omp_expected_var_name_member_expr_or_array_item
5817 : diag::err_omp_expected_var_name_member_expr)
5818 << (S.getCurrentThisType().isNull() ? 0 : 1) << ERange;
5819 }
5820 return std::make_pair(x: nullptr, y: false);
5821 }
5822 return std::make_pair(
5823 x: getCanonicalDecl(D: DE ? DE->getDecl() : ME->getMemberDecl()), y: false);
5824}
5825
5826namespace {
5827/// Checks if the allocator is used in uses_allocators clause to be allowed in
5828/// target regions.
5829class AllocatorChecker final : public ConstStmtVisitor<AllocatorChecker, bool> {
5830 DSAStackTy *S = nullptr;
5831
5832public:
5833 bool VisitDeclRefExpr(const DeclRefExpr *E) {
5834 return S->isUsesAllocatorsDecl(D: E->getDecl())
5835 .value_or(u: DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait) ==
5836 DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait;
5837 }
5838 bool VisitStmt(const Stmt *S) {
5839 for (const Stmt *Child : S->children()) {
5840 if (Child && Visit(S: Child))
5841 return true;
5842 }
5843 return false;
5844 }
5845 explicit AllocatorChecker(DSAStackTy *S) : S(S) {}
5846};
5847} // namespace
5848
5849static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
5850 ArrayRef<OMPClause *> Clauses) {
5851 assert(!S.CurContext->isDependentContext() &&
5852 "Expected non-dependent context.");
5853 auto AllocateRange =
5854 llvm::make_filter_range(Range&: Clauses, Pred: OMPAllocateClause::classof);
5855 llvm::DenseMap<CanonicalDeclPtr<Decl>, CanonicalDeclPtr<VarDecl>> DeclToCopy;
5856 auto PrivateRange = llvm::make_filter_range(Range&: Clauses, Pred: [](const OMPClause *C) {
5857 return isOpenMPPrivate(Kind: C->getClauseKind());
5858 });
5859 for (OMPClause *Cl : PrivateRange) {
5860 MutableArrayRef<Expr *>::iterator I, It, Et;
5861 if (Cl->getClauseKind() == OMPC_private) {
5862 auto *PC = cast<OMPPrivateClause>(Val: Cl);
5863 I = PC->private_copies().begin();
5864 It = PC->varlist_begin();
5865 Et = PC->varlist_end();
5866 } else if (Cl->getClauseKind() == OMPC_firstprivate) {
5867 auto *PC = cast<OMPFirstprivateClause>(Val: Cl);
5868 I = PC->private_copies().begin();
5869 It = PC->varlist_begin();
5870 Et = PC->varlist_end();
5871 } else if (Cl->getClauseKind() == OMPC_lastprivate) {
5872 auto *PC = cast<OMPLastprivateClause>(Val: Cl);
5873 I = PC->private_copies().begin();
5874 It = PC->varlist_begin();
5875 Et = PC->varlist_end();
5876 } else if (Cl->getClauseKind() == OMPC_linear) {
5877 auto *PC = cast<OMPLinearClause>(Val: Cl);
5878 I = PC->privates().begin();
5879 It = PC->varlist_begin();
5880 Et = PC->varlist_end();
5881 } else if (Cl->getClauseKind() == OMPC_reduction) {
5882 auto *PC = cast<OMPReductionClause>(Val: Cl);
5883 I = PC->privates().begin();
5884 It = PC->varlist_begin();
5885 Et = PC->varlist_end();
5886 } else if (Cl->getClauseKind() == OMPC_task_reduction) {
5887 auto *PC = cast<OMPTaskReductionClause>(Val: Cl);
5888 I = PC->privates().begin();
5889 It = PC->varlist_begin();
5890 Et = PC->varlist_end();
5891 } else if (Cl->getClauseKind() == OMPC_in_reduction) {
5892 auto *PC = cast<OMPInReductionClause>(Val: Cl);
5893 I = PC->privates().begin();
5894 It = PC->varlist_begin();
5895 Et = PC->varlist_end();
5896 } else {
5897 llvm_unreachable("Expected private clause.");
5898 }
5899 for (Expr *E : llvm::make_range(x: It, y: Et)) {
5900 if (!*I) {
5901 ++I;
5902 continue;
5903 }
5904 SourceLocation ELoc;
5905 SourceRange ERange;
5906 Expr *SimpleRefExpr = E;
5907 auto Res = getPrivateItem(S, RefExpr&: SimpleRefExpr, ELoc, ERange,
5908 /*AllowArraySection=*/true);
5909 DeclToCopy.try_emplace(Key: Res.first,
5910 Args: cast<VarDecl>(Val: cast<DeclRefExpr>(Val: *I)->getDecl()));
5911 ++I;
5912 }
5913 }
5914 for (OMPClause *C : AllocateRange) {
5915 auto *AC = cast<OMPAllocateClause>(Val: C);
5916 if (S.getLangOpts().OpenMP >= 50 &&
5917 !Stack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>() &&
5918 isOpenMPTargetExecutionDirective(DKind: Stack->getCurrentDirective()) &&
5919 AC->getAllocator()) {
5920 Expr *Allocator = AC->getAllocator();
5921 // OpenMP, 2.12.5 target Construct
5922 // Memory allocators that do not appear in a uses_allocators clause cannot
5923 // appear as an allocator in an allocate clause or be used in the target
5924 // region unless a requires directive with the dynamic_allocators clause
5925 // is present in the same compilation unit.
5926 AllocatorChecker Checker(Stack);
5927 if (Checker.Visit(S: Allocator))
5928 S.Diag(Loc: Allocator->getExprLoc(),
5929 DiagID: diag::err_omp_allocator_not_in_uses_allocators)
5930 << Allocator->getSourceRange();
5931 }
5932 OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind =
5933 getAllocatorKind(S, Stack, Allocator: AC->getAllocator());
5934 // OpenMP, 2.11.4 allocate Clause, Restrictions.
5935 // For task, taskloop or target directives, allocation requests to memory
5936 // allocators with the trait access set to thread result in unspecified
5937 // behavior.
5938 if (AllocatorKind == OMPAllocateDeclAttr::OMPThreadMemAlloc &&
5939 (isOpenMPTaskingDirective(Kind: Stack->getCurrentDirective()) ||
5940 isOpenMPTargetExecutionDirective(DKind: Stack->getCurrentDirective()))) {
5941 llvm::omp::Version OMPVersion = S.getLangOpts().getOpenMPVersion();
5942 S.Diag(Loc: AC->getAllocator()->getExprLoc(),
5943 DiagID: diag::warn_omp_allocate_thread_on_task_target_directive)
5944 << getOpenMPDirectiveName(D: Stack->getCurrentDirective(), V: OMPVersion);
5945 }
5946 for (Expr *E : AC->varlist()) {
5947 SourceLocation ELoc;
5948 SourceRange ERange;
5949 Expr *SimpleRefExpr = E;
5950 auto Res = getPrivateItem(S, RefExpr&: SimpleRefExpr, ELoc, ERange);
5951 ValueDecl *VD = Res.first;
5952 if (!VD)
5953 continue;
5954 DSAStackTy::DSAVarData Data = Stack->getTopDSA(D: VD, /*FromParent=*/false);
5955 if (!isOpenMPPrivate(Kind: Data.CKind)) {
5956 S.Diag(Loc: E->getExprLoc(),
5957 DiagID: diag::err_omp_expected_private_copy_for_allocate);
5958 continue;
5959 }
5960 VarDecl *PrivateVD = DeclToCopy[VD];
5961 if (checkPreviousOMPAllocateAttribute(S, Stack, RefExpr: E, VD: PrivateVD,
5962 AllocatorKind, Allocator: AC->getAllocator()))
5963 continue;
5964 applyOMPAllocateAttribute(S, VD: PrivateVD, AllocatorKind, Allocator: AC->getAllocator(),
5965 Alignment: AC->getAlignment(), SR: E->getSourceRange());
5966 }
5967 }
5968}
5969
5970namespace {
5971/// Rewrite statements and expressions for Sema \p Actions CurContext.
5972///
5973/// Used to wrap already parsed statements/expressions into a new CapturedStmt
5974/// context. DeclRefExpr used inside the new context are changed to refer to the
5975/// captured variable instead.
5976class CaptureVars : public TreeTransform<CaptureVars> {
5977 using BaseTransform = TreeTransform<CaptureVars>;
5978
5979public:
5980 CaptureVars(Sema &Actions) : BaseTransform(Actions) {}
5981
5982 bool AlwaysRebuild() { return true; }
5983};
5984} // namespace
5985
5986/// Like ASTContext::getIntTypeForBitwidth, but falls back to a _BitInt type
5987/// when no standard integer type has the requested width.
5988static QualType getIntTypeForBitwidthOrBitInt(ASTContext &C, unsigned Bits,
5989 bool Signed) {
5990 QualType Ty = C.getIntTypeForBitwidth(DestWidth: Bits, Signed);
5991 if (Ty.isNull())
5992 Ty = C.getBitIntType(/*IsUnsigned=*/Unsigned: !Signed, NumBits: Bits);
5993 return Ty;
5994}
5995
5996static VarDecl *precomputeExpr(Sema &Actions,
5997 SmallVectorImpl<Stmt *> &BodyStmts, Expr *E,
5998 StringRef Name) {
5999 Expr *NewE = AssertSuccess(R: CaptureVars(Actions).TransformExpr(E));
6000 VarDecl *NewVar = buildVarDecl(SemaRef&: Actions, Loc: {}, Type: NewE->getType(), Name, Attrs: nullptr,
6001 OrigRef: dyn_cast<DeclRefExpr>(Val: E->IgnoreImplicit()));
6002 auto *NewDeclStmt = cast<DeclStmt>(Val: AssertSuccess(
6003 R: Actions.ActOnDeclStmt(Decl: Actions.ConvertDeclToDeclGroup(Ptr: NewVar), StartLoc: {}, EndLoc: {})));
6004 Actions.AddInitializerToDecl(dcl: NewDeclStmt->getSingleDecl(), init: NewE, DirectInit: false);
6005 BodyStmts.push_back(Elt: NewDeclStmt);
6006 return NewVar;
6007}
6008
6009/// Create a closure that computes the number of iterations of a loop.
6010///
6011/// \param Actions The Sema object.
6012/// \param LogicalTy Type for the logical iteration number.
6013/// \param Rel Comparison operator of the loop condition.
6014/// \param StartExpr Value of the loop counter at the first iteration.
6015/// \param StopExpr Expression the loop counter is compared against in the loop
6016/// condition. \param StepExpr Amount of increment after each iteration.
6017///
6018/// \return Closure (CapturedStmt) of the distance calculation.
6019static CapturedStmt *buildDistanceFunc(Sema &Actions, QualType LogicalTy,
6020 BinaryOperator::Opcode Rel,
6021 Expr *StartExpr, Expr *StopExpr,
6022 Expr *StepExpr) {
6023 ASTContext &Ctx = Actions.getASTContext();
6024 TypeSourceInfo *LogicalTSI = Ctx.getTrivialTypeSourceInfo(T: LogicalTy);
6025
6026 // Captured regions currently don't support return values, we use an
6027 // out-parameter instead. All inputs are implicit captures.
6028 // TODO: Instead of capturing each DeclRefExpr occurring in
6029 // StartExpr/StopExpr/Step, these could also be passed as a value capture.
6030 QualType ResultTy = Ctx.getLValueReferenceType(T: LogicalTy);
6031 Sema::CapturedParamNameType Params[] = {{"Distance", ResultTy},
6032 {StringRef(), QualType()}};
6033 Actions.ActOnCapturedRegionStart(Loc: {}, CurScope: nullptr, Kind: CR_Default, Params);
6034
6035 Stmt *Body;
6036 {
6037 Sema::CompoundScopeRAII CompoundScope(Actions);
6038 CapturedDecl *CS = cast<CapturedDecl>(Val: Actions.CurContext);
6039
6040 // Get the LValue expression for the result.
6041 ImplicitParamDecl *DistParam = CS->getParam(i: 0);
6042 DeclRefExpr *DistRef = Actions.BuildDeclRefExpr(
6043 D: DistParam, Ty: LogicalTy, VK: VK_LValue, NameInfo: {}, SS: nullptr, FoundD: nullptr, TemplateKWLoc: {}, TemplateArgs: nullptr);
6044
6045 SmallVector<Stmt *, 4> BodyStmts;
6046
6047 // Capture all referenced variable references.
6048 // TODO: Instead of computing NewStart/NewStop/NewStep inside the
6049 // CapturedStmt, we could compute them before and capture the result, to be
6050 // used jointly with the LoopVar function.
6051 VarDecl *NewStart = precomputeExpr(Actions, BodyStmts, E: StartExpr, Name: ".start");
6052 VarDecl *NewStop = precomputeExpr(Actions, BodyStmts, E: StopExpr, Name: ".stop");
6053 VarDecl *NewStep = precomputeExpr(Actions, BodyStmts, E: StepExpr, Name: ".step");
6054 auto BuildVarRef = [&](VarDecl *VD) {
6055 return buildDeclRefExpr(S&: Actions, D: VD, Ty: VD->getType(), Loc: {});
6056 };
6057
6058 IntegerLiteral *Zero = IntegerLiteral::Create(
6059 C: Ctx, V: llvm::APInt(Ctx.getIntWidth(T: LogicalTy), 0), type: LogicalTy, l: {});
6060 IntegerLiteral *One = IntegerLiteral::Create(
6061 C: Ctx, V: llvm::APInt(Ctx.getIntWidth(T: LogicalTy), 1), type: LogicalTy, l: {});
6062 Expr *Dist;
6063 if (Rel == BO_NE) {
6064 // When using a != comparison, the increment can be +1 or -1. This can be
6065 // dynamic at runtime, so we need to check for the direction.
6066 Expr *IsNegStep = AssertSuccess(
6067 R: Actions.BuildBinOp(S: nullptr, OpLoc: {}, Opc: BO_LT, LHSExpr: BuildVarRef(NewStep), RHSExpr: Zero));
6068
6069 // Positive increment.
6070 Expr *ForwardRange = AssertSuccess(R: Actions.BuildBinOp(
6071 S: nullptr, OpLoc: {}, Opc: BO_Sub, LHSExpr: BuildVarRef(NewStop), RHSExpr: BuildVarRef(NewStart)));
6072 ForwardRange = AssertSuccess(
6073 R: Actions.BuildCStyleCastExpr(LParenLoc: {}, Ty: LogicalTSI, RParenLoc: {}, Op: ForwardRange));
6074 Expr *ForwardDist = AssertSuccess(R: Actions.BuildBinOp(
6075 S: nullptr, OpLoc: {}, Opc: BO_Div, LHSExpr: ForwardRange, RHSExpr: BuildVarRef(NewStep)));
6076
6077 // Negative increment.
6078 Expr *BackwardRange = AssertSuccess(R: Actions.BuildBinOp(
6079 S: nullptr, OpLoc: {}, Opc: BO_Sub, LHSExpr: BuildVarRef(NewStart), RHSExpr: BuildVarRef(NewStop)));
6080 BackwardRange = AssertSuccess(
6081 R: Actions.BuildCStyleCastExpr(LParenLoc: {}, Ty: LogicalTSI, RParenLoc: {}, Op: BackwardRange));
6082 Expr *NegIncAmount = AssertSuccess(
6083 R: Actions.BuildUnaryOp(S: nullptr, OpLoc: {}, Opc: UO_Minus, Input: BuildVarRef(NewStep)));
6084 Expr *BackwardDist = AssertSuccess(
6085 R: Actions.BuildBinOp(S: nullptr, OpLoc: {}, Opc: BO_Div, LHSExpr: BackwardRange, RHSExpr: NegIncAmount));
6086
6087 // Use the appropriate case.
6088 Dist = AssertSuccess(R: Actions.ActOnConditionalOp(
6089 QuestionLoc: {}, ColonLoc: {}, CondExpr: IsNegStep, LHSExpr: BackwardDist, RHSExpr: ForwardDist));
6090 } else {
6091 assert((Rel == BO_LT || Rel == BO_LE || Rel == BO_GE || Rel == BO_GT) &&
6092 "Expected one of these relational operators");
6093
6094 // We can derive the direction from any other comparison operator. It is
6095 // non well-formed OpenMP if Step increments/decrements in the other
6096 // directions. Whether at least the first iteration passes the loop
6097 // condition.
6098 Expr *HasAnyIteration = AssertSuccess(R: Actions.BuildBinOp(
6099 S: nullptr, OpLoc: {}, Opc: Rel, LHSExpr: BuildVarRef(NewStart), RHSExpr: BuildVarRef(NewStop)));
6100
6101 // Compute the range between first and last counter value.
6102 Expr *Range;
6103 if (Rel == BO_GE || Rel == BO_GT)
6104 Range = AssertSuccess(R: Actions.BuildBinOp(
6105 S: nullptr, OpLoc: {}, Opc: BO_Sub, LHSExpr: BuildVarRef(NewStart), RHSExpr: BuildVarRef(NewStop)));
6106 else
6107 Range = AssertSuccess(R: Actions.BuildBinOp(
6108 S: nullptr, OpLoc: {}, Opc: BO_Sub, LHSExpr: BuildVarRef(NewStop), RHSExpr: BuildVarRef(NewStart)));
6109
6110 // Ensure unsigned range space.
6111 Range =
6112 AssertSuccess(R: Actions.BuildCStyleCastExpr(LParenLoc: {}, Ty: LogicalTSI, RParenLoc: {}, Op: Range));
6113
6114 if (Rel == BO_LE || Rel == BO_GE) {
6115 // Add one to the range if the relational operator is inclusive.
6116 Range =
6117 AssertSuccess(R: Actions.BuildBinOp(S: nullptr, OpLoc: {}, Opc: BO_Add, LHSExpr: Range, RHSExpr: One));
6118 }
6119
6120 // Divide by the absolute step amount. If the range is not a multiple of
6121 // the step size, rounding-up the effective upper bound ensures that the
6122 // last iteration is included.
6123 // Note that the rounding-up may cause an overflow in a temporary that
6124 // could be avoided, but would have occurred in a C-style for-loop as
6125 // well.
6126 Expr *Divisor = BuildVarRef(NewStep);
6127 if (Rel == BO_GE || Rel == BO_GT)
6128 Divisor =
6129 AssertSuccess(R: Actions.BuildUnaryOp(S: nullptr, OpLoc: {}, Opc: UO_Minus, Input: Divisor));
6130 Expr *DivisorMinusOne =
6131 AssertSuccess(R: Actions.BuildBinOp(S: nullptr, OpLoc: {}, Opc: BO_Sub, LHSExpr: Divisor, RHSExpr: One));
6132 Expr *RangeRoundUp = AssertSuccess(
6133 R: Actions.BuildBinOp(S: nullptr, OpLoc: {}, Opc: BO_Add, LHSExpr: Range, RHSExpr: DivisorMinusOne));
6134 Dist = AssertSuccess(
6135 R: Actions.BuildBinOp(S: nullptr, OpLoc: {}, Opc: BO_Div, LHSExpr: RangeRoundUp, RHSExpr: Divisor));
6136
6137 // If there is not at least one iteration, the range contains garbage. Fix
6138 // to zero in this case.
6139 Dist = AssertSuccess(
6140 R: Actions.ActOnConditionalOp(QuestionLoc: {}, ColonLoc: {}, CondExpr: HasAnyIteration, LHSExpr: Dist, RHSExpr: Zero));
6141 }
6142
6143 // Assign the result to the out-parameter.
6144 Stmt *ResultAssign = AssertSuccess(R: Actions.BuildBinOp(
6145 S: Actions.getCurScope(), OpLoc: {}, Opc: BO_Assign, LHSExpr: DistRef, RHSExpr: Dist));
6146 BodyStmts.push_back(Elt: ResultAssign);
6147
6148 Body = AssertSuccess(R: Actions.ActOnCompoundStmt(L: {}, R: {}, Elts: BodyStmts, isStmtExpr: false));
6149 }
6150
6151 return cast<CapturedStmt>(
6152 Val: AssertSuccess(R: Actions.ActOnCapturedRegionEnd(S: Body)));
6153}
6154
6155/// Create a closure that computes the loop variable from the logical iteration
6156/// number.
6157///
6158/// \param Actions The Sema object.
6159/// \param LoopVarTy Type for the loop variable used for result value.
6160/// \param LogicalTy Type for the logical iteration number.
6161/// \param StartExpr Value of the loop counter at the first iteration.
6162/// \param Step Amount of increment after each iteration.
6163/// \param Deref Whether the loop variable is a dereference of the loop
6164/// counter variable.
6165///
6166/// \return Closure (CapturedStmt) of the loop value calculation.
6167static CapturedStmt *buildLoopVarFunc(Sema &Actions, QualType LoopVarTy,
6168 QualType LogicalTy,
6169 DeclRefExpr *StartExpr, Expr *Step,
6170 bool Deref) {
6171 ASTContext &Ctx = Actions.getASTContext();
6172
6173 // Pass the result as an out-parameter. Passing as return value would require
6174 // the OpenMPIRBuilder to know additional C/C++ semantics, such as how to
6175 // invoke a copy constructor.
6176 QualType TargetParamTy = Ctx.getLValueReferenceType(T: LoopVarTy);
6177 SemaOpenMP::CapturedParamNameType Params[] = {{"LoopVar", TargetParamTy},
6178 {"Logical", LogicalTy},
6179 {StringRef(), QualType()}};
6180 Actions.ActOnCapturedRegionStart(Loc: {}, CurScope: nullptr, Kind: CR_Default, Params);
6181
6182 // Capture the initial iterator which represents the LoopVar value at the
6183 // zero's logical iteration. Since the original ForStmt/CXXForRangeStmt update
6184 // it in every iteration, capture it by value before it is modified.
6185 VarDecl *StartVar = cast<VarDecl>(Val: StartExpr->getDecl());
6186 bool Invalid = Actions.tryCaptureVariable(Var: StartVar, Loc: {},
6187 Kind: TryCaptureKind::ExplicitByVal, EllipsisLoc: {});
6188 (void)Invalid;
6189 assert(!Invalid && "Expecting capture-by-value to work.");
6190
6191 Expr *Body;
6192 {
6193 Sema::CompoundScopeRAII CompoundScope(Actions);
6194 auto *CS = cast<CapturedDecl>(Val: Actions.CurContext);
6195
6196 ImplicitParamDecl *TargetParam = CS->getParam(i: 0);
6197 DeclRefExpr *TargetRef = Actions.BuildDeclRefExpr(
6198 D: TargetParam, Ty: LoopVarTy, VK: VK_LValue, NameInfo: {}, SS: nullptr, FoundD: nullptr, TemplateKWLoc: {}, TemplateArgs: nullptr);
6199 ImplicitParamDecl *IndvarParam = CS->getParam(i: 1);
6200 DeclRefExpr *LogicalRef = Actions.BuildDeclRefExpr(
6201 D: IndvarParam, Ty: LogicalTy, VK: VK_LValue, NameInfo: {}, SS: nullptr, FoundD: nullptr, TemplateKWLoc: {}, TemplateArgs: nullptr);
6202
6203 // Capture the Start expression.
6204 CaptureVars Recap(Actions);
6205 Expr *NewStart = AssertSuccess(R: Recap.TransformExpr(E: StartExpr));
6206 Expr *NewStep = AssertSuccess(R: Recap.TransformExpr(E: Step));
6207
6208 Expr *Skip = AssertSuccess(
6209 R: Actions.BuildBinOp(S: nullptr, OpLoc: {}, Opc: BO_Mul, LHSExpr: NewStep, RHSExpr: LogicalRef));
6210 // TODO: Explicitly cast to the iterator's difference_type instead of
6211 // relying on implicit conversion.
6212 Expr *Advanced =
6213 AssertSuccess(R: Actions.BuildBinOp(S: nullptr, OpLoc: {}, Opc: BO_Add, LHSExpr: NewStart, RHSExpr: Skip));
6214
6215 if (Deref) {
6216 // For range-based for-loops convert the loop counter value to a concrete
6217 // loop variable value by dereferencing the iterator.
6218 Advanced =
6219 AssertSuccess(R: Actions.BuildUnaryOp(S: nullptr, OpLoc: {}, Opc: UO_Deref, Input: Advanced));
6220 }
6221
6222 // Assign the result to the output parameter.
6223 Body = AssertSuccess(R: Actions.BuildBinOp(S: Actions.getCurScope(), OpLoc: {},
6224 Opc: BO_Assign, LHSExpr: TargetRef, RHSExpr: Advanced));
6225 }
6226 return cast<CapturedStmt>(
6227 Val: AssertSuccess(R: Actions.ActOnCapturedRegionEnd(S: Body)));
6228}
6229
6230StmtResult SemaOpenMP::ActOnOpenMPCanonicalLoop(Stmt *AStmt) {
6231 ASTContext &Ctx = getASTContext();
6232
6233 // Extract the common elements of ForStmt and CXXForRangeStmt:
6234 // Loop variable, repeat condition, increment
6235 Expr *Cond, *Inc;
6236 VarDecl *LIVDecl, *LUVDecl;
6237 if (auto *For = dyn_cast<ForStmt>(Val: AStmt)) {
6238 Stmt *Init = For->getInit();
6239 if (auto *LCVarDeclStmt = dyn_cast<DeclStmt>(Val: Init)) {
6240 // For statement declares loop variable.
6241 LIVDecl = cast<VarDecl>(Val: LCVarDeclStmt->getSingleDecl());
6242 } else if (auto *LCAssign = dyn_cast<BinaryOperator>(Val: Init)) {
6243 // For statement reuses variable.
6244 assert(LCAssign->getOpcode() == BO_Assign &&
6245 "init part must be a loop variable assignment");
6246 auto *CounterRef = cast<DeclRefExpr>(Val: LCAssign->getLHS());
6247 LIVDecl = cast<VarDecl>(Val: CounterRef->getDecl());
6248 } else
6249 llvm_unreachable("Cannot determine loop variable");
6250 LUVDecl = LIVDecl;
6251
6252 Cond = For->getCond();
6253 Inc = For->getInc();
6254 } else if (auto *RangeFor = dyn_cast<CXXForRangeStmt>(Val: AStmt)) {
6255 DeclStmt *BeginStmt = RangeFor->getBeginStmt();
6256 LIVDecl = cast<VarDecl>(Val: BeginStmt->getSingleDecl());
6257 LUVDecl = RangeFor->getLoopVariable();
6258
6259 Cond = RangeFor->getCond();
6260 Inc = RangeFor->getInc();
6261 } else
6262 llvm_unreachable("unhandled kind of loop");
6263
6264 QualType CounterTy = LIVDecl->getType();
6265 QualType LVTy = LUVDecl->getType();
6266
6267 // Analyze the loop condition.
6268 Expr *LHS, *RHS;
6269 BinaryOperator::Opcode CondRel;
6270 Cond = Cond->IgnoreImplicit();
6271 if (auto *CondBinExpr = dyn_cast<BinaryOperator>(Val: Cond)) {
6272 LHS = CondBinExpr->getLHS();
6273 RHS = CondBinExpr->getRHS();
6274 CondRel = CondBinExpr->getOpcode();
6275 } else if (auto *CondCXXOp = dyn_cast<CXXOperatorCallExpr>(Val: Cond)) {
6276 assert(CondCXXOp->getNumArgs() == 2 && "Comparison should have 2 operands");
6277 LHS = CondCXXOp->getArg(Arg: 0);
6278 RHS = CondCXXOp->getArg(Arg: 1);
6279 switch (CondCXXOp->getOperator()) {
6280 case OO_ExclaimEqual:
6281 CondRel = BO_NE;
6282 break;
6283 case OO_Less:
6284 CondRel = BO_LT;
6285 break;
6286 case OO_LessEqual:
6287 CondRel = BO_LE;
6288 break;
6289 case OO_Greater:
6290 CondRel = BO_GT;
6291 break;
6292 case OO_GreaterEqual:
6293 CondRel = BO_GE;
6294 break;
6295 default:
6296 llvm_unreachable("unexpected iterator operator");
6297 }
6298 } else
6299 llvm_unreachable("unexpected loop condition");
6300
6301 // Normalize such that the loop counter is on the LHS.
6302 if (!isa<DeclRefExpr>(Val: LHS->IgnoreImplicit()) ||
6303 cast<DeclRefExpr>(Val: LHS->IgnoreImplicit())->getDecl() != LIVDecl) {
6304 std::swap(a&: LHS, b&: RHS);
6305 CondRel = BinaryOperator::reverseComparisonOp(Opc: CondRel);
6306 }
6307 auto *CounterRef = cast<DeclRefExpr>(Val: LHS->IgnoreImplicit());
6308
6309 // Decide the bit width for the logical iteration counter. By default use the
6310 // unsigned ptrdiff_t integer size (for iterators and pointers).
6311 // TODO: For iterators, use iterator::difference_type,
6312 // std::iterator_traits<>::difference_type or decltype(it - end).
6313 QualType LogicalTy = Ctx.getUnsignedPointerDiffType();
6314 if (CounterTy->isIntegerType()) {
6315 unsigned BitWidth = Ctx.getIntWidth(T: CounterTy);
6316 LogicalTy = getIntTypeForBitwidthOrBitInt(C&: Ctx, Bits: BitWidth, /*Signed=*/false);
6317 }
6318
6319 // Analyze the loop increment.
6320 Expr *Step;
6321 if (auto *IncUn = dyn_cast<UnaryOperator>(Val: Inc)) {
6322 int Direction;
6323 switch (IncUn->getOpcode()) {
6324 case UO_PreInc:
6325 case UO_PostInc:
6326 Direction = 1;
6327 break;
6328 case UO_PreDec:
6329 case UO_PostDec:
6330 Direction = -1;
6331 break;
6332 default:
6333 llvm_unreachable("unhandled unary increment operator");
6334 }
6335 Step = IntegerLiteral::Create(
6336 C: Ctx,
6337 V: llvm::APInt(Ctx.getIntWidth(T: LogicalTy), Direction, /*isSigned=*/true),
6338 type: LogicalTy, l: {});
6339 } else if (auto *IncBin = dyn_cast<BinaryOperator>(Val: Inc)) {
6340 if (IncBin->getOpcode() == BO_AddAssign) {
6341 Step = IncBin->getRHS();
6342 } else if (IncBin->getOpcode() == BO_SubAssign) {
6343 Step = AssertSuccess(
6344 R: SemaRef.BuildUnaryOp(S: nullptr, OpLoc: {}, Opc: UO_Minus, Input: IncBin->getRHS()));
6345 } else
6346 llvm_unreachable("unhandled binary increment operator");
6347 } else if (auto *CondCXXOp = dyn_cast<CXXOperatorCallExpr>(Val: Inc)) {
6348 switch (CondCXXOp->getOperator()) {
6349 case OO_PlusPlus:
6350 Step = IntegerLiteral::Create(
6351 C: Ctx, V: llvm::APInt(Ctx.getIntWidth(T: LogicalTy), 1), type: LogicalTy, l: {});
6352 break;
6353 case OO_MinusMinus:
6354 Step = IntegerLiteral::Create(
6355 C: Ctx, V: llvm::APInt(Ctx.getIntWidth(T: LogicalTy), -1), type: LogicalTy, l: {});
6356 break;
6357 case OO_PlusEqual:
6358 Step = CondCXXOp->getArg(Arg: 1);
6359 break;
6360 case OO_MinusEqual:
6361 Step = AssertSuccess(
6362 R: SemaRef.BuildUnaryOp(S: nullptr, OpLoc: {}, Opc: UO_Minus, Input: CondCXXOp->getArg(Arg: 1)));
6363 break;
6364 default:
6365 llvm_unreachable("unhandled overloaded increment operator");
6366 }
6367 } else
6368 llvm_unreachable("unknown increment expression");
6369
6370 CapturedStmt *DistanceFunc =
6371 buildDistanceFunc(Actions&: SemaRef, LogicalTy, Rel: CondRel, StartExpr: LHS, StopExpr: RHS, StepExpr: Step);
6372 CapturedStmt *LoopVarFunc = buildLoopVarFunc(
6373 Actions&: SemaRef, LoopVarTy: LVTy, LogicalTy, StartExpr: CounterRef, Step, Deref: isa<CXXForRangeStmt>(Val: AStmt));
6374 DeclRefExpr *LVRef =
6375 SemaRef.BuildDeclRefExpr(D: LUVDecl, Ty: LUVDecl->getType(), VK: VK_LValue, NameInfo: {},
6376 SS: nullptr, FoundD: nullptr, TemplateKWLoc: {}, TemplateArgs: nullptr);
6377 return OMPCanonicalLoop::create(Ctx: getASTContext(), LoopStmt: AStmt, DistanceFunc,
6378 LoopVarFunc, LoopVarRef: LVRef);
6379}
6380
6381StmtResult SemaOpenMP::ActOnOpenMPLoopnest(Stmt *AStmt) {
6382 // Handle a literal loop.
6383 if (isa<ForStmt>(Val: AStmt) || isa<CXXForRangeStmt>(Val: AStmt))
6384 return ActOnOpenMPCanonicalLoop(AStmt);
6385
6386 // If not a literal loop, it must be the result of a loop transformation.
6387 OMPExecutableDirective *LoopTransform = cast<OMPExecutableDirective>(Val: AStmt);
6388 assert(
6389 isOpenMPLoopTransformationDirective(LoopTransform->getDirectiveKind()) &&
6390 "Loop transformation directive expected");
6391 return LoopTransform;
6392}
6393
6394static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
6395 CXXScopeSpec &MapperIdScopeSpec,
6396 const DeclarationNameInfo &MapperId,
6397 QualType Type,
6398 Expr *UnresolvedMapper,
6399 SourceLocation ItemLoc);
6400
6401/// Perform DFS through the structure/class data members trying to find
6402/// member(s) with user-defined 'default' mapper and generate implicit map
6403/// clauses for such members with the found 'default' mapper.
6404static void
6405processImplicitMapsWithDefaultMappers(Sema &S, DSAStackTy *Stack,
6406 SmallVectorImpl<OMPClause *> &Clauses) {
6407 // Check for the default mapper for data members.
6408 if (S.getLangOpts().OpenMP < 50)
6409 return;
6410 for (int Cnt = 0, EndCnt = Clauses.size(); Cnt < EndCnt; ++Cnt) {
6411 auto *C = dyn_cast<OMPMapClause>(Val: Clauses[Cnt]);
6412 if (!C)
6413 continue;
6414 SmallVector<Expr *, 4> SubExprs;
6415 auto *MI = C->mapperlist_begin();
6416 for (auto I = C->varlist_begin(), End = C->varlist_end(); I != End;
6417 ++I, ++MI) {
6418 // Expression is mapped using mapper - skip it.
6419 if (*MI)
6420 continue;
6421 Expr *E = *I;
6422 // Expression is dependent - skip it, build the mapper when it gets
6423 // instantiated.
6424 if (E->isTypeDependent() || E->isValueDependent() ||
6425 E->containsUnexpandedParameterPack())
6426 continue;
6427 // Array section - need to check for the mapping of the array section
6428 // element.
6429 QualType CanonType = E->getType().getCanonicalType();
6430 if (CanonType->isSpecificBuiltinType(K: BuiltinType::ArraySection)) {
6431 const auto *OASE = cast<ArraySectionExpr>(Val: E->IgnoreParenImpCasts());
6432 QualType BaseType =
6433 ArraySectionExpr::getBaseOriginalType(Base: OASE->getBase());
6434 QualType ElemType;
6435 if (const auto *ATy = BaseType->getAsArrayTypeUnsafe())
6436 ElemType = ATy->getElementType();
6437 else
6438 ElemType = BaseType->getPointeeType();
6439 CanonType = ElemType;
6440 }
6441
6442 // DFS over data members in structures/classes.
6443 SmallVector<std::pair<QualType, FieldDecl *>, 4> Types(
6444 1, {CanonType, nullptr});
6445 llvm::DenseMap<const Type *, Expr *> Visited;
6446 SmallVector<std::pair<FieldDecl *, unsigned>, 4> ParentChain(
6447 1, {nullptr, 1});
6448 while (!Types.empty()) {
6449 QualType BaseType;
6450 FieldDecl *CurFD;
6451 std::tie(args&: BaseType, args&: CurFD) = Types.pop_back_val();
6452 while (ParentChain.back().second == 0)
6453 ParentChain.pop_back();
6454 --ParentChain.back().second;
6455 if (BaseType.isNull())
6456 continue;
6457 // Only structs/classes are allowed to have mappers.
6458 const RecordDecl *RD = BaseType.getCanonicalType()->getAsRecordDecl();
6459 if (!RD)
6460 continue;
6461 auto It = Visited.find(Val: BaseType.getTypePtr());
6462 if (It == Visited.end()) {
6463 // Try to find the associated user-defined mapper.
6464 CXXScopeSpec MapperIdScopeSpec;
6465 DeclarationNameInfo DefaultMapperId;
6466 DefaultMapperId.setName(S.Context.DeclarationNames.getIdentifier(
6467 ID: &S.Context.Idents.get(Name: "default")));
6468 DefaultMapperId.setLoc(E->getExprLoc());
6469 ExprResult ER = buildUserDefinedMapperRef(
6470 SemaRef&: S, S: Stack->getCurScope(), MapperIdScopeSpec, MapperId: DefaultMapperId,
6471 Type: BaseType, /*UnresolvedMapper=*/nullptr, ItemLoc: E->getExprLoc());
6472 if (ER.isInvalid())
6473 continue;
6474 It = Visited.try_emplace(Key: BaseType.getTypePtr(), Args: ER.get()).first;
6475 }
6476 // Found default mapper.
6477 if (It->second) {
6478 auto *OE = new (S.Context) OpaqueValueExpr(E->getExprLoc(), CanonType,
6479 VK_LValue, OK_Ordinary, E);
6480 OE->setIsUnique(/*V=*/true);
6481 Expr *BaseExpr = OE;
6482 for (const auto &P : ParentChain) {
6483 if (P.first) {
6484 BaseExpr = S.BuildMemberExpr(
6485 Base: BaseExpr, /*IsArrow=*/false, OpLoc: E->getExprLoc(),
6486 NNS: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), Member: P.first,
6487 FoundDecl: DeclAccessPair::make(D: P.first, AS: P.first->getAccess()),
6488 /*HadMultipleCandidates=*/false, MemberNameInfo: DeclarationNameInfo(),
6489 Ty: P.first->getType(), VK: VK_LValue, OK: OK_Ordinary);
6490 BaseExpr = S.DefaultLvalueConversion(E: BaseExpr).get();
6491 }
6492 }
6493 if (CurFD)
6494 BaseExpr = S.BuildMemberExpr(
6495 Base: BaseExpr, /*IsArrow=*/false, OpLoc: E->getExprLoc(),
6496 NNS: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), Member: CurFD,
6497 FoundDecl: DeclAccessPair::make(D: CurFD, AS: CurFD->getAccess()),
6498 /*HadMultipleCandidates=*/false, MemberNameInfo: DeclarationNameInfo(),
6499 Ty: CurFD->getType(), VK: VK_LValue, OK: OK_Ordinary);
6500 SubExprs.push_back(Elt: BaseExpr);
6501 continue;
6502 }
6503 // Check for the "default" mapper for data members.
6504 bool FirstIter = true;
6505 for (FieldDecl *FD : RD->fields()) {
6506 if (!FD)
6507 continue;
6508 QualType FieldTy = FD->getType();
6509 if (FieldTy.isNull() ||
6510 !(FieldTy->isStructureOrClassType() || FieldTy->isUnionType()))
6511 continue;
6512 if (FirstIter) {
6513 FirstIter = false;
6514 ParentChain.emplace_back(Args&: CurFD, Args: 1);
6515 } else {
6516 ++ParentChain.back().second;
6517 }
6518 Types.emplace_back(Args&: FieldTy, Args&: FD);
6519 }
6520 }
6521 }
6522 if (SubExprs.empty())
6523 continue;
6524 CXXScopeSpec MapperIdScopeSpec;
6525 DeclarationNameInfo MapperId;
6526 if (OMPClause *NewClause = S.OpenMP().ActOnOpenMPMapClause(
6527 IteratorModifier: nullptr, MapTypeModifiers: C->getMapTypeModifiers(), MapTypeModifiersLoc: C->getMapTypeModifiersLoc(),
6528 MapperIdScopeSpec, MapperId, MapType: C->getMapType(),
6529 /*IsMapTypeImplicit=*/true, MapLoc: SourceLocation(), ColonLoc: SourceLocation(),
6530 VarList: SubExprs, Locs: OMPVarListLocTy()))
6531 Clauses.push_back(Elt: NewClause);
6532 }
6533}
6534
6535namespace {
6536/// A 'teams loop' with a nested 'loop bind(parallel)' or generic function
6537/// call in the associated loop-nest cannot be a 'parallel for'.
6538class TeamsLoopChecker final : public ConstStmtVisitor<TeamsLoopChecker> {
6539 Sema &SemaRef;
6540
6541public:
6542 bool teamsLoopCanBeParallelFor() const { return TeamsLoopCanBeParallelFor; }
6543
6544 // Is there a nested OpenMP loop bind(parallel)
6545 void VisitOMPExecutableDirective(const OMPExecutableDirective *D) {
6546 if (D->getDirectiveKind() == llvm::omp::Directive::OMPD_loop) {
6547 if (const auto *C = D->getSingleClause<OMPBindClause>())
6548 if (C->getBindKind() == OMPC_BIND_parallel) {
6549 TeamsLoopCanBeParallelFor = false;
6550 // No need to continue visiting any more
6551 return;
6552 }
6553 }
6554 for (const Stmt *Child : D->children())
6555 if (Child)
6556 Visit(S: Child);
6557 }
6558
6559 void VisitCallExpr(const CallExpr *C) {
6560 // Function calls inhibit parallel loop translation of 'target teams loop'
6561 // unless the assume-no-nested-parallelism flag has been specified.
6562 // OpenMP API runtime library calls do not inhibit parallel loop
6563 // translation, regardless of the assume-no-nested-parallelism.
6564 bool IsOpenMPAPI = false;
6565 auto *FD = dyn_cast_or_null<FunctionDecl>(Val: C->getCalleeDecl());
6566 if (FD) {
6567 std::string Name = FD->getNameInfo().getAsString();
6568 IsOpenMPAPI = Name.find(s: "omp_") == 0;
6569 }
6570 TeamsLoopCanBeParallelFor =
6571 IsOpenMPAPI || SemaRef.getLangOpts().OpenMPNoNestedParallelism;
6572 if (!TeamsLoopCanBeParallelFor)
6573 return;
6574
6575 for (const Stmt *Child : C->children())
6576 if (Child)
6577 Visit(S: Child);
6578 }
6579
6580 void VisitCapturedStmt(const CapturedStmt *S) {
6581 if (!S)
6582 return;
6583 Visit(S: S->getCapturedDecl()->getBody());
6584 }
6585
6586 void VisitStmt(const Stmt *S) {
6587 if (!S)
6588 return;
6589 for (const Stmt *Child : S->children())
6590 if (Child)
6591 Visit(S: Child);
6592 }
6593 explicit TeamsLoopChecker(Sema &SemaRef)
6594 : SemaRef(SemaRef), TeamsLoopCanBeParallelFor(true) {}
6595
6596private:
6597 bool TeamsLoopCanBeParallelFor;
6598};
6599} // namespace
6600
6601static bool teamsLoopCanBeParallelFor(Stmt *AStmt, Sema &SemaRef) {
6602 TeamsLoopChecker Checker(SemaRef);
6603 Checker.Visit(S: AStmt);
6604 return Checker.teamsLoopCanBeParallelFor();
6605}
6606
6607StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
6608 OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
6609 OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses,
6610 Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) {
6611 assert(isOpenMPExecutableDirective(Kind) && "Unexpected directive category");
6612
6613 StmtResult Res = StmtError();
6614 OpenMPBindClauseKind BindKind = OMPC_BIND_unknown;
6615 llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit;
6616
6617 if (const OMPBindClause *BC =
6618 OMPExecutableDirective::getSingleClause<OMPBindClause>(Clauses))
6619 BindKind = BC->getBindKind();
6620
6621 if (Kind == OMPD_loop && BindKind == OMPC_BIND_unknown) {
6622 const OpenMPDirectiveKind ParentDirective = DSAStack->getParentDirective();
6623
6624 // Setting the enclosing teams or parallel construct for the loop
6625 // directive without bind clause.
6626 // [5.0:129:25-28] If the bind clause is not present on the construct and
6627 // the loop construct is closely nested inside a teams or parallel
6628 // construct, the binding region is the corresponding teams or parallel
6629 // region. If none of those conditions hold, the binding region is not
6630 // defined.
6631 BindKind = OMPC_BIND_thread; // Default bind(thread) if binding is unknown
6632 ArrayRef<OpenMPDirectiveKind> ParentLeafs =
6633 getLeafConstructsOrSelf(D: ParentDirective);
6634
6635 if (ParentDirective == OMPD_unknown) {
6636 Diag(DSAStack->getDefaultDSALocation(),
6637 DiagID: diag::err_omp_bind_required_on_loop);
6638 } else if (ParentLeafs.back() == OMPD_parallel) {
6639 BindKind = OMPC_BIND_parallel;
6640 } else if (ParentLeafs.back() == OMPD_teams) {
6641 BindKind = OMPC_BIND_teams;
6642 }
6643
6644 assert(BindKind != OMPC_BIND_unknown && "Expecting BindKind");
6645
6646 OMPClause *C =
6647 ActOnOpenMPBindClause(Kind: BindKind, KindLoc: SourceLocation(), StartLoc: SourceLocation(),
6648 LParenLoc: SourceLocation(), EndLoc: SourceLocation());
6649 ClausesWithImplicit.push_back(Elt: C);
6650 }
6651
6652 // Diagnose "loop bind(teams)" with "reduction".
6653 if (Kind == OMPD_loop && BindKind == OMPC_BIND_teams) {
6654 for (OMPClause *C : Clauses) {
6655 if (C->getClauseKind() == OMPC_reduction)
6656 Diag(DSAStack->getDefaultDSALocation(),
6657 DiagID: diag::err_omp_loop_reduction_clause);
6658 }
6659 }
6660
6661 // First check CancelRegion which is then used in checkNestingOfRegions.
6662 if (checkCancelRegion(SemaRef, CurrentRegion: Kind, CancelRegion, StartLoc) ||
6663 checkNestingOfRegions(SemaRef, DSAStack, CurrentRegion: Kind, CurrentName: DirName, CancelRegion,
6664 BindKind, StartLoc)) {
6665 return StmtError();
6666 }
6667
6668 // Report affected OpenMP target offloading behavior when in HIP lang-mode.
6669 if (getLangOpts().HIP && (isOpenMPTargetExecutionDirective(DKind: Kind) ||
6670 isOpenMPTargetDataManagementDirective(DKind: Kind)))
6671 Diag(Loc: StartLoc, DiagID: diag::warn_hip_omp_target_directives);
6672
6673 VarsWithInheritedDSAType VarsWithInheritedDSA;
6674 bool ErrorFound = false;
6675 ClausesWithImplicit.append(in_start: Clauses.begin(), in_end: Clauses.end());
6676
6677 if (AStmt && !SemaRef.CurContext->isDependentContext() &&
6678 isOpenMPCapturingDirective(DKind: Kind)) {
6679 assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
6680
6681 // Check default data sharing attributes for referenced variables.
6682 DSAAttrChecker DSAChecker(DSAStack, SemaRef, cast<CapturedStmt>(Val: AStmt));
6683 int ThisCaptureLevel = getOpenMPCaptureLevels(DKind: Kind);
6684 Stmt *S = AStmt;
6685 while (--ThisCaptureLevel >= 0)
6686 S = cast<CapturedStmt>(Val: S)->getCapturedStmt();
6687 DSAChecker.Visit(S);
6688 if (!isOpenMPTargetDataManagementDirective(DKind: Kind) &&
6689 !isOpenMPTaskingDirective(Kind)) {
6690 // Visit subcaptures to generate implicit clauses for captured vars.
6691 auto *CS = cast<CapturedStmt>(Val: AStmt);
6692 SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
6693 getOpenMPCaptureRegions(CaptureRegions, DKind: Kind);
6694 // Ignore outer tasking regions for target directives.
6695 if (CaptureRegions.size() > 1 && CaptureRegions.front() == OMPD_task)
6696 CS = cast<CapturedStmt>(Val: CS->getCapturedStmt());
6697 DSAChecker.visitSubCaptures(S: CS);
6698 }
6699 if (DSAChecker.isErrorFound())
6700 return StmtError();
6701 // Generate list of implicitly defined firstprivate variables.
6702 VarsWithInheritedDSA = DSAChecker.getVarsWithInheritedDSA();
6703 VariableImplicitInfo ImpInfo = DSAChecker.getImplicitInfo();
6704
6705 SmallVector<SourceLocation, NumberOfOMPMapClauseModifiers>
6706 ImplicitMapModifiersLoc[VariableImplicitInfo::DefaultmapKindNum];
6707 // Get the original location of present modifier from Defaultmap clause.
6708 SourceLocation PresentModifierLocs[VariableImplicitInfo::DefaultmapKindNum];
6709 for (OMPClause *C : Clauses) {
6710 if (auto *DMC = dyn_cast<OMPDefaultmapClause>(Val: C))
6711 if (DMC->getDefaultmapModifier() == OMPC_DEFAULTMAP_MODIFIER_present)
6712 PresentModifierLocs[DMC->getDefaultmapKind()] =
6713 DMC->getDefaultmapModifierLoc();
6714 }
6715
6716 for (OpenMPDefaultmapClauseKind K :
6717 llvm::enum_seq_inclusive<OpenMPDefaultmapClauseKind>(
6718 Begin: OpenMPDefaultmapClauseKind(), End: OMPC_DEFAULTMAP_unknown)) {
6719 std::fill_n(first: std::back_inserter(x&: ImplicitMapModifiersLoc[K]),
6720 n: ImpInfo.MapModifiers[K].size(), value: PresentModifierLocs[K]);
6721 }
6722 // Mark taskgroup task_reduction descriptors as implicitly firstprivate.
6723 for (OMPClause *C : Clauses) {
6724 if (auto *IRC = dyn_cast<OMPInReductionClause>(Val: C)) {
6725 for (Expr *E : IRC->taskgroup_descriptors())
6726 if (E)
6727 ImpInfo.Firstprivates.insert(X: E);
6728 }
6729 // OpenMP 5.0, 2.10.1 task Construct
6730 // [detach clause]... The event-handle will be considered as if it was
6731 // specified on a firstprivate clause.
6732 if (auto *DC = dyn_cast<OMPDetachClause>(Val: C))
6733 ImpInfo.Firstprivates.insert(X: DC->getEventHandler());
6734 }
6735 if (!ImpInfo.Firstprivates.empty()) {
6736 if (OMPClause *Implicit = ActOnOpenMPFirstprivateClause(
6737 VarList: ImpInfo.Firstprivates.getArrayRef(), StartLoc: SourceLocation(),
6738 LParenLoc: SourceLocation(), EndLoc: SourceLocation())) {
6739 ClausesWithImplicit.push_back(Elt: Implicit);
6740 ErrorFound = cast<OMPFirstprivateClause>(Val: Implicit)->varlist_size() !=
6741 ImpInfo.Firstprivates.size();
6742 } else {
6743 ErrorFound = true;
6744 }
6745 }
6746 if (!ImpInfo.Privates.empty()) {
6747 if (OMPClause *Implicit = ActOnOpenMPPrivateClause(
6748 VarList: ImpInfo.Privates.getArrayRef(), StartLoc: SourceLocation(),
6749 LParenLoc: SourceLocation(), EndLoc: SourceLocation())) {
6750 ClausesWithImplicit.push_back(Elt: Implicit);
6751 ErrorFound = cast<OMPPrivateClause>(Val: Implicit)->varlist_size() !=
6752 ImpInfo.Privates.size();
6753 } else {
6754 ErrorFound = true;
6755 }
6756 }
6757 // OpenMP 5.0 [2.19.7]
6758 // If a list item appears in a reduction, lastprivate or linear
6759 // clause on a combined target construct then it is treated as
6760 // if it also appears in a map clause with a map-type of tofrom
6761 if (getLangOpts().OpenMP >= 50 && Kind != OMPD_target &&
6762 isOpenMPTargetExecutionDirective(DKind: Kind)) {
6763 SmallVector<Expr *, 4> ImplicitExprs;
6764 for (OMPClause *C : Clauses) {
6765 if (auto *RC = dyn_cast<OMPReductionClause>(Val: C))
6766 for (Expr *E : RC->varlist())
6767 if (!isa<DeclRefExpr>(Val: E->IgnoreParenImpCasts()))
6768 ImplicitExprs.emplace_back(Args&: E);
6769 }
6770 if (!ImplicitExprs.empty()) {
6771 ArrayRef<Expr *> Exprs = ImplicitExprs;
6772 CXXScopeSpec MapperIdScopeSpec;
6773 DeclarationNameInfo MapperId;
6774 if (OMPClause *Implicit = ActOnOpenMPMapClause(
6775 IteratorModifier: nullptr, MapTypeModifiers: OMPC_MAP_MODIFIER_unknown, MapTypeModifiersLoc: SourceLocation(),
6776 MapperIdScopeSpec, MapperId, MapType: OMPC_MAP_tofrom,
6777 /*IsMapTypeImplicit=*/true, MapLoc: SourceLocation(), ColonLoc: SourceLocation(),
6778 VarList: Exprs, Locs: OMPVarListLocTy(), /*NoDiagnose=*/true))
6779 ClausesWithImplicit.emplace_back(Args&: Implicit);
6780 }
6781 }
6782 for (unsigned I = 0; I < VariableImplicitInfo::DefaultmapKindNum; ++I) {
6783 int ClauseKindCnt = -1;
6784 for (unsigned J = 0; J < VariableImplicitInfo::MapKindNum; ++J) {
6785 ArrayRef<Expr *> ImplicitMap = ImpInfo.Mappings[I][J].getArrayRef();
6786 ++ClauseKindCnt;
6787 if (ImplicitMap.empty())
6788 continue;
6789 CXXScopeSpec MapperIdScopeSpec;
6790 DeclarationNameInfo MapperId;
6791 auto K = static_cast<OpenMPMapClauseKind>(ClauseKindCnt);
6792 if (OMPClause *Implicit = ActOnOpenMPMapClause(
6793 IteratorModifier: nullptr, MapTypeModifiers: ImpInfo.MapModifiers[I], MapTypeModifiersLoc: ImplicitMapModifiersLoc[I],
6794 MapperIdScopeSpec, MapperId, MapType: K, /*IsMapTypeImplicit=*/true,
6795 MapLoc: SourceLocation(), ColonLoc: SourceLocation(), VarList: ImplicitMap,
6796 Locs: OMPVarListLocTy())) {
6797 ClausesWithImplicit.emplace_back(Args&: Implicit);
6798 ErrorFound |= cast<OMPMapClause>(Val: Implicit)->varlist_size() !=
6799 ImplicitMap.size();
6800 } else {
6801 ErrorFound = true;
6802 }
6803 }
6804 }
6805 // Build expressions for implicit maps of data members with 'default'
6806 // mappers.
6807 if (getLangOpts().OpenMP >= 50)
6808 processImplicitMapsWithDefaultMappers(S&: SemaRef, DSAStack,
6809 Clauses&: ClausesWithImplicit);
6810 }
6811
6812 switch (Kind) {
6813 case OMPD_parallel:
6814 Res = ActOnOpenMPParallelDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
6815 EndLoc);
6816 break;
6817 case OMPD_simd:
6818 Res = ActOnOpenMPSimdDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc,
6819 VarsWithImplicitDSA&: VarsWithInheritedDSA);
6820 break;
6821 case OMPD_tile:
6822 Res =
6823 ActOnOpenMPTileDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc);
6824 break;
6825 case OMPD_stripe:
6826 Res = ActOnOpenMPStripeDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
6827 EndLoc);
6828 break;
6829 case OMPD_unroll:
6830 Res = ActOnOpenMPUnrollDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
6831 EndLoc);
6832 break;
6833 case OMPD_reverse:
6834 assert(ClausesWithImplicit.empty() &&
6835 "reverse directive does not support any clauses");
6836 Res = ActOnOpenMPReverseDirective(AStmt, StartLoc, EndLoc);
6837 break;
6838 case OMPD_split:
6839 Res =
6840 ActOnOpenMPSplitDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc);
6841 break;
6842 case OMPD_interchange:
6843 Res = ActOnOpenMPInterchangeDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
6844 EndLoc);
6845 break;
6846 case OMPD_flatten:
6847 Res = ActOnOpenMPFlattenDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
6848 EndLoc);
6849 break;
6850 case OMPD_fuse:
6851 Res =
6852 ActOnOpenMPFuseDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc);
6853 break;
6854 case OMPD_for:
6855 Res = ActOnOpenMPForDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc,
6856 VarsWithImplicitDSA&: VarsWithInheritedDSA);
6857 break;
6858 case OMPD_for_simd:
6859 Res = ActOnOpenMPForSimdDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
6860 EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
6861 break;
6862 case OMPD_sections:
6863 Res = ActOnOpenMPSectionsDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
6864 EndLoc);
6865 break;
6866 case OMPD_section:
6867 assert(ClausesWithImplicit.empty() &&
6868 "No clauses are allowed for 'omp section' directive");
6869 Res = ActOnOpenMPSectionDirective(AStmt, StartLoc, EndLoc);
6870 break;
6871 case OMPD_single:
6872 Res = ActOnOpenMPSingleDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
6873 EndLoc);
6874 break;
6875 case OMPD_master:
6876 assert(ClausesWithImplicit.empty() &&
6877 "No clauses are allowed for 'omp master' directive");
6878 Res = ActOnOpenMPMasterDirective(AStmt, StartLoc, EndLoc);
6879 break;
6880 case OMPD_masked:
6881 Res = ActOnOpenMPMaskedDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
6882 EndLoc);
6883 break;
6884 case OMPD_critical:
6885 Res = ActOnOpenMPCriticalDirective(DirName, Clauses: ClausesWithImplicit, AStmt,
6886 StartLoc, EndLoc);
6887 break;
6888 case OMPD_parallel_for:
6889 Res = ActOnOpenMPParallelForDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
6890 EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
6891 break;
6892 case OMPD_parallel_for_simd:
6893 Res = ActOnOpenMPParallelForSimdDirective(
6894 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
6895 break;
6896 case OMPD_scope:
6897 Res =
6898 ActOnOpenMPScopeDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc);
6899 break;
6900 case OMPD_parallel_master:
6901 Res = ActOnOpenMPParallelMasterDirective(Clauses: ClausesWithImplicit, AStmt,
6902 StartLoc, EndLoc);
6903 break;
6904 case OMPD_parallel_masked:
6905 Res = ActOnOpenMPParallelMaskedDirective(Clauses: ClausesWithImplicit, AStmt,
6906 StartLoc, EndLoc);
6907 break;
6908 case OMPD_parallel_sections:
6909 Res = ActOnOpenMPParallelSectionsDirective(Clauses: ClausesWithImplicit, AStmt,
6910 StartLoc, EndLoc);
6911 break;
6912 case OMPD_task:
6913 Res =
6914 ActOnOpenMPTaskDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc);
6915 break;
6916 case OMPD_taskyield:
6917 assert(ClausesWithImplicit.empty() &&
6918 "No clauses are allowed for 'omp taskyield' directive");
6919 assert(AStmt == nullptr &&
6920 "No associated statement allowed for 'omp taskyield' directive");
6921 Res = ActOnOpenMPTaskyieldDirective(StartLoc, EndLoc);
6922 break;
6923 case OMPD_error:
6924 assert(AStmt == nullptr &&
6925 "No associated statement allowed for 'omp error' directive");
6926 Res = ActOnOpenMPErrorDirective(Clauses: ClausesWithImplicit, StartLoc, EndLoc);
6927 break;
6928 case OMPD_barrier:
6929 assert(ClausesWithImplicit.empty() &&
6930 "No clauses are allowed for 'omp barrier' directive");
6931 assert(AStmt == nullptr &&
6932 "No associated statement allowed for 'omp barrier' directive");
6933 Res = ActOnOpenMPBarrierDirective(StartLoc, EndLoc);
6934 break;
6935 case OMPD_taskwait:
6936 assert(AStmt == nullptr &&
6937 "No associated statement allowed for 'omp taskwait' directive");
6938 Res = ActOnOpenMPTaskwaitDirective(Clauses: ClausesWithImplicit, StartLoc, EndLoc);
6939 break;
6940 case OMPD_taskgroup:
6941 Res = ActOnOpenMPTaskgroupDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
6942 EndLoc);
6943 break;
6944 case OMPD_flush:
6945 assert(AStmt == nullptr &&
6946 "No associated statement allowed for 'omp flush' directive");
6947 Res = ActOnOpenMPFlushDirective(Clauses: ClausesWithImplicit, StartLoc, EndLoc);
6948 break;
6949 case OMPD_depobj:
6950 assert(AStmt == nullptr &&
6951 "No associated statement allowed for 'omp depobj' directive");
6952 Res = ActOnOpenMPDepobjDirective(Clauses: ClausesWithImplicit, StartLoc, EndLoc);
6953 break;
6954 case OMPD_scan:
6955 assert(AStmt == nullptr &&
6956 "No associated statement allowed for 'omp scan' directive");
6957 Res = ActOnOpenMPScanDirective(Clauses: ClausesWithImplicit, StartLoc, EndLoc);
6958 break;
6959 case OMPD_ordered_blockassoc:
6960 case OMPD_ordered_standalone:
6961 Res = ActOnOpenMPOrderedDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
6962 EndLoc);
6963 break;
6964 case OMPD_atomic:
6965 Res = ActOnOpenMPAtomicDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
6966 EndLoc);
6967 break;
6968 case OMPD_teams:
6969 Res =
6970 ActOnOpenMPTeamsDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc);
6971 break;
6972 case OMPD_target:
6973 Res = ActOnOpenMPTargetDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
6974 EndLoc);
6975 break;
6976 case OMPD_target_parallel:
6977 Res = ActOnOpenMPTargetParallelDirective(Clauses: ClausesWithImplicit, AStmt,
6978 StartLoc, EndLoc);
6979 break;
6980 case OMPD_target_parallel_for:
6981 Res = ActOnOpenMPTargetParallelForDirective(
6982 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
6983 break;
6984 case OMPD_cancellation_point:
6985 assert(ClausesWithImplicit.empty() &&
6986 "No clauses are allowed for 'omp cancellation point' directive");
6987 assert(AStmt == nullptr && "No associated statement allowed for 'omp "
6988 "cancellation point' directive");
6989 Res = ActOnOpenMPCancellationPointDirective(StartLoc, EndLoc, CancelRegion);
6990 break;
6991 case OMPD_cancel:
6992 assert(AStmt == nullptr &&
6993 "No associated statement allowed for 'omp cancel' directive");
6994 Res = ActOnOpenMPCancelDirective(Clauses: ClausesWithImplicit, StartLoc, EndLoc,
6995 CancelRegion);
6996 break;
6997 case OMPD_target_data:
6998 Res = ActOnOpenMPTargetDataDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
6999 EndLoc);
7000 break;
7001 case OMPD_target_enter_data:
7002 Res = ActOnOpenMPTargetEnterDataDirective(Clauses: ClausesWithImplicit, StartLoc,
7003 EndLoc, AStmt);
7004 break;
7005 case OMPD_target_exit_data:
7006 Res = ActOnOpenMPTargetExitDataDirective(Clauses: ClausesWithImplicit, StartLoc,
7007 EndLoc, AStmt);
7008 break;
7009 case OMPD_taskloop:
7010 Res = ActOnOpenMPTaskLoopDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
7011 EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7012 break;
7013 case OMPD_taskloop_simd:
7014 Res = ActOnOpenMPTaskLoopSimdDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
7015 EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7016 break;
7017 case OMPD_master_taskloop:
7018 Res = ActOnOpenMPMasterTaskLoopDirective(
7019 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7020 break;
7021 case OMPD_masked_taskloop:
7022 Res = ActOnOpenMPMaskedTaskLoopDirective(
7023 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7024 break;
7025 case OMPD_master_taskloop_simd:
7026 Res = ActOnOpenMPMasterTaskLoopSimdDirective(
7027 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7028 break;
7029 case OMPD_masked_taskloop_simd:
7030 Res = ActOnOpenMPMaskedTaskLoopSimdDirective(
7031 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7032 break;
7033 case OMPD_parallel_master_taskloop:
7034 Res = ActOnOpenMPParallelMasterTaskLoopDirective(
7035 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7036 break;
7037 case OMPD_parallel_masked_taskloop:
7038 Res = ActOnOpenMPParallelMaskedTaskLoopDirective(
7039 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7040 break;
7041 case OMPD_parallel_master_taskloop_simd:
7042 Res = ActOnOpenMPParallelMasterTaskLoopSimdDirective(
7043 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7044 break;
7045 case OMPD_parallel_masked_taskloop_simd:
7046 Res = ActOnOpenMPParallelMaskedTaskLoopSimdDirective(
7047 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7048 break;
7049 case OMPD_distribute:
7050 Res = ActOnOpenMPDistributeDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
7051 EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7052 break;
7053 case OMPD_target_update:
7054 Res = ActOnOpenMPTargetUpdateDirective(Clauses: ClausesWithImplicit, StartLoc,
7055 EndLoc, AStmt);
7056 break;
7057 case OMPD_distribute_parallel_for:
7058 Res = ActOnOpenMPDistributeParallelForDirective(
7059 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7060 break;
7061 case OMPD_distribute_parallel_for_simd:
7062 Res = ActOnOpenMPDistributeParallelForSimdDirective(
7063 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7064 break;
7065 case OMPD_distribute_simd:
7066 Res = ActOnOpenMPDistributeSimdDirective(
7067 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7068 break;
7069 case OMPD_target_parallel_for_simd:
7070 Res = ActOnOpenMPTargetParallelForSimdDirective(
7071 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7072 break;
7073 case OMPD_target_simd:
7074 Res = ActOnOpenMPTargetSimdDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
7075 EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7076 break;
7077 case OMPD_teams_distribute:
7078 Res = ActOnOpenMPTeamsDistributeDirective(
7079 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7080 break;
7081 case OMPD_teams_distribute_simd:
7082 Res = ActOnOpenMPTeamsDistributeSimdDirective(
7083 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7084 break;
7085 case OMPD_teams_distribute_parallel_for_simd:
7086 Res = ActOnOpenMPTeamsDistributeParallelForSimdDirective(
7087 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7088 break;
7089 case OMPD_teams_distribute_parallel_for:
7090 Res = ActOnOpenMPTeamsDistributeParallelForDirective(
7091 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7092 break;
7093 case OMPD_target_teams:
7094 Res = ActOnOpenMPTargetTeamsDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
7095 EndLoc);
7096 break;
7097 case OMPD_target_teams_distribute:
7098 Res = ActOnOpenMPTargetTeamsDistributeDirective(
7099 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7100 break;
7101 case OMPD_target_teams_distribute_parallel_for:
7102 Res = ActOnOpenMPTargetTeamsDistributeParallelForDirective(
7103 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7104 break;
7105 case OMPD_target_teams_distribute_parallel_for_simd:
7106 Res = ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective(
7107 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7108 break;
7109 case OMPD_target_teams_distribute_simd:
7110 Res = ActOnOpenMPTargetTeamsDistributeSimdDirective(
7111 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7112 break;
7113 case OMPD_interop:
7114 assert(AStmt == nullptr &&
7115 "No associated statement allowed for 'omp interop' directive");
7116 Res = ActOnOpenMPInteropDirective(Clauses: ClausesWithImplicit, StartLoc, EndLoc);
7117 break;
7118 case OMPD_dispatch:
7119 Res = ActOnOpenMPDispatchDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
7120 EndLoc);
7121 break;
7122 case OMPD_loop:
7123 Res = ActOnOpenMPGenericLoopDirective(Clauses: ClausesWithImplicit, AStmt, StartLoc,
7124 EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7125 break;
7126 case OMPD_teams_loop:
7127 Res = ActOnOpenMPTeamsGenericLoopDirective(
7128 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7129 break;
7130 case OMPD_target_teams_loop:
7131 Res = ActOnOpenMPTargetTeamsGenericLoopDirective(
7132 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7133 break;
7134 case OMPD_parallel_loop:
7135 Res = ActOnOpenMPParallelGenericLoopDirective(
7136 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7137 break;
7138 case OMPD_target_parallel_loop:
7139 Res = ActOnOpenMPTargetParallelGenericLoopDirective(
7140 Clauses: ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithImplicitDSA&: VarsWithInheritedDSA);
7141 break;
7142 case OMPD_declare_target:
7143 case OMPD_end_declare_target:
7144 case OMPD_threadprivate:
7145 case OMPD_allocate:
7146 case OMPD_declare_reduction:
7147 case OMPD_declare_mapper:
7148 case OMPD_declare_simd:
7149 case OMPD_requires:
7150 case OMPD_declare_variant:
7151 case OMPD_begin_declare_variant:
7152 case OMPD_end_declare_variant:
7153 llvm_unreachable("OpenMP Directive is not allowed");
7154 case OMPD_taskgraph:
7155 Diag(Loc: StartLoc, DiagID: diag::err_omp_unexpected_directive)
7156 << 1 << getOpenMPDirectiveName(D: OMPD_taskgraph);
7157 return StmtError();
7158 case OMPD_unknown:
7159 default:
7160 llvm_unreachable("Unknown OpenMP directive");
7161 }
7162
7163 ErrorFound = Res.isInvalid() || ErrorFound;
7164
7165 // Check variables in the clauses if default(none) or
7166 // default(firstprivate) was specified.
7167 if (DSAStack->getDefaultDSA() == DSA_none ||
7168 DSAStack->getDefaultDSA() == DSA_private ||
7169 DSAStack->getDefaultDSA() == DSA_firstprivate) {
7170 DSAAttrChecker DSAChecker(DSAStack, SemaRef, nullptr);
7171 for (OMPClause *C : Clauses) {
7172 switch (C->getClauseKind()) {
7173 case OMPC_num_threads:
7174 case OMPC_dist_schedule:
7175 // Do not analyze if no parent teams directive.
7176 if (isOpenMPTeamsDirective(DKind: Kind))
7177 break;
7178 continue;
7179 case OMPC_if:
7180 if (isOpenMPTeamsDirective(DKind: Kind) &&
7181 cast<OMPIfClause>(Val: C)->getNameModifier() != OMPD_target)
7182 break;
7183 if (isOpenMPParallelDirective(DKind: Kind) &&
7184 isOpenMPTaskLoopDirective(DKind: Kind) &&
7185 cast<OMPIfClause>(Val: C)->getNameModifier() != OMPD_parallel)
7186 break;
7187 continue;
7188 case OMPC_schedule:
7189 case OMPC_detach:
7190 break;
7191 case OMPC_grainsize:
7192 case OMPC_num_tasks:
7193 case OMPC_final:
7194 case OMPC_priority:
7195 case OMPC_novariants:
7196 case OMPC_nocontext:
7197 // Do not analyze if no parent parallel directive.
7198 if (isOpenMPParallelDirective(DKind: Kind))
7199 break;
7200 continue;
7201 case OMPC_ordered:
7202 case OMPC_device:
7203 case OMPC_num_teams:
7204 case OMPC_thread_limit:
7205 case OMPC_hint:
7206 case OMPC_collapse:
7207 case OMPC_safelen:
7208 case OMPC_simdlen:
7209 case OMPC_sizes:
7210 case OMPC_depth:
7211 case OMPC_default:
7212 case OMPC_proc_bind:
7213 case OMPC_private:
7214 case OMPC_firstprivate:
7215 case OMPC_lastprivate:
7216 case OMPC_shared:
7217 case OMPC_reduction:
7218 case OMPC_task_reduction:
7219 case OMPC_in_reduction:
7220 case OMPC_linear:
7221 case OMPC_aligned:
7222 case OMPC_copyin:
7223 case OMPC_copyprivate:
7224 case OMPC_nowait:
7225 case OMPC_untied:
7226 case OMPC_mergeable:
7227 case OMPC_allocate:
7228 case OMPC_read:
7229 case OMPC_write:
7230 case OMPC_update:
7231 case OMPC_capture:
7232 case OMPC_compare:
7233 case OMPC_seq_cst:
7234 case OMPC_acq_rel:
7235 case OMPC_acquire:
7236 case OMPC_release:
7237 case OMPC_relaxed:
7238 case OMPC_depend:
7239 case OMPC_threads:
7240 case OMPC_simd:
7241 case OMPC_map:
7242 case OMPC_nogroup:
7243 case OMPC_defaultmap:
7244 case OMPC_to:
7245 case OMPC_from:
7246 case OMPC_use_device_ptr:
7247 case OMPC_use_device_addr:
7248 case OMPC_is_device_ptr:
7249 case OMPC_has_device_addr:
7250 case OMPC_nontemporal:
7251 case OMPC_order:
7252 case OMPC_destroy:
7253 case OMPC_inclusive:
7254 case OMPC_exclusive:
7255 case OMPC_uses_allocators:
7256 case OMPC_affinity:
7257 case OMPC_bind:
7258 case OMPC_filter:
7259 case OMPC_severity:
7260 case OMPC_message:
7261 continue;
7262 case OMPC_allocator:
7263 case OMPC_flush:
7264 case OMPC_depobj:
7265 case OMPC_threadprivate:
7266 case OMPC_groupprivate:
7267 case OMPC_uniform:
7268 case OMPC_unknown:
7269 case OMPC_unified_address:
7270 case OMPC_unified_shared_memory:
7271 case OMPC_reverse_offload:
7272 case OMPC_dynamic_allocators:
7273 case OMPC_atomic_default_mem_order:
7274 case OMPC_self_maps:
7275 case OMPC_device_type:
7276 case OMPC_match:
7277 case OMPC_when:
7278 case OMPC_at:
7279 default:
7280 llvm_unreachable("Unexpected clause");
7281 }
7282 for (Stmt *CC : C->children()) {
7283 if (CC)
7284 DSAChecker.Visit(S: CC);
7285 }
7286 }
7287 for (const auto &P : DSAChecker.getVarsWithInheritedDSA())
7288 VarsWithInheritedDSA[P.getFirst()] = P.getSecond();
7289 }
7290 for (const auto &P : VarsWithInheritedDSA) {
7291 if (P.getFirst()->isImplicit() || isa<OMPCapturedExprDecl>(Val: P.getFirst()))
7292 continue;
7293 ErrorFound = true;
7294 if (DSAStack->getDefaultDSA() == DSA_none ||
7295 DSAStack->getDefaultDSA() == DSA_private ||
7296 DSAStack->getDefaultDSA() == DSA_firstprivate) {
7297 Diag(Loc: P.second->getExprLoc(), DiagID: diag::err_omp_no_dsa_for_variable)
7298 << P.first << P.second->getSourceRange();
7299 Diag(DSAStack->getDefaultDSALocation(), DiagID: diag::note_omp_default_dsa_none);
7300 } else if (getLangOpts().OpenMP >= 50) {
7301 Diag(Loc: P.second->getExprLoc(),
7302 DiagID: diag::err_omp_defaultmap_no_attr_for_variable)
7303 << P.first << P.second->getSourceRange();
7304 Diag(DSAStack->getDefaultDSALocation(),
7305 DiagID: diag::note_omp_defaultmap_attr_none);
7306 }
7307 }
7308
7309 llvm::SmallVector<OpenMPDirectiveKind, 4> AllowedNameModifiers;
7310 for (OpenMPDirectiveKind D : getLeafConstructsOrSelf(D: Kind)) {
7311 if (isAllowedClauseForDirective(D, C: OMPC_if,
7312 V: getLangOpts().getOpenMPVersion()))
7313 AllowedNameModifiers.push_back(Elt: D);
7314 }
7315 if (!AllowedNameModifiers.empty())
7316 ErrorFound = checkIfClauses(S&: SemaRef, Kind, Clauses, AllowedNameModifiers) ||
7317 ErrorFound;
7318
7319 if (ErrorFound)
7320 return StmtError();
7321
7322 if (!SemaRef.CurContext->isDependentContext() &&
7323 isOpenMPTargetExecutionDirective(DKind: Kind) &&
7324 !(DSAStack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() ||
7325 DSAStack->hasRequiresDeclWithClause<OMPUnifiedAddressClause>() ||
7326 DSAStack->hasRequiresDeclWithClause<OMPReverseOffloadClause>() ||
7327 DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>())) {
7328 // Register target to DSA Stack.
7329 DSAStack->addTargetDirLocation(LocStart: StartLoc);
7330 }
7331
7332 return Res;
7333}
7334
7335SemaOpenMP::DeclGroupPtrTy SemaOpenMP::ActOnOpenMPDeclareSimdDirective(
7336 DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS, Expr *Simdlen,
7337 ArrayRef<Expr *> Uniforms, ArrayRef<Expr *> Aligneds,
7338 ArrayRef<Expr *> Alignments, ArrayRef<Expr *> Linears,
7339 ArrayRef<unsigned> LinModifiers, ArrayRef<Expr *> Steps, SourceRange SR) {
7340 assert(Aligneds.size() == Alignments.size());
7341 assert(Linears.size() == LinModifiers.size());
7342 assert(Linears.size() == Steps.size());
7343 if (!DG || DG.get().isNull())
7344 return DeclGroupPtrTy();
7345
7346 const int SimdId = 0;
7347 if (!DG.get().isSingleDecl()) {
7348 Diag(Loc: SR.getBegin(), DiagID: diag::err_omp_single_decl_in_declare_simd_variant)
7349 << SimdId;
7350 return DG;
7351 }
7352 Decl *ADecl = DG.get().getSingleDecl();
7353 if (auto *FTD = dyn_cast<FunctionTemplateDecl>(Val: ADecl))
7354 ADecl = FTD->getTemplatedDecl();
7355
7356 auto *FD = dyn_cast<FunctionDecl>(Val: ADecl);
7357 if (!FD) {
7358 Diag(Loc: ADecl->getLocation(), DiagID: diag::err_omp_function_expected) << SimdId;
7359 return DeclGroupPtrTy();
7360 }
7361
7362 // OpenMP [2.8.2, declare simd construct, Description]
7363 // The parameter of the simdlen clause must be a constant positive integer
7364 // expression.
7365 ExprResult SL;
7366 if (Simdlen)
7367 SL = VerifyPositiveIntegerConstantInClause(Op: Simdlen, CKind: OMPC_simdlen);
7368 // OpenMP [2.8.2, declare simd construct, Description]
7369 // The special this pointer can be used as if was one of the arguments to the
7370 // function in any of the linear, aligned, or uniform clauses.
7371 // The uniform clause declares one or more arguments to have an invariant
7372 // value for all concurrent invocations of the function in the execution of a
7373 // single SIMD loop.
7374 llvm::DenseMap<const Decl *, const Expr *> UniformedArgs;
7375 const Expr *UniformedLinearThis = nullptr;
7376 for (const Expr *E : Uniforms) {
7377 E = E->IgnoreParenImpCasts();
7378 if (const auto *DRE = dyn_cast<DeclRefExpr>(Val: E))
7379 if (const auto *PVD = dyn_cast<ParmVarDecl>(Val: DRE->getDecl()))
7380 if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
7381 FD->getParamDecl(i: PVD->getFunctionScopeIndex())
7382 ->getCanonicalDecl() == PVD->getCanonicalDecl()) {
7383 UniformedArgs.try_emplace(Key: PVD->getCanonicalDecl(), Args&: E);
7384 continue;
7385 }
7386 if (isa<CXXThisExpr>(Val: E)) {
7387 UniformedLinearThis = E;
7388 continue;
7389 }
7390 Diag(Loc: E->getExprLoc(), DiagID: diag::err_omp_param_or_this_in_clause)
7391 << FD->getDeclName() << (isa<CXXMethodDecl>(Val: ADecl) ? 1 : 0);
7392 }
7393 // OpenMP [2.8.2, declare simd construct, Description]
7394 // The aligned clause declares that the object to which each list item points
7395 // is aligned to the number of bytes expressed in the optional parameter of
7396 // the aligned clause.
7397 // The special this pointer can be used as if was one of the arguments to the
7398 // function in any of the linear, aligned, or uniform clauses.
7399 // The type of list items appearing in the aligned clause must be array,
7400 // pointer, reference to array, or reference to pointer.
7401 llvm::DenseMap<const Decl *, const Expr *> AlignedArgs;
7402 const Expr *AlignedThis = nullptr;
7403 for (const Expr *E : Aligneds) {
7404 E = E->IgnoreParenImpCasts();
7405 if (const auto *DRE = dyn_cast<DeclRefExpr>(Val: E))
7406 if (const auto *PVD = dyn_cast<ParmVarDecl>(Val: DRE->getDecl())) {
7407 const VarDecl *CanonPVD = PVD->getCanonicalDecl();
7408 if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
7409 FD->getParamDecl(i: PVD->getFunctionScopeIndex())
7410 ->getCanonicalDecl() == CanonPVD) {
7411 // OpenMP [2.8.1, simd construct, Restrictions]
7412 // A list-item cannot appear in more than one aligned clause.
7413 auto [It, Inserted] = AlignedArgs.try_emplace(Key: CanonPVD, Args&: E);
7414 if (!Inserted) {
7415 Diag(Loc: E->getExprLoc(), DiagID: diag::err_omp_used_in_clause_twice)
7416 << 1 << getOpenMPClauseNameForDiag(C: OMPC_aligned)
7417 << E->getSourceRange();
7418 Diag(Loc: It->second->getExprLoc(), DiagID: diag::note_omp_explicit_dsa)
7419 << getOpenMPClauseNameForDiag(C: OMPC_aligned);
7420 continue;
7421 }
7422 QualType QTy = PVD->getType()
7423 .getNonReferenceType()
7424 .getUnqualifiedType()
7425 .getCanonicalType();
7426 const Type *Ty = QTy.getTypePtrOrNull();
7427 if (!Ty || (!Ty->isArrayType() && !Ty->isPointerType())) {
7428 Diag(Loc: E->getExprLoc(), DiagID: diag::err_omp_aligned_expected_array_or_ptr)
7429 << QTy << getLangOpts().CPlusPlus << E->getSourceRange();
7430 Diag(Loc: PVD->getLocation(), DiagID: diag::note_previous_decl) << PVD;
7431 }
7432 continue;
7433 }
7434 }
7435 if (isa<CXXThisExpr>(Val: E)) {
7436 if (AlignedThis) {
7437 Diag(Loc: E->getExprLoc(), DiagID: diag::err_omp_used_in_clause_twice)
7438 << 2 << getOpenMPClauseNameForDiag(C: OMPC_aligned)
7439 << E->getSourceRange();
7440 Diag(Loc: AlignedThis->getExprLoc(), DiagID: diag::note_omp_explicit_dsa)
7441 << getOpenMPClauseNameForDiag(C: OMPC_aligned);
7442 }
7443 AlignedThis = E;
7444 continue;
7445 }
7446 Diag(Loc: E->getExprLoc(), DiagID: diag::err_omp_param_or_this_in_clause)
7447 << FD->getDeclName() << (isa<CXXMethodDecl>(Val: ADecl) ? 1 : 0);
7448 }
7449 // The optional parameter of the aligned clause, alignment, must be a constant
7450 // positive integer expression. If no optional parameter is specified,
7451 // implementation-defined default alignments for SIMD instructions on the
7452 // target platforms are assumed.
7453 SmallVector<const Expr *, 4> NewAligns;
7454 for (Expr *E : Alignments) {
7455 ExprResult Align;
7456 if (E)
7457 Align = VerifyPositiveIntegerConstantInClause(Op: E, CKind: OMPC_aligned);
7458 NewAligns.push_back(Elt: Align.get());
7459 }
7460 // OpenMP [2.8.2, declare simd construct, Description]
7461 // The linear clause declares one or more list items to be private to a SIMD
7462 // lane and to have a linear relationship with respect to the iteration space
7463 // of a loop.
7464 // The special this pointer can be used as if was one of the arguments to the
7465 // function in any of the linear, aligned, or uniform clauses.
7466 // When a linear-step expression is specified in a linear clause it must be
7467 // either a constant integer expression or an integer-typed parameter that is
7468 // specified in a uniform clause on the directive.
7469 llvm::DenseMap<const Decl *, const Expr *> LinearArgs;
7470 const bool IsUniformedThis = UniformedLinearThis != nullptr;
7471 auto MI = LinModifiers.begin();
7472 for (const Expr *E : Linears) {
7473 auto LinKind = static_cast<OpenMPLinearClauseKind>(*MI);
7474 ++MI;
7475 E = E->IgnoreParenImpCasts();
7476 if (const auto *DRE = dyn_cast<DeclRefExpr>(Val: E))
7477 if (const auto *PVD = dyn_cast<ParmVarDecl>(Val: DRE->getDecl())) {
7478 const VarDecl *CanonPVD = PVD->getCanonicalDecl();
7479 if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
7480 FD->getParamDecl(i: PVD->getFunctionScopeIndex())
7481 ->getCanonicalDecl() == CanonPVD) {
7482 // OpenMP [2.15.3.7, linear Clause, Restrictions]
7483 // A list-item cannot appear in more than one linear clause.
7484 if (auto It = LinearArgs.find(Val: CanonPVD); It != LinearArgs.end()) {
7485 Diag(Loc: E->getExprLoc(), DiagID: diag::err_omp_wrong_dsa)
7486 << getOpenMPClauseNameForDiag(C: OMPC_linear)
7487 << getOpenMPClauseNameForDiag(C: OMPC_linear)
7488 << E->getSourceRange();
7489 Diag(Loc: It->second->getExprLoc(), DiagID: diag::note_omp_explicit_dsa)
7490 << getOpenMPClauseNameForDiag(C: OMPC_linear);
7491 continue;
7492 }
7493 // Each argument can appear in at most one uniform or linear clause.
7494 if (auto It = UniformedArgs.find(Val: CanonPVD);
7495 It != UniformedArgs.end()) {
7496 Diag(Loc: E->getExprLoc(), DiagID: diag::err_omp_wrong_dsa)
7497 << getOpenMPClauseNameForDiag(C: OMPC_linear)
7498 << getOpenMPClauseNameForDiag(C: OMPC_uniform)
7499 << E->getSourceRange();
7500 Diag(Loc: It->second->getExprLoc(), DiagID: diag::note_omp_explicit_dsa)
7501 << getOpenMPClauseNameForDiag(C: OMPC_uniform);
7502 continue;
7503 }
7504 LinearArgs[CanonPVD] = E;
7505 if (E->isValueDependent() || E->isTypeDependent() ||
7506 E->isInstantiationDependent() ||
7507 E->containsUnexpandedParameterPack())
7508 continue;
7509 (void)CheckOpenMPLinearDecl(D: CanonPVD, ELoc: E->getExprLoc(), LinKind,
7510 Type: PVD->getOriginalType(),
7511 /*IsDeclareSimd=*/true);
7512 continue;
7513 }
7514 }
7515 if (isa<CXXThisExpr>(Val: E)) {
7516 if (UniformedLinearThis) {
7517 Diag(Loc: E->getExprLoc(), DiagID: diag::err_omp_wrong_dsa)
7518 << getOpenMPClauseNameForDiag(C: OMPC_linear)
7519 << getOpenMPClauseNameForDiag(C: IsUniformedThis ? OMPC_uniform
7520 : OMPC_linear)
7521 << E->getSourceRange();
7522 Diag(Loc: UniformedLinearThis->getExprLoc(), DiagID: diag::note_omp_explicit_dsa)
7523 << getOpenMPClauseNameForDiag(C: IsUniformedThis ? OMPC_uniform
7524 : OMPC_linear);
7525 continue;
7526 }
7527 UniformedLinearThis = E;
7528 if (E->isValueDependent() || E->isTypeDependent() ||
7529 E->isInstantiationDependent() || E->containsUnexpandedParameterPack())
7530 continue;
7531 (void)CheckOpenMPLinearDecl(/*D=*/nullptr, ELoc: E->getExprLoc(), LinKind,
7532 Type: E->getType(), /*IsDeclareSimd=*/true);
7533 continue;
7534 }
7535 Diag(Loc: E->getExprLoc(), DiagID: diag::err_omp_param_or_this_in_clause)
7536 << FD->getDeclName() << (isa<CXXMethodDecl>(Val: ADecl) ? 1 : 0);
7537 }
7538 Expr *Step = nullptr;
7539 Expr *NewStep = nullptr;
7540 SmallVector<Expr *, 4> NewSteps;
7541 for (Expr *E : Steps) {
7542 // Skip the same step expression, it was checked already.
7543 if (Step == E || !E) {
7544 NewSteps.push_back(Elt: E ? NewStep : nullptr);
7545 continue;
7546 }
7547 Step = E;
7548 if (const auto *DRE = dyn_cast<DeclRefExpr>(Val: Step))
7549 if (const auto *PVD = dyn_cast<ParmVarDecl>(Val: DRE->getDecl())) {
7550 const VarDecl *CanonPVD = PVD->getCanonicalDecl();
7551 if (UniformedArgs.count(Val: CanonPVD) == 0) {
7552 Diag(Loc: Step->getExprLoc(), DiagID: diag::err_omp_expected_uniform_param)
7553 << Step->getSourceRange();
7554 } else if (E->isValueDependent() || E->isTypeDependent() ||
7555 E->isInstantiationDependent() ||
7556 E->containsUnexpandedParameterPack() ||
7557 CanonPVD->getType()->hasIntegerRepresentation()) {
7558 NewSteps.push_back(Elt: Step);
7559 } else {
7560 Diag(Loc: Step->getExprLoc(), DiagID: diag::err_omp_expected_int_param)
7561 << Step->getSourceRange();
7562 }
7563 continue;
7564 }
7565 NewStep = Step;
7566 if (Step && !Step->isValueDependent() && !Step->isTypeDependent() &&
7567 !Step->isInstantiationDependent() &&
7568 !Step->containsUnexpandedParameterPack()) {
7569 NewStep = PerformOpenMPImplicitIntegerConversion(OpLoc: Step->getExprLoc(), Op: Step)
7570 .get();
7571 if (NewStep)
7572 NewStep = SemaRef
7573 .VerifyIntegerConstantExpression(
7574 E: NewStep, /*FIXME*/ CanFold: AllowFoldKind::Allow)
7575 .get();
7576 }
7577 NewSteps.push_back(Elt: NewStep);
7578 }
7579 auto *NewAttr = OMPDeclareSimdDeclAttr::CreateImplicit(
7580 Ctx&: getASTContext(), BranchState: BS, Simdlen: SL.get(), Uniforms: const_cast<Expr **>(Uniforms.data()),
7581 UniformsSize: Uniforms.size(), Aligneds: const_cast<Expr **>(Aligneds.data()), AlignedsSize: Aligneds.size(),
7582 Alignments: const_cast<Expr **>(NewAligns.data()), AlignmentsSize: NewAligns.size(),
7583 Linears: const_cast<Expr **>(Linears.data()), LinearsSize: Linears.size(),
7584 Modifiers: const_cast<unsigned *>(LinModifiers.data()), ModifiersSize: LinModifiers.size(),
7585 Steps: NewSteps.data(), StepsSize: NewSteps.size(), Range: SR);
7586 ADecl->addAttr(A: NewAttr);
7587 return DG;
7588}
7589
7590StmtResult SemaOpenMP::ActOnOpenMPInformationalDirective(
7591 OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
7592 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
7593 SourceLocation EndLoc) {
7594 assert(isOpenMPInformationalDirective(Kind) &&
7595 "Unexpected directive category");
7596
7597 StmtResult Res = StmtError();
7598
7599 switch (Kind) {
7600 case OMPD_assume:
7601 Res = ActOnOpenMPAssumeDirective(Clauses, AStmt, StartLoc, EndLoc);
7602 break;
7603 default:
7604 llvm_unreachable("Unknown OpenMP directive");
7605 }
7606
7607 return Res;
7608}
7609
7610static void setPrototype(Sema &S, FunctionDecl *FD, FunctionDecl *FDWithProto,
7611 QualType NewType) {
7612 assert(NewType->isFunctionProtoType() &&
7613 "Expected function type with prototype.");
7614 assert(FD->getType()->isFunctionNoProtoType() &&
7615 "Expected function with type with no prototype.");
7616 assert(FDWithProto->getType()->isFunctionProtoType() &&
7617 "Expected function with prototype.");
7618 // Synthesize parameters with the same types.
7619 FD->setType(NewType);
7620 SmallVector<ParmVarDecl *, 16> Params;
7621 for (const ParmVarDecl *P : FDWithProto->parameters()) {
7622 auto *Param = ParmVarDecl::Create(C&: S.getASTContext(), DC: FD, StartLoc: SourceLocation(),
7623 IdLoc: SourceLocation(), Id: nullptr, T: P->getType(),
7624 /*TInfo=*/nullptr, S: SC_None, DefArg: nullptr);
7625 Param->setScopeInfo(scopeDepth: 0, parameterIndex: Params.size());
7626 Param->setImplicit();
7627 Params.push_back(Elt: Param);
7628 }
7629
7630 FD->setParams(Params);
7631}
7632
7633void SemaOpenMP::ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(Decl *D) {
7634 if (D->isInvalidDecl())
7635 return;
7636 FunctionDecl *FD = nullptr;
7637 if (auto *UTemplDecl = dyn_cast<FunctionTemplateDecl>(Val: D))
7638 FD = UTemplDecl->getTemplatedDecl();
7639 else
7640 FD = cast<FunctionDecl>(Val: D);
7641 assert(FD && "Expected a function declaration!");
7642
7643 // If we are instantiating templates we do *not* apply scoped assumptions but
7644 // only global ones. We apply scoped assumption to the template definition
7645 // though.
7646 if (!SemaRef.inTemplateInstantiation()) {
7647 for (OMPAssumeAttr *AA : OMPAssumeScoped)
7648 FD->addAttr(A: AA);
7649 }
7650 for (OMPAssumeAttr *AA : OMPAssumeGlobal)
7651 FD->addAttr(A: AA);
7652}
7653
7654SemaOpenMP::OMPDeclareVariantScope::OMPDeclareVariantScope(OMPTraitInfo &TI)
7655 : TI(&TI), NameSuffix(TI.getMangledName()) {}
7656
7657void SemaOpenMP::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(
7658 Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists,
7659 SmallVectorImpl<FunctionDecl *> &Bases) {
7660 if (!D.getIdentifier())
7661 return;
7662
7663 OMPDeclareVariantScope &DVScope = OMPDeclareVariantScopes.back();
7664
7665 // Template specialization is an extension, check if we do it.
7666 bool IsTemplated = !TemplateParamLists.empty();
7667 if (IsTemplated &&
7668 !DVScope.TI->isExtensionActive(
7669 TP: llvm::omp::TraitProperty::implementation_extension_allow_templates))
7670 return;
7671
7672 const IdentifierInfo *BaseII = D.getIdentifier();
7673 LookupResult Lookup(SemaRef, DeclarationName(BaseII), D.getIdentifierLoc(),
7674 Sema::LookupOrdinaryName);
7675 SemaRef.LookupParsedName(R&: Lookup, S, SS: &D.getCXXScopeSpec(),
7676 /*ObjectType=*/QualType());
7677
7678 TypeSourceInfo *TInfo = SemaRef.GetTypeForDeclarator(D);
7679 QualType FType = TInfo->getType();
7680
7681 bool IsConstexpr =
7682 D.getDeclSpec().getConstexprSpecifier() == ConstexprSpecKind::Constexpr;
7683 bool IsConsteval =
7684 D.getDeclSpec().getConstexprSpecifier() == ConstexprSpecKind::Consteval;
7685
7686 for (auto *Candidate : Lookup) {
7687 auto *CandidateDecl = Candidate->getUnderlyingDecl();
7688 FunctionDecl *UDecl = nullptr;
7689 if (IsTemplated && isa<FunctionTemplateDecl>(Val: CandidateDecl)) {
7690 auto *FTD = cast<FunctionTemplateDecl>(Val: CandidateDecl);
7691 // FIXME: Should this compare the template parameter lists on all levels?
7692 if (SemaRef.Context.isSameTemplateParameterList(
7693 X: FTD->getTemplateParameters(), Y: TemplateParamLists.back()))
7694 UDecl = FTD->getTemplatedDecl();
7695 } else if (!IsTemplated)
7696 UDecl = dyn_cast<FunctionDecl>(Val: CandidateDecl);
7697 if (!UDecl)
7698 continue;
7699
7700 // Don't specialize constexpr/consteval functions with
7701 // non-constexpr/consteval functions.
7702 if (UDecl->isConstexpr() && !IsConstexpr)
7703 continue;
7704 if (UDecl->isConsteval() && !IsConsteval)
7705 continue;
7706
7707 QualType UDeclTy = UDecl->getType();
7708 if (!UDeclTy->isDependentType()) {
7709 QualType NewType = getASTContext().mergeFunctionTypes(
7710 FType, UDeclTy, /*OfBlockPointer=*/false,
7711 /*Unqualified=*/false, /*AllowCXX=*/true);
7712 if (NewType.isNull())
7713 continue;
7714 }
7715
7716 // Found a base!
7717 Bases.push_back(Elt: UDecl);
7718 }
7719
7720 bool UseImplicitBase = !DVScope.TI->isExtensionActive(
7721 TP: llvm::omp::TraitProperty::implementation_extension_disable_implicit_base);
7722 // If no base was found we create a declaration that we use as base.
7723 if (Bases.empty() && UseImplicitBase) {
7724 D.setFunctionDefinitionKind(FunctionDefinitionKind::Declaration);
7725 Decl *BaseD = SemaRef.HandleDeclarator(S, D, TemplateParameterLists: TemplateParamLists);
7726 BaseD->setImplicit(true);
7727 if (auto *BaseTemplD = dyn_cast<FunctionTemplateDecl>(Val: BaseD))
7728 Bases.push_back(Elt: BaseTemplD->getTemplatedDecl());
7729 else
7730 Bases.push_back(Elt: cast<FunctionDecl>(Val: BaseD));
7731 }
7732
7733 std::string MangledName;
7734 MangledName += D.getIdentifier()->getName();
7735 MangledName += getOpenMPVariantManglingSeparatorStr();
7736 MangledName += DVScope.NameSuffix;
7737 IdentifierInfo &VariantII = getASTContext().Idents.get(Name: MangledName);
7738
7739 VariantII.setMangledOpenMPVariantName(true);
7740 D.SetIdentifier(Id: &VariantII, IdLoc: D.getBeginLoc());
7741}
7742
7743void SemaOpenMP::ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(
7744 Decl *D, SmallVectorImpl<FunctionDecl *> &Bases) {
7745 // Do not mark function as is used to prevent its emission if this is the
7746 // only place where it is used.
7747 EnterExpressionEvaluationContext Unevaluated(
7748 SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
7749
7750 FunctionDecl *FD = nullptr;
7751 if (auto *UTemplDecl = dyn_cast<FunctionTemplateDecl>(Val: D))
7752 FD = UTemplDecl->getTemplatedDecl();
7753 else
7754 FD = cast<FunctionDecl>(Val: D);
7755 auto *VariantFuncRef = DeclRefExpr::Create(
7756 Context: getASTContext(), QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: FD,
7757 /*RefersToEnclosingVariableOrCapture=*/false,
7758 /*NameLoc=*/FD->getLocation(), T: FD->getType(), VK: ExprValueKind::VK_PRValue);
7759
7760 OMPDeclareVariantScope &DVScope = OMPDeclareVariantScopes.back();
7761 auto *OMPDeclareVariantA = OMPDeclareVariantAttr::CreateImplicit(
7762 Ctx&: getASTContext(), VariantFuncRef, TraitInfos: DVScope.TI,
7763 /*NothingArgs=*/AdjustArgsNothing: nullptr, /*NothingArgsSize=*/AdjustArgsNothingSize: 0,
7764 /*NeedDevicePtrArgs=*/AdjustArgsNeedDevicePtr: nullptr, /*NeedDevicePtrArgsSize=*/AdjustArgsNeedDevicePtrSize: 0,
7765 /*NeedDeviceAddrArgs=*/AdjustArgsNeedDeviceAddr: nullptr, /*NeedDeviceAddrArgsSize=*/AdjustArgsNeedDeviceAddrSize: 0,
7766 /*AppendArgs=*/nullptr, /*AppendArgsSize=*/0);
7767 for (FunctionDecl *BaseFD : Bases)
7768 BaseFD->addAttr(A: OMPDeclareVariantA);
7769}
7770
7771ExprResult SemaOpenMP::ActOnOpenMPCall(ExprResult Call, Scope *Scope,
7772 SourceLocation LParenLoc,
7773 MultiExprArg ArgExprs,
7774 SourceLocation RParenLoc,
7775 Expr *ExecConfig) {
7776 // The common case is a regular call we do not want to specialize at all. Try
7777 // to make that case fast by bailing early.
7778 CallExpr *CE = dyn_cast<CallExpr>(Val: Call.get());
7779 if (!CE)
7780 return Call;
7781
7782 FunctionDecl *CalleeFnDecl = CE->getDirectCallee();
7783
7784 // Mark indirect calls inside target regions, to allow for insertion of
7785 // __llvm_omp_indirect_call_lookup calls during codegen.
7786 if (!CalleeFnDecl) {
7787 if (isInOpenMPTargetExecutionDirective()) {
7788 Expr *E = CE->getCallee()->IgnoreParenImpCasts();
7789 DeclRefExpr *DRE = nullptr;
7790 while (E) {
7791 if ((DRE = dyn_cast<DeclRefExpr>(Val: E)))
7792 break;
7793 if (auto *ME = dyn_cast<MemberExpr>(Val: E))
7794 E = ME->getBase()->IgnoreParenImpCasts();
7795 else if (auto *ASE = dyn_cast<ArraySubscriptExpr>(Val: E))
7796 E = ASE->getBase()->IgnoreParenImpCasts();
7797 else
7798 break;
7799 }
7800 VarDecl *VD = DRE ? dyn_cast<VarDecl>(Val: DRE->getDecl()) : nullptr;
7801 if (VD && !VD->hasAttr<OMPTargetIndirectCallAttr>()) {
7802 VD->addAttr(A: OMPTargetIndirectCallAttr::CreateImplicit(Ctx&: getASTContext()));
7803 if (ASTMutationListener *ML = getASTContext().getASTMutationListener())
7804 ML->DeclarationMarkedOpenMPIndirectCall(D: VD);
7805 }
7806 }
7807
7808 return Call;
7809 }
7810
7811 if (getLangOpts().OpenMP >= 50 && getLangOpts().OpenMP <= 60 &&
7812 CalleeFnDecl->getIdentifier() &&
7813 CalleeFnDecl->getName().starts_with_insensitive(Prefix: "omp_")) {
7814 // checking for any calls inside an Order region
7815 if (Scope && Scope->isOpenMPOrderClauseScope())
7816 Diag(Loc: LParenLoc, DiagID: diag::err_omp_unexpected_call_to_omp_runtime_api);
7817 }
7818
7819 if (!CalleeFnDecl->hasAttr<OMPDeclareVariantAttr>())
7820 return Call;
7821
7822 ASTContext &Context = getASTContext();
7823 std::function<void(StringRef)> DiagUnknownTrait = [this,
7824 CE](StringRef ISATrait) {
7825 // TODO Track the selector locations in a way that is accessible here to
7826 // improve the diagnostic location.
7827 Diag(Loc: CE->getBeginLoc(), DiagID: diag::warn_unknown_declare_variant_isa_trait)
7828 << ISATrait;
7829 };
7830 TargetOMPContext OMPCtx(Context, std::move(DiagUnknownTrait),
7831 SemaRef.getCurFunctionDecl(),
7832 DSAStack->getConstructTraits(), getOpenMPDeviceNum());
7833
7834 QualType CalleeFnType = CalleeFnDecl->getType();
7835
7836 SmallVector<Expr *, 4> Exprs;
7837 SmallVector<VariantMatchInfo, 4> VMIs;
7838 while (CalleeFnDecl) {
7839 for (OMPDeclareVariantAttr *A :
7840 CalleeFnDecl->specific_attrs<OMPDeclareVariantAttr>()) {
7841 Expr *VariantRef = A->getVariantFuncRef();
7842
7843 VariantMatchInfo VMI;
7844 OMPTraitInfo &TI = A->getTraitInfo();
7845 TI.getAsVariantMatchInfo(ASTCtx&: Context, VMI);
7846 if (!isVariantApplicableInContext(VMI, Ctx: OMPCtx,
7847 /*DeviceSetOnly=*/DeviceOrImplementationSetOnly: false))
7848 continue;
7849
7850 VMIs.push_back(Elt: VMI);
7851 Exprs.push_back(Elt: VariantRef);
7852 }
7853
7854 CalleeFnDecl = CalleeFnDecl->getPreviousDecl();
7855 }
7856
7857 ExprResult NewCall;
7858 do {
7859 int BestIdx = getBestVariantMatchForContext(VMIs, Ctx: OMPCtx);
7860 if (BestIdx < 0)
7861 return Call;
7862 Expr *BestExpr = cast<DeclRefExpr>(Val: Exprs[BestIdx]);
7863 Decl *BestDecl = cast<DeclRefExpr>(Val: BestExpr)->getDecl();
7864
7865 {
7866 // Try to build a (member) call expression for the current best applicable
7867 // variant expression. We allow this to fail in which case we continue
7868 // with the next best variant expression. The fail case is part of the
7869 // implementation defined behavior in the OpenMP standard when it talks
7870 // about what differences in the function prototypes: "Any differences
7871 // that the specific OpenMP context requires in the prototype of the
7872 // variant from the base function prototype are implementation defined."
7873 // This wording is there to allow the specialized variant to have a
7874 // different type than the base function. This is intended and OK but if
7875 // we cannot create a call the difference is not in the "implementation
7876 // defined range" we allow.
7877 Sema::TentativeAnalysisScope Trap(SemaRef);
7878
7879 if (auto *SpecializedMethod = dyn_cast<CXXMethodDecl>(Val: BestDecl)) {
7880 auto *MemberCall = dyn_cast<CXXMemberCallExpr>(Val: CE);
7881 BestExpr = MemberExpr::CreateImplicit(
7882 C: Context, Base: MemberCall->getImplicitObjectArgument(),
7883 /*IsArrow=*/false, MemberDecl: SpecializedMethod, T: Context.BoundMemberTy,
7884 VK: MemberCall->getValueKind(), OK: MemberCall->getObjectKind());
7885 }
7886 NewCall = SemaRef.BuildCallExpr(S: Scope, Fn: BestExpr, LParenLoc, ArgExprs,
7887 RParenLoc, ExecConfig);
7888 if (NewCall.isUsable()) {
7889 if (CallExpr *NCE = dyn_cast<CallExpr>(Val: NewCall.get())) {
7890 FunctionDecl *NewCalleeFnDecl = NCE->getDirectCallee();
7891 QualType NewType = getASTContext().mergeFunctionTypes(
7892 CalleeFnType, NewCalleeFnDecl->getType(),
7893 /*OfBlockPointer=*/false,
7894 /*Unqualified=*/false, /*AllowCXX=*/true);
7895 if (!NewType.isNull())
7896 break;
7897 // Don't use the call if the function type was not compatible.
7898 NewCall = nullptr;
7899 }
7900 }
7901 }
7902
7903 VMIs.erase(CI: VMIs.begin() + BestIdx);
7904 Exprs.erase(CI: Exprs.begin() + BestIdx);
7905 } while (!VMIs.empty());
7906
7907 if (!NewCall.isUsable())
7908 return Call;
7909 return PseudoObjectExpr::Create(Context: getASTContext(), syntactic: CE, semantic: {NewCall.get()}, resultIndex: 0);
7910}
7911
7912std::optional<std::pair<FunctionDecl *, Expr *>>
7913SemaOpenMP::checkOpenMPDeclareVariantFunction(SemaOpenMP::DeclGroupPtrTy DG,
7914 Expr *VariantRef,
7915 OMPTraitInfo &TI,
7916 unsigned NumAppendArgs,
7917 SourceRange SR) {
7918 ASTContext &Context = getASTContext();
7919 if (!DG || DG.get().isNull())
7920 return std::nullopt;
7921
7922 const int VariantId = 1;
7923 // Must be applied only to single decl.
7924 if (!DG.get().isSingleDecl()) {
7925 Diag(Loc: SR.getBegin(), DiagID: diag::err_omp_single_decl_in_declare_simd_variant)
7926 << VariantId << SR;
7927 return std::nullopt;
7928 }
7929 Decl *ADecl = DG.get().getSingleDecl();
7930 if (auto *FTD = dyn_cast<FunctionTemplateDecl>(Val: ADecl))
7931 ADecl = FTD->getTemplatedDecl();
7932
7933 // Decl must be a function.
7934 auto *FD = dyn_cast<FunctionDecl>(Val: ADecl);
7935 if (!FD) {
7936 Diag(Loc: ADecl->getLocation(), DiagID: diag::err_omp_function_expected)
7937 << VariantId << SR;
7938 return std::nullopt;
7939 }
7940
7941 auto &&HasMultiVersionAttributes = [](const FunctionDecl *FD) {
7942 // The 'target' attribute needs to be separately checked because it does
7943 // not always signify a multiversion function declaration.
7944 return FD->isMultiVersion() || FD->hasAttr<TargetAttr>();
7945 };
7946 // OpenMP is not compatible with multiversion function attributes.
7947 if (HasMultiVersionAttributes(FD)) {
7948 Diag(Loc: FD->getLocation(), DiagID: diag::err_omp_declare_variant_incompat_attributes)
7949 << SR;
7950 return std::nullopt;
7951 }
7952
7953 // Allow #pragma omp declare variant only if the function is not used.
7954 if (FD->isUsed(CheckUsedAttr: false))
7955 Diag(Loc: SR.getBegin(), DiagID: diag::warn_omp_declare_variant_after_used)
7956 << FD->getLocation();
7957
7958 // Check if the function was emitted already.
7959 const FunctionDecl *Definition;
7960 if (!FD->isThisDeclarationADefinition() && FD->isDefined(Definition) &&
7961 (getLangOpts().EmitAllDecls || Context.DeclMustBeEmitted(D: Definition)))
7962 Diag(Loc: SR.getBegin(), DiagID: diag::warn_omp_declare_variant_after_emitted)
7963 << FD->getLocation();
7964
7965 // The VariantRef must point to function.
7966 if (!VariantRef) {
7967 Diag(Loc: SR.getBegin(), DiagID: diag::err_omp_function_expected) << VariantId;
7968 return std::nullopt;
7969 }
7970
7971 auto ShouldDelayChecks = [](Expr *&E, bool) {
7972 return E && (E->isTypeDependent() || E->isValueDependent() ||
7973 E->containsUnexpandedParameterPack() ||
7974 E->isInstantiationDependent());
7975 };
7976 // Do not check templates, wait until instantiation.
7977 if (FD->isDependentContext() || ShouldDelayChecks(VariantRef, false) ||
7978 TI.anyScoreOrCondition(Cond: ShouldDelayChecks))
7979 return std::make_pair(x&: FD, y&: VariantRef);
7980
7981 // Deal with non-constant score and user condition expressions.
7982 auto HandleNonConstantScoresAndConditions = [this](Expr *&E,
7983 bool IsScore) -> bool {
7984 if (!E || E->isIntegerConstantExpr(Ctx: getASTContext()))
7985 return false;
7986
7987 if (IsScore) {
7988 // We warn on non-constant scores and pretend they were not present.
7989 Diag(Loc: E->getExprLoc(), DiagID: diag::warn_omp_declare_variant_score_not_constant)
7990 << E;
7991 E = nullptr;
7992 } else {
7993 // We could replace a non-constant user condition with "false" but we
7994 // will soon need to handle these anyway for the dynamic version of
7995 // OpenMP context selectors.
7996 Diag(Loc: E->getExprLoc(),
7997 DiagID: diag::err_omp_declare_variant_user_condition_not_constant)
7998 << E;
7999 }
8000 return true;
8001 };
8002 if (TI.anyScoreOrCondition(Cond: HandleNonConstantScoresAndConditions))
8003 return std::nullopt;
8004
8005 QualType AdjustedFnType = FD->getType();
8006 if (NumAppendArgs) {
8007 const auto *PTy = AdjustedFnType->getAsAdjusted<FunctionProtoType>();
8008 if (!PTy) {
8009 Diag(Loc: FD->getLocation(), DiagID: diag::err_omp_declare_variant_prototype_required)
8010 << SR;
8011 return std::nullopt;
8012 }
8013 // Adjust the function type to account for an extra omp_interop_t for each
8014 // specified in the append_args clause.
8015 const TypeDecl *TD = nullptr;
8016 LookupResult Result(SemaRef, &Context.Idents.get(Name: "omp_interop_t"),
8017 SR.getBegin(), Sema::LookupOrdinaryName);
8018 if (SemaRef.LookupName(R&: Result, S: SemaRef.getCurScope())) {
8019 NamedDecl *ND = Result.getFoundDecl();
8020 TD = dyn_cast_or_null<TypeDecl>(Val: ND);
8021 }
8022 if (!TD) {
8023 Diag(Loc: SR.getBegin(), DiagID: diag::err_omp_interop_type_not_found) << SR;
8024 return std::nullopt;
8025 }
8026 QualType InteropType =
8027 Context.getTypeDeclType(Keyword: ElaboratedTypeKeyword::None,
8028 /*Qualifier=*/std::nullopt, Decl: TD);
8029 if (PTy->isVariadic()) {
8030 Diag(Loc: FD->getLocation(), DiagID: diag::err_omp_append_args_with_varargs) << SR;
8031 return std::nullopt;
8032 }
8033 llvm::SmallVector<QualType, 8> Params;
8034 Params.append(in_start: PTy->param_type_begin(), in_end: PTy->param_type_end());
8035 Params.insert(I: Params.end(), NumToInsert: NumAppendArgs, Elt: InteropType);
8036 AdjustedFnType = Context.getFunctionType(ResultTy: PTy->getReturnType(), Args: Params,
8037 EPI: PTy->getExtProtoInfo());
8038 }
8039
8040 // Convert VariantRef expression to the type of the original function to
8041 // resolve possible conflicts.
8042 ExprResult VariantRefCast = VariantRef;
8043 if (getLangOpts().CPlusPlus) {
8044 QualType FnPtrType;
8045 auto *Method = dyn_cast<CXXMethodDecl>(Val: FD);
8046 if (Method && !Method->isStatic()) {
8047 FnPtrType = Context.getMemberPointerType(
8048 T: AdjustedFnType, /*Qualifier=*/std::nullopt, Cls: Method->getParent());
8049 ExprResult ER;
8050 {
8051 // Build addr_of unary op to correctly handle type checks for member
8052 // functions.
8053 Sema::TentativeAnalysisScope Trap(SemaRef);
8054 ER = SemaRef.CreateBuiltinUnaryOp(OpLoc: VariantRef->getBeginLoc(), Opc: UO_AddrOf,
8055 InputExpr: VariantRef);
8056 }
8057 if (!ER.isUsable()) {
8058 Diag(Loc: VariantRef->getExprLoc(), DiagID: diag::err_omp_function_expected)
8059 << VariantId << VariantRef->getSourceRange();
8060 return std::nullopt;
8061 }
8062 VariantRef = ER.get();
8063 } else {
8064 FnPtrType = Context.getPointerType(T: AdjustedFnType);
8065 }
8066 QualType VarianPtrType = Context.getPointerType(T: VariantRef->getType());
8067 if (VarianPtrType.getUnqualifiedType() != FnPtrType.getUnqualifiedType()) {
8068 ImplicitConversionSequence ICS = SemaRef.TryImplicitConversion(
8069 From: VariantRef, ToType: FnPtrType.getUnqualifiedType(),
8070 /*SuppressUserConversions=*/false, AllowExplicit: Sema::AllowedExplicit::None,
8071 /*InOverloadResolution=*/false,
8072 /*CStyle=*/false,
8073 /*AllowObjCWritebackConversion=*/false);
8074 if (ICS.isFailure()) {
8075 Diag(Loc: VariantRef->getExprLoc(),
8076 DiagID: diag::err_omp_declare_variant_incompat_types)
8077 << VariantRef->getType()
8078 << ((Method && !Method->isStatic()) ? FnPtrType : FD->getType())
8079 << (NumAppendArgs ? 1 : 0) << VariantRef->getSourceRange();
8080 return std::nullopt;
8081 }
8082 VariantRefCast = SemaRef.PerformImplicitConversion(
8083 From: VariantRef, ToType: FnPtrType.getUnqualifiedType(),
8084 Action: AssignmentAction::Converting);
8085 if (!VariantRefCast.isUsable())
8086 return std::nullopt;
8087 }
8088 // Drop previously built artificial addr_of unary op for member functions.
8089 if (Method && !Method->isStatic()) {
8090 Expr *PossibleAddrOfVariantRef = VariantRefCast.get();
8091 if (auto *UO = dyn_cast<UnaryOperator>(
8092 Val: PossibleAddrOfVariantRef->IgnoreImplicit()))
8093 VariantRefCast = UO->getSubExpr();
8094 }
8095 }
8096
8097 ExprResult ER = SemaRef.CheckPlaceholderExpr(E: VariantRefCast.get());
8098 if (!ER.isUsable() ||
8099 !ER.get()->IgnoreParenImpCasts()->getType()->isFunctionType()) {
8100 Diag(Loc: VariantRef->getExprLoc(), DiagID: diag::err_omp_function_expected)
8101 << VariantId << VariantRef->getSourceRange();
8102 return std::nullopt;
8103 }
8104
8105 // The VariantRef must point to function.
8106 auto *DRE = dyn_cast<DeclRefExpr>(Val: ER.get()->IgnoreParenImpCasts());
8107 if (!DRE) {
8108 Diag(Loc: VariantRef->getExprLoc(), DiagID: diag::err_omp_function_expected)
8109 << VariantId << VariantRef->getSourceRange();
8110 return std::nullopt;
8111 }
8112 auto *NewFD = dyn_cast_or_null<FunctionDecl>(Val: DRE->getDecl());
8113 if (!NewFD) {
8114 Diag(Loc: VariantRef->getExprLoc(), DiagID: diag::err_omp_function_expected)
8115 << VariantId << VariantRef->getSourceRange();
8116 return std::nullopt;
8117 }
8118
8119 if (FD->getCanonicalDecl() == NewFD->getCanonicalDecl()) {
8120 Diag(Loc: VariantRef->getExprLoc(),
8121 DiagID: diag::err_omp_declare_variant_same_base_function)
8122 << VariantRef->getSourceRange();
8123 return std::nullopt;
8124 }
8125
8126 // Check if function types are compatible in C.
8127 if (!getLangOpts().CPlusPlus) {
8128 QualType NewType =
8129 Context.mergeFunctionTypes(AdjustedFnType, NewFD->getType());
8130 if (NewType.isNull()) {
8131 Diag(Loc: VariantRef->getExprLoc(),
8132 DiagID: diag::err_omp_declare_variant_incompat_types)
8133 << NewFD->getType() << FD->getType() << (NumAppendArgs ? 1 : 0)
8134 << VariantRef->getSourceRange();
8135 return std::nullopt;
8136 }
8137 if (NewType->isFunctionProtoType()) {
8138 if (FD->getType()->isFunctionNoProtoType())
8139 setPrototype(S&: SemaRef, FD, FDWithProto: NewFD, NewType);
8140 else if (NewFD->getType()->isFunctionNoProtoType())
8141 setPrototype(S&: SemaRef, FD: NewFD, FDWithProto: FD, NewType);
8142 }
8143 }
8144
8145 // Check if variant function is not marked with declare variant directive.
8146 if (NewFD->hasAttrs() && NewFD->hasAttr<OMPDeclareVariantAttr>()) {
8147 Diag(Loc: VariantRef->getExprLoc(),
8148 DiagID: diag::warn_omp_declare_variant_marked_as_declare_variant)
8149 << VariantRef->getSourceRange();
8150 SourceRange SR =
8151 NewFD->specific_attr_begin<OMPDeclareVariantAttr>()->getRange();
8152 Diag(Loc: SR.getBegin(), DiagID: diag::note_omp_marked_declare_variant_here) << SR;
8153 return std::nullopt;
8154 }
8155
8156 enum DoesntSupport {
8157 VirtFuncs = 1,
8158 Constructors = 3,
8159 Destructors = 4,
8160 DeletedFuncs = 5,
8161 DefaultedFuncs = 6,
8162 ConstexprFuncs = 7,
8163 ConstevalFuncs = 8,
8164 };
8165 if (const auto *CXXFD = dyn_cast<CXXMethodDecl>(Val: FD)) {
8166 if (CXXFD->isVirtual()) {
8167 Diag(Loc: FD->getLocation(), DiagID: diag::err_omp_declare_variant_doesnt_support)
8168 << VirtFuncs;
8169 return std::nullopt;
8170 }
8171
8172 if (isa<CXXConstructorDecl>(Val: FD)) {
8173 Diag(Loc: FD->getLocation(), DiagID: diag::err_omp_declare_variant_doesnt_support)
8174 << Constructors;
8175 return std::nullopt;
8176 }
8177
8178 if (isa<CXXDestructorDecl>(Val: FD)) {
8179 Diag(Loc: FD->getLocation(), DiagID: diag::err_omp_declare_variant_doesnt_support)
8180 << Destructors;
8181 return std::nullopt;
8182 }
8183 }
8184
8185 if (FD->isDeleted()) {
8186 Diag(Loc: FD->getLocation(), DiagID: diag::err_omp_declare_variant_doesnt_support)
8187 << DeletedFuncs;
8188 return std::nullopt;
8189 }
8190
8191 if (FD->isDefaulted()) {
8192 Diag(Loc: FD->getLocation(), DiagID: diag::err_omp_declare_variant_doesnt_support)
8193 << DefaultedFuncs;
8194 return std::nullopt;
8195 }
8196
8197 if (FD->isConstexpr()) {
8198 Diag(Loc: FD->getLocation(), DiagID: diag::err_omp_declare_variant_doesnt_support)
8199 << (NewFD->isConsteval() ? ConstevalFuncs : ConstexprFuncs);
8200 return std::nullopt;
8201 }
8202
8203 // Check general compatibility.
8204 if (SemaRef.areMultiversionVariantFunctionsCompatible(
8205 OldFD: FD, NewFD, NoProtoDiagID: PartialDiagnostic::NullDiagnostic(),
8206 NoteCausedDiagIDAt: PartialDiagnosticAt(SourceLocation(),
8207 PartialDiagnostic::NullDiagnostic()),
8208 NoSupportDiagIDAt: PartialDiagnosticAt(
8209 VariantRef->getExprLoc(),
8210 SemaRef.PDiag(DiagID: diag::err_omp_declare_variant_doesnt_support)),
8211 DiffDiagIDAt: PartialDiagnosticAt(VariantRef->getExprLoc(),
8212 SemaRef.PDiag(DiagID: diag::err_omp_declare_variant_diff)
8213 << FD->getLocation()),
8214 /*TemplatesSupported=*/true, /*ConstexprSupported=*/false,
8215 /*CLinkageMayDiffer=*/true))
8216 return std::nullopt;
8217 return std::make_pair(x&: FD, y: cast<Expr>(Val: DRE));
8218}
8219
8220/// Validate prefer_type fr() and attr() arguments in an OMPInteropInfo.
8221/// fr() must be a string literal or constant integer expression.
8222/// attr() must be a string literal starting with "ompx_" and containing no
8223/// commas. Returns true if valid; emits diagnostic and returns false on first
8224/// error.
8225static bool checkPreferTypeArgs(SemaOpenMP &S, const OMPInteropInfo &Info) {
8226 auto isDependent = [](const Expr *E) {
8227 return E->isValueDependent() || E->isTypeDependent() ||
8228 E->isInstantiationDependent() ||
8229 E->containsUnexpandedParameterPack();
8230 };
8231 for (const OMPInteropPref &P : Info.Prefs) {
8232 const Expr *E = P.Fr;
8233 if (!E) {
8234 assert(Info.HasPreferAttrs && "null Fr requires OMP 6.0 syntax");
8235 } else if (!isDependent(E)) {
8236 if (!E->isIntegerConstantExpr(Ctx: S.getASTContext()) &&
8237 !isa<StringLiteral>(Val: E)) {
8238 S.Diag(Loc: E->getExprLoc(), DiagID: diag::err_omp_interop_prefer_type);
8239 return false;
8240 }
8241 }
8242 for (const Expr *A : P.Attrs) {
8243 if (isDependent(A))
8244 continue;
8245 const auto *SL = dyn_cast<StringLiteral>(Val: A);
8246 if (!SL) {
8247 S.Diag(Loc: A->getExprLoc(), DiagID: diag::err_omp_interop_attr_not_string);
8248 return false;
8249 }
8250 StringRef Str = SL->getString();
8251 if (!Str.starts_with(Prefix: "ompx_")) {
8252 S.Diag(Loc: A->getExprLoc(), DiagID: diag::err_omp_interop_attr_missing_ompx_prefix)
8253 << Str;
8254 return false;
8255 }
8256 if (Str.contains(C: ',')) {
8257 S.Diag(Loc: A->getExprLoc(), DiagID: diag::err_omp_interop_attr_contains_comma)
8258 << Str;
8259 return false;
8260 }
8261 }
8262 }
8263 return true;
8264}
8265
8266void SemaOpenMP::ActOnOpenMPDeclareVariantDirective(
8267 FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI,
8268 ArrayRef<Expr *> AdjustArgsNothing,
8269 ArrayRef<Expr *> AdjustArgsNeedDevicePtr,
8270 ArrayRef<Expr *> AdjustArgsNeedDeviceAddr,
8271 ArrayRef<OMPInteropInfo> AppendArgs, SourceLocation AdjustArgsLoc,
8272 SourceLocation AppendArgsLoc, SourceRange SR) {
8273
8274 // OpenMP 5.1 [2.3.5, declare variant directive, Restrictions]
8275 // An adjust_args clause or append_args clause can only be specified if the
8276 // dispatch selector of the construct selector set appears in the match
8277 // clause.
8278
8279 SmallVector<Expr *, 8> AllAdjustArgs;
8280 llvm::append_range(C&: AllAdjustArgs, R&: AdjustArgsNothing);
8281 llvm::append_range(C&: AllAdjustArgs, R&: AdjustArgsNeedDevicePtr);
8282 llvm::append_range(C&: AllAdjustArgs, R&: AdjustArgsNeedDeviceAddr);
8283
8284 if (!AllAdjustArgs.empty() || !AppendArgs.empty()) {
8285 VariantMatchInfo VMI;
8286 TI.getAsVariantMatchInfo(ASTCtx&: getASTContext(), VMI);
8287 if (!llvm::is_contained(
8288 Range&: VMI.ConstructTraits,
8289 Element: llvm::omp::TraitProperty::construct_dispatch_dispatch)) {
8290 if (!AllAdjustArgs.empty())
8291 Diag(Loc: AdjustArgsLoc, DiagID: diag::err_omp_clause_requires_dispatch_construct)
8292 << getOpenMPClauseNameForDiag(C: OMPC_adjust_args);
8293 if (!AppendArgs.empty())
8294 Diag(Loc: AppendArgsLoc, DiagID: diag::err_omp_clause_requires_dispatch_construct)
8295 << getOpenMPClauseNameForDiag(C: OMPC_append_args);
8296 return;
8297 }
8298 }
8299
8300 // OpenMP 5.1 [2.3.5, declare variant directive, Restrictions]
8301 // Each argument can only appear in a single adjust_args clause for each
8302 // declare variant directive.
8303 llvm::SmallPtrSet<const VarDecl *, 4> AdjustVars;
8304
8305 for (Expr *E : AllAdjustArgs) {
8306 E = E->IgnoreParenImpCasts();
8307 if (const auto *DRE = dyn_cast<DeclRefExpr>(Val: E)) {
8308 if (const auto *PVD = dyn_cast<ParmVarDecl>(Val: DRE->getDecl())) {
8309 const VarDecl *CanonPVD = PVD->getCanonicalDecl();
8310 if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
8311 FD->getParamDecl(i: PVD->getFunctionScopeIndex())
8312 ->getCanonicalDecl() == CanonPVD) {
8313 // It's a parameter of the function, check duplicates.
8314 if (!AdjustVars.insert(Ptr: CanonPVD).second) {
8315 Diag(Loc: DRE->getLocation(), DiagID: diag::err_omp_adjust_arg_multiple_clauses)
8316 << PVD;
8317 return;
8318 }
8319 continue;
8320 }
8321 }
8322 }
8323 // Anything that is not a function parameter is an error.
8324 Diag(Loc: E->getExprLoc(), DiagID: diag::err_omp_param_or_this_in_clause) << FD << 0;
8325 return;
8326 }
8327
8328 // OpenMP 6.0 [9.6.2 (page 332, line 31-33, adjust_args clause, Restrictions]
8329 // If the `need_device_addr` adjust-op modifier is present, each list item
8330 // that appears in the clause must refer to an argument in the declaration of
8331 // the function variant that has a reference type
8332 if (getLangOpts().OpenMP >= 60) {
8333 for (Expr *E : AdjustArgsNeedDeviceAddr) {
8334 E = E->IgnoreParenImpCasts();
8335 if (const auto *DRE = dyn_cast<DeclRefExpr>(Val: E)) {
8336 if (const auto *VD = dyn_cast<VarDecl>(Val: DRE->getDecl())) {
8337 if (!VD->getType()->isReferenceType())
8338 Diag(Loc: E->getExprLoc(),
8339 DiagID: diag::err_omp_non_by_ref_need_device_addr_modifier_argument);
8340 }
8341 }
8342 }
8343 }
8344
8345 // OpenMP 6.0 [16.1.3] Check prefer_type fr()/attr() arguments in
8346 // append_args.
8347 for (const OMPInteropInfo &Info : AppendArgs) {
8348 if (!checkPreferTypeArgs(S&: *this, Info))
8349 return;
8350 }
8351
8352 auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit(
8353 Ctx&: getASTContext(), VariantFuncRef: VariantRef, TraitInfos: &TI,
8354 AdjustArgsNothing: const_cast<Expr **>(AdjustArgsNothing.data()), AdjustArgsNothingSize: AdjustArgsNothing.size(),
8355 AdjustArgsNeedDevicePtr: const_cast<Expr **>(AdjustArgsNeedDevicePtr.data()),
8356 AdjustArgsNeedDevicePtrSize: AdjustArgsNeedDevicePtr.size(),
8357 AdjustArgsNeedDeviceAddr: const_cast<Expr **>(AdjustArgsNeedDeviceAddr.data()),
8358 AdjustArgsNeedDeviceAddrSize: AdjustArgsNeedDeviceAddr.size(),
8359 AppendArgs: const_cast<OMPInteropInfo *>(AppendArgs.data()), AppendArgsSize: AppendArgs.size(), Range: SR);
8360 FD->addAttr(A: NewAttr);
8361}
8362
8363static CapturedStmt *
8364setBranchProtectedScope(Sema &SemaRef, OpenMPDirectiveKind DKind, Stmt *AStmt) {
8365 auto *CS = dyn_cast<CapturedStmt>(Val: AStmt);
8366 assert(CS && "Captured statement expected");
8367 // 1.2.2 OpenMP Language Terminology
8368 // Structured block - An executable statement with a single entry at the
8369 // top and a single exit at the bottom.
8370 // The point of exit cannot be a branch out of the structured block.
8371 // longjmp() and throw() must not violate the entry/exit criteria.
8372 CS->getCapturedDecl()->setNothrow();
8373
8374 for (int ThisCaptureLevel = SemaRef.OpenMP().getOpenMPCaptureLevels(DKind);
8375 ThisCaptureLevel > 1; --ThisCaptureLevel) {
8376 CS = cast<CapturedStmt>(Val: CS->getCapturedStmt());
8377 // 1.2.2 OpenMP Language Terminology
8378 // Structured block - An executable statement with a single entry at the
8379 // top and a single exit at the bottom.
8380 // The point of exit cannot be a branch out of the structured block.
8381 // longjmp() and throw() must not violate the entry/exit criteria.
8382 CS->getCapturedDecl()->setNothrow();
8383 }
8384 SemaRef.setFunctionHasBranchProtectedScope();
8385 return CS;
8386}
8387
8388StmtResult
8389SemaOpenMP::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
8390 Stmt *AStmt, SourceLocation StartLoc,
8391 SourceLocation EndLoc) {
8392 if (!AStmt)
8393 return StmtError();
8394
8395 // Check for conflicting capture kinds on structured bindings.
8396 if (checkClausesForDecompositionConflicts(SemaRef, DKind: OMPD_parallel, Clauses,
8397 Body: AStmt))
8398 return StmtError();
8399
8400 setBranchProtectedScope(SemaRef, DKind: OMPD_parallel, AStmt);
8401
8402 return OMPParallelDirective::Create(
8403 C: getASTContext(), StartLoc, EndLoc, Clauses, AssociatedStmt: AStmt,
8404 DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
8405}
8406
8407namespace {
8408/// Iteration space of a single for loop.
8409struct LoopIterationSpace final {
8410 /// True if the condition operator is the strict compare operator (<, > or
8411 /// !=).
8412 bool IsStrictCompare = false;
8413 /// Condition of the loop.
8414 Expr *PreCond = nullptr;
8415 /// This expression calculates the number of iterations in the loop.
8416 /// It is always possible to calculate it before starting the loop.
8417 Expr *NumIterations = nullptr;
8418 /// The loop counter variable.
8419 Expr *CounterVar = nullptr;
8420 /// Private loop counter variable.
8421 Expr *PrivateCounterVar = nullptr;
8422 /// This is initializer for the initial value of #CounterVar.
8423 Expr *CounterInit = nullptr;
8424 /// This is step for the #CounterVar used to generate its update:
8425 /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration.
8426 Expr *CounterStep = nullptr;
8427 /// Should step be subtracted?
8428 bool Subtract = false;
8429 /// Source range of the loop init.
8430 SourceRange InitSrcRange;
8431 /// Source range of the loop condition.
8432 SourceRange CondSrcRange;
8433 /// Source range of the loop increment.
8434 SourceRange IncSrcRange;
8435 /// Minimum value that can have the loop control variable. Used to support
8436 /// non-rectangular loops. Applied only for LCV with the non-iterator types,
8437 /// since only such variables can be used in non-loop invariant expressions.
8438 Expr *MinValue = nullptr;
8439 /// Maximum value that can have the loop control variable. Used to support
8440 /// non-rectangular loops. Applied only for LCV with the non-iterator type,
8441 /// since only such variables can be used in non-loop invariant expressions.
8442 Expr *MaxValue = nullptr;
8443 /// true, if the lower bound depends on the outer loop control var.
8444 bool IsNonRectangularLB = false;
8445 /// true, if the upper bound depends on the outer loop control var.
8446 bool IsNonRectangularUB = false;
8447 /// Index of the loop this loop depends on and forms non-rectangular loop
8448 /// nest.
8449 unsigned LoopDependentIdx = 0;
8450 /// Final condition for the non-rectangular loop nest support. It is used to
8451 /// check that the number of iterations for this particular counter must be
8452 /// finished.
8453 Expr *FinalCondition = nullptr;
8454};
8455
8456/// Scan an AST subtree, checking that no decls in the CollapsedLoopVarDecls
8457/// set are referenced. Used for verifying loop nest structure before
8458/// performing a loop collapse operation.
8459class ForSubExprChecker : public DynamicRecursiveASTVisitor {
8460 const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopVarDecls;
8461 VarDecl *ForbiddenVar = nullptr;
8462 SourceRange ErrLoc;
8463
8464public:
8465 explicit ForSubExprChecker(
8466 const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopVarDecls)
8467 : CollapsedLoopVarDecls(CollapsedLoopVarDecls) {
8468 // We want to visit implicit code, i.e. synthetic initialisation statements
8469 // created during range-for lowering.
8470 ShouldVisitImplicitCode = true;
8471 }
8472
8473 bool VisitDeclRefExpr(DeclRefExpr *E) override {
8474 ValueDecl *VD = E->getDecl();
8475 if (!isa<VarDecl, BindingDecl>(Val: VD))
8476 return true;
8477 VarDecl *V = VD->getPotentiallyDecomposedVarDecl();
8478 if (V->getType()->isReferenceType()) {
8479 VarDecl *VD = V->getDefinition();
8480 if (VD && VD->hasInit()) {
8481 Expr *I = VD->getInit();
8482 DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Val: I);
8483 if (!DRE)
8484 return true;
8485 V = DRE->getDecl()->getPotentiallyDecomposedVarDecl();
8486 }
8487 }
8488 Decl *Canon = V->getCanonicalDecl();
8489 if (CollapsedLoopVarDecls.contains(Ptr: Canon)) {
8490 ForbiddenVar = V;
8491 ErrLoc = E->getSourceRange();
8492 return false;
8493 }
8494
8495 return true;
8496 }
8497
8498 VarDecl *getForbiddenVar() const { return ForbiddenVar; }
8499 SourceRange getErrRange() const { return ErrLoc; }
8500};
8501
8502/// Helper class for checking canonical form of the OpenMP loops and
8503/// extracting iteration space of each loop in the loop nest, that will be used
8504/// for IR generation.
8505class OpenMPIterationSpaceChecker {
8506 /// Reference to Sema.
8507 Sema &SemaRef;
8508 /// Does the loop associated directive support non-rectangular loops?
8509 bool SupportsNonRectangular;
8510 /// Data-sharing stack.
8511 DSAStackTy &Stack;
8512 /// A location for diagnostics (when there is no some better location).
8513 SourceLocation DefaultLoc;
8514 /// A location for diagnostics (when increment is not compatible).
8515 SourceLocation ConditionLoc;
8516 /// The set of variables declared within the (to be collapsed) loop nest.
8517 const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopVarDecls;
8518 /// The set of induction variables from outer collapsed loops.
8519 llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopInductionVars;
8520 /// A source location for referring to loop init later.
8521 SourceRange InitSrcRange;
8522 /// A source location for referring to condition later.
8523 SourceRange ConditionSrcRange;
8524 /// A source location for referring to increment later.
8525 SourceRange IncrementSrcRange;
8526 /// Loop variable.
8527 ValueDecl *LCDecl = nullptr;
8528 /// Reference to loop variable.
8529 Expr *LCRef = nullptr;
8530 /// Lower bound (initializer for the var).
8531 Expr *LB = nullptr;
8532 /// Upper bound.
8533 Expr *UB = nullptr;
8534 /// Loop step (increment).
8535 Expr *Step = nullptr;
8536 /// This flag is true when condition is one of:
8537 /// Var < UB
8538 /// Var <= UB
8539 /// UB > Var
8540 /// UB >= Var
8541 /// This will have no value when the condition is !=
8542 std::optional<bool> TestIsLessOp;
8543 /// This flag is true when condition is strict ( < or > ).
8544 bool TestIsStrictOp = false;
8545 /// This flag is true when step is subtracted on each iteration.
8546 bool SubtractStep = false;
8547 /// The outer loop counter this loop depends on (if any).
8548 const ValueDecl *DepDecl = nullptr;
8549 /// Contains number of loop (starts from 1) on which loop counter init
8550 /// expression of this loop depends on.
8551 std::optional<unsigned> InitDependOnLC;
8552 /// Contains number of loop (starts from 1) on which loop counter condition
8553 /// expression of this loop depends on.
8554 std::optional<unsigned> CondDependOnLC;
8555 /// Checks if the provide statement depends on the loop counter.
8556 std::optional<unsigned> doesDependOnLoopCounter(const Stmt *S,
8557 bool IsInitializer);
8558 /// Original condition required for checking of the exit condition for
8559 /// non-rectangular loop.
8560 Expr *Condition = nullptr;
8561
8562public:
8563 OpenMPIterationSpaceChecker(
8564 Sema &SemaRef, bool SupportsNonRectangular, DSAStackTy &Stack,
8565 SourceLocation DefaultLoc,
8566 const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopDecls,
8567 llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopInductionVars)
8568 : SemaRef(SemaRef), SupportsNonRectangular(SupportsNonRectangular),
8569 Stack(Stack), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc),
8570 CollapsedLoopVarDecls(CollapsedLoopDecls),
8571 CollapsedLoopInductionVars(CollapsedLoopInductionVars) {}
8572 /// Check init-expr for canonical loop form and save loop counter
8573 /// variable - #Var and its initialization value - #LB.
8574 bool checkAndSetInit(Stmt *S, bool EmitDiags = true);
8575 /// Check test-expr for canonical form, save upper-bound (#UB), flags
8576 /// for less/greater and for strict/non-strict comparison.
8577 bool checkAndSetCond(Expr *S);
8578 /// Check incr-expr for canonical loop form and return true if it
8579 /// does not conform, otherwise save loop step (#Step).
8580 bool checkAndSetInc(Expr *S);
8581 /// Return the loop counter variable.
8582 ValueDecl *getLoopDecl() const { return LCDecl; }
8583 /// Return the reference expression to loop counter variable.
8584 Expr *getLoopDeclRefExpr() const { return LCRef; }
8585 /// Source range of the loop init.
8586 SourceRange getInitSrcRange() const { return InitSrcRange; }
8587 /// Source range of the loop condition.
8588 SourceRange getConditionSrcRange() const { return ConditionSrcRange; }
8589 /// Source range of the loop increment.
8590 SourceRange getIncrementSrcRange() const { return IncrementSrcRange; }
8591 /// True if the step should be subtracted.
8592 bool shouldSubtractStep() const { return SubtractStep; }
8593 /// True, if the compare operator is strict (<, > or !=).
8594 bool isStrictTestOp() const { return TestIsStrictOp; }
8595 /// Build the expression to calculate the number of iterations.
8596 Expr *buildNumIterations(
8597 Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType,
8598 llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const;
8599 /// Build the precondition expression for the loops.
8600 Expr *
8601 buildPreCond(Scope *S, Expr *Cond,
8602 llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const;
8603 /// Build reference expression to the counter be used for codegen.
8604 DeclRefExpr *
8605 buildCounterVar(llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
8606 DSAStackTy &DSA) const;
8607 /// Build reference expression to the private counter be used for
8608 /// codegen.
8609 Expr *buildPrivateCounterVar() const;
8610 /// Build initialization of the counter be used for codegen.
8611 Expr *buildCounterInit() const;
8612 /// Build step of the counter be used for codegen.
8613 Expr *buildCounterStep() const;
8614 /// Build loop data with counter value for depend clauses in ordered
8615 /// directives.
8616 Expr *
8617 buildOrderedLoopData(Scope *S, Expr *Counter,
8618 llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
8619 SourceLocation Loc, Expr *Inc = nullptr,
8620 OverloadedOperatorKind OOK = OO_Amp);
8621 /// Builds the minimum value for the loop counter.
8622 std::pair<Expr *, Expr *> buildMinMaxValues(
8623 Scope *S, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const;
8624 /// Builds final condition for the non-rectangular loops.
8625 Expr *buildFinalCondition(Scope *S) const;
8626 /// Return true if any expression is dependent.
8627 bool dependent() const;
8628 /// Returns true if the initializer forms non-rectangular loop.
8629 bool doesInitDependOnLC() const { return InitDependOnLC.has_value(); }
8630 /// Returns true if the condition forms non-rectangular loop.
8631 bool doesCondDependOnLC() const { return CondDependOnLC.has_value(); }
8632 /// Returns index of the loop we depend on (starting from 1), or 0 otherwise.
8633 unsigned getLoopDependentIdx() const {
8634 return InitDependOnLC.value_or(u: CondDependOnLC.value_or(u: 0));
8635 }
8636
8637private:
8638 /// Check the right-hand side of an assignment in the increment
8639 /// expression.
8640 bool checkAndSetIncRHS(Expr *RHS);
8641 /// Helper to set loop counter variable and its initializer.
8642 bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB,
8643 bool EmitDiags);
8644 /// Helper to set upper bound.
8645 bool setUB(Expr *NewUB, std::optional<bool> LessOp, bool StrictOp,
8646 SourceRange SR, SourceLocation SL);
8647 /// Helper to set loop increment.
8648 bool setStep(Expr *NewStep, bool Subtract);
8649 /// Diagnose a statement expression in a bound of a non-rectangular loop.
8650 bool checkNonRectangularBound(const Expr *E, bool IsInitializer) const;
8651};
8652
8653bool OpenMPIterationSpaceChecker::dependent() const {
8654 if (!LCDecl) {
8655 assert(!LB && !UB && !Step);
8656 return false;
8657 }
8658 return LCDecl->getType()->isDependentType() ||
8659 (LB && LB->isValueDependent()) || (UB && UB->isValueDependent()) ||
8660 (Step && Step->isValueDependent());
8661}
8662
8663/// Find a statement expression in \p E.
8664static const StmtExpr *findStmtExpr(const Expr *E) {
8665 SmallVector<const Stmt *, 8> Worklist{E};
8666 while (!Worklist.empty()) {
8667 const Stmt *S = Worklist.pop_back_val();
8668 if (!S)
8669 continue;
8670 if (const auto *SE = dyn_cast<StmtExpr>(Val: S))
8671 return SE;
8672 llvm::append_range(C&: Worklist, R: S->children());
8673 }
8674 return nullptr;
8675}
8676
8677bool OpenMPIterationSpaceChecker::checkNonRectangularBound(
8678 const Expr *E, bool IsInitializer) const {
8679 // Such a bound is emitted at every use, its declarations cannot be.
8680 const StmtExpr *SE = findStmtExpr(E);
8681 if (!SE)
8682 return false;
8683 SemaRef.Diag(Loc: SE->getBeginLoc(),
8684 DiagID: diag::err_omp_stmt_expr_in_non_rectangular_loop)
8685 << (IsInitializer ? 0 : 1);
8686 return true;
8687}
8688
8689bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl,
8690 Expr *NewLCRefExpr,
8691 Expr *NewLB, bool EmitDiags) {
8692 // State consistency checking to ensure correct usage.
8693 assert(LCDecl == nullptr && LB == nullptr && LCRef == nullptr &&
8694 UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp);
8695 if (!NewLCDecl || !NewLB || NewLB->containsErrors())
8696 return true;
8697 LCDecl = getCanonicalDecl(D: NewLCDecl);
8698 LCRef = NewLCRefExpr;
8699 if (auto *CE = dyn_cast_or_null<CXXConstructExpr>(Val: NewLB))
8700 if (const CXXConstructorDecl *Ctor = CE->getConstructor())
8701 if ((Ctor->isCopyOrMoveConstructor() ||
8702 Ctor->isConvertingConstructor(/*AllowExplicit=*/false)) &&
8703 CE->getNumArgs() > 0 && CE->getArg(Arg: 0) != nullptr)
8704 NewLB = CE->getArg(Arg: 0)->IgnoreParenImpCasts();
8705 LB = NewLB;
8706 if (EmitDiags) {
8707 InitDependOnLC = doesDependOnLoopCounter(S: LB, /*IsInitializer=*/true);
8708 if (InitDependOnLC && checkNonRectangularBound(E: LB, /*IsInitializer=*/true))
8709 return true;
8710 }
8711 return false;
8712}
8713
8714bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, std::optional<bool> LessOp,
8715 bool StrictOp, SourceRange SR,
8716 SourceLocation SL) {
8717 // State consistency checking to ensure correct usage.
8718 assert(LCDecl != nullptr && LB != nullptr && UB == nullptr &&
8719 Step == nullptr && !TestIsLessOp && !TestIsStrictOp);
8720 if (!NewUB || NewUB->containsErrors())
8721 return true;
8722 UB = NewUB;
8723 if (LessOp)
8724 TestIsLessOp = LessOp;
8725 TestIsStrictOp = StrictOp;
8726 ConditionSrcRange = SR;
8727 ConditionLoc = SL;
8728 CondDependOnLC = doesDependOnLoopCounter(S: UB, /*IsInitializer=*/false);
8729 // The condition is also emitted as the body guard of a non-rectangular loop.
8730 if ((InitDependOnLC || CondDependOnLC) &&
8731 checkNonRectangularBound(E: UB, /*IsInitializer=*/false))
8732 return true;
8733 return false;
8734}
8735
8736bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) {
8737 // State consistency checking to ensure correct usage.
8738 assert(LCDecl != nullptr && LB != nullptr && Step == nullptr);
8739 if (!NewStep || NewStep->containsErrors())
8740 return true;
8741 if (!NewStep->isValueDependent()) {
8742 // Check that the step is integer expression.
8743 SourceLocation StepLoc = NewStep->getBeginLoc();
8744 ExprResult Val = SemaRef.OpenMP().PerformOpenMPImplicitIntegerConversion(
8745 OpLoc: StepLoc, Op: getExprAsWritten(E: NewStep));
8746 if (Val.isInvalid())
8747 return true;
8748 NewStep = Val.get();
8749
8750 // OpenMP [2.6, Canonical Loop Form, Restrictions]
8751 // If test-expr is of form var relational-op b and relational-op is < or
8752 // <= then incr-expr must cause var to increase on each iteration of the
8753 // loop. If test-expr is of form var relational-op b and relational-op is
8754 // > or >= then incr-expr must cause var to decrease on each iteration of
8755 // the loop.
8756 // If test-expr is of form b relational-op var and relational-op is < or
8757 // <= then incr-expr must cause var to decrease on each iteration of the
8758 // loop. If test-expr is of form b relational-op var and relational-op is
8759 // > or >= then incr-expr must cause var to increase on each iteration of
8760 // the loop.
8761 std::optional<llvm::APSInt> Result =
8762 NewStep->getIntegerConstantExpr(Ctx: SemaRef.Context);
8763 bool IsUnsigned = !NewStep->getType()->hasSignedIntegerRepresentation();
8764 bool IsConstNeg =
8765 Result && Result->isSigned() && (Subtract != Result->isNegative());
8766 bool IsConstPos =
8767 Result && Result->isSigned() && (Subtract == Result->isNegative());
8768 bool IsConstZero = Result && !Result->getBoolValue();
8769
8770 // != with increment is treated as <; != with decrement is treated as >
8771 if (!TestIsLessOp)
8772 TestIsLessOp = IsConstPos || (IsUnsigned && !Subtract);
8773 if (UB && (IsConstZero ||
8774 (*TestIsLessOp ? (IsConstNeg || (IsUnsigned && Subtract))
8775 : (IsConstPos || (IsUnsigned && !Subtract))))) {
8776 SemaRef.Diag(Loc: NewStep->getExprLoc(),
8777 DiagID: diag::err_omp_loop_incr_not_compatible)
8778 << LCDecl << *TestIsLessOp << NewStep->getSourceRange();
8779 SemaRef.Diag(Loc: ConditionLoc,
8780 DiagID: diag::note_omp_loop_cond_requires_compatible_incr)
8781 << *TestIsLessOp << ConditionSrcRange;
8782 return true;
8783 }
8784 if (*TestIsLessOp == Subtract) {
8785 NewStep =
8786 SemaRef.CreateBuiltinUnaryOp(OpLoc: NewStep->getExprLoc(), Opc: UO_Minus, InputExpr: NewStep)
8787 .get();
8788 Subtract = !Subtract;
8789 }
8790 }
8791
8792 Step = NewStep;
8793 SubtractStep = Subtract;
8794 return false;
8795}
8796
8797namespace {
8798/// Checker for the non-rectangular loops. Checks if the initializer or
8799/// condition expression references loop counter variable.
8800class LoopCounterRefChecker final
8801 : public ConstStmtVisitor<LoopCounterRefChecker, bool> {
8802 Sema &SemaRef;
8803 DSAStackTy &Stack;
8804 const ValueDecl *CurLCDecl = nullptr;
8805 const ValueDecl *DepDecl = nullptr;
8806 const ValueDecl *PrevDepDecl = nullptr;
8807 bool IsInitializer = true;
8808 bool SupportsNonRectangular;
8809 unsigned BaseLoopId = 0;
8810 bool checkDecl(const Expr *E, const ValueDecl *VD) {
8811 if (getCanonicalDecl(D: VD) == getCanonicalDecl(D: CurLCDecl)) {
8812 SemaRef.Diag(Loc: E->getExprLoc(), DiagID: diag::err_omp_stmt_depends_on_loop_counter)
8813 << (IsInitializer ? 0 : 1);
8814 return false;
8815 }
8816 const auto &&Data = Stack.isLoopControlVariable(D: VD);
8817 // OpenMP, 2.9.1 Canonical Loop Form, Restrictions.
8818 // The type of the loop iterator on which we depend may not have a random
8819 // access iterator type.
8820 if (Data.first && VD->getType()->isRecordType()) {
8821 SmallString<128> Name;
8822 llvm::raw_svector_ostream OS(Name);
8823 VD->getNameForDiagnostic(OS, Policy: SemaRef.getPrintingPolicy(),
8824 /*Qualified=*/true);
8825 SemaRef.Diag(Loc: E->getExprLoc(),
8826 DiagID: diag::err_omp_wrong_dependency_iterator_type)
8827 << OS.str();
8828 SemaRef.Diag(Loc: VD->getLocation(), DiagID: diag::note_previous_decl) << VD;
8829 return false;
8830 }
8831 if (Data.first && !SupportsNonRectangular) {
8832 SemaRef.Diag(Loc: E->getExprLoc(), DiagID: diag::err_omp_invariant_dependency);
8833 return false;
8834 }
8835 if (Data.first &&
8836 (DepDecl || (PrevDepDecl &&
8837 getCanonicalDecl(D: VD) != getCanonicalDecl(D: PrevDepDecl)))) {
8838 if (!DepDecl && PrevDepDecl)
8839 DepDecl = PrevDepDecl;
8840 SmallString<128> Name;
8841 llvm::raw_svector_ostream OS(Name);
8842 DepDecl->getNameForDiagnostic(OS, Policy: SemaRef.getPrintingPolicy(),
8843 /*Qualified=*/true);
8844 SemaRef.Diag(Loc: E->getExprLoc(),
8845 DiagID: diag::err_omp_invariant_or_linear_dependency)
8846 << OS.str();
8847 return false;
8848 }
8849 if (Data.first) {
8850 DepDecl = VD;
8851 BaseLoopId = Data.first;
8852 }
8853 return Data.first;
8854 }
8855
8856public:
8857 bool VisitDeclRefExpr(const DeclRefExpr *E) {
8858 const ValueDecl *VD = E->getDecl();
8859 if (isa<VarDecl>(Val: VD))
8860 return checkDecl(E, VD);
8861 return false;
8862 }
8863 bool VisitMemberExpr(const MemberExpr *E) {
8864 if (isa<CXXThisExpr>(Val: E->getBase()->IgnoreParens())) {
8865 const ValueDecl *VD = E->getMemberDecl();
8866 if (isa<VarDecl>(Val: VD) || isa<FieldDecl>(Val: VD))
8867 return checkDecl(E, VD);
8868 }
8869 return false;
8870 }
8871 bool VisitStmt(const Stmt *S) {
8872 bool Res = false;
8873 for (const Stmt *Child : S->children())
8874 Res = (Child && Visit(S: Child)) || Res;
8875 return Res;
8876 }
8877 explicit LoopCounterRefChecker(Sema &SemaRef, DSAStackTy &Stack,
8878 const ValueDecl *CurLCDecl, bool IsInitializer,
8879 const ValueDecl *PrevDepDecl = nullptr,
8880 bool SupportsNonRectangular = true)
8881 : SemaRef(SemaRef), Stack(Stack), CurLCDecl(CurLCDecl),
8882 PrevDepDecl(PrevDepDecl), IsInitializer(IsInitializer),
8883 SupportsNonRectangular(SupportsNonRectangular) {}
8884 unsigned getBaseLoopId() const {
8885 assert(CurLCDecl && "Expected loop dependency.");
8886 return BaseLoopId;
8887 }
8888 const ValueDecl *getDepDecl() const {
8889 assert(CurLCDecl && "Expected loop dependency.");
8890 return DepDecl;
8891 }
8892};
8893} // namespace
8894
8895std::optional<unsigned>
8896OpenMPIterationSpaceChecker::doesDependOnLoopCounter(const Stmt *S,
8897 bool IsInitializer) {
8898 // Check for the non-rectangular loops.
8899 LoopCounterRefChecker LoopStmtChecker(SemaRef, Stack, LCDecl, IsInitializer,
8900 DepDecl, SupportsNonRectangular);
8901 if (LoopStmtChecker.Visit(S)) {
8902 DepDecl = LoopStmtChecker.getDepDecl();
8903 return LoopStmtChecker.getBaseLoopId();
8904 }
8905 return std::nullopt;
8906}
8907
8908bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
8909 // Check init-expr for canonical loop form and save loop counter
8910 // variable - #Var and its initialization value - #LB.
8911 // OpenMP [2.6] Canonical loop form. init-expr may be one of the following:
8912 // var = lb
8913 // integer-type var = lb
8914 // random-access-iterator-type var = lb
8915 // pointer-type var = lb
8916 //
8917 if (!S) {
8918 if (EmitDiags) {
8919 SemaRef.Diag(Loc: DefaultLoc, DiagID: diag::err_omp_loop_not_canonical_init);
8920 }
8921 return true;
8922 }
8923 if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(Val: S))
8924 if (!ExprTemp->cleanupsHaveSideEffects())
8925 S = ExprTemp->getSubExpr();
8926
8927 if (!CollapsedLoopVarDecls.empty()) {
8928 ForSubExprChecker FSEC{CollapsedLoopVarDecls};
8929 if (!FSEC.TraverseStmt(S)) {
8930 SourceRange Range = FSEC.getErrRange();
8931 SemaRef.Diag(Loc: Range.getBegin(), DiagID: diag::err_omp_loop_bad_collapse_var)
8932 << Range.getEnd() << 0 << FSEC.getForbiddenVar();
8933 return true;
8934 }
8935 }
8936
8937 // Helper lambda to reject structured bindings used as OpenMP loop
8938 // control variables. Loop counters are implicitly private, but bindings
8939 // share storage with their decomposition, so this is not representable.
8940 auto CheckBindingAsLoopVar = [&](ValueDecl *LoopVar,
8941 SourceLocation Loc) -> bool {
8942 if (!isa<BindingDecl>(Val: LoopVar))
8943 return false;
8944 if (EmitDiags)
8945 SemaRef.Diag(Loc, DiagID: diag::err_omp_loop_var_is_structured_binding)
8946 << LoopVar;
8947 return true;
8948 };
8949
8950 // Helper lambda to check if a loop variable is already used in an outer
8951 // loop.
8952 auto CheckLoopVarReuse = [&](ValueDecl *LoopVar, SourceLocation Loc) -> bool {
8953 if (EmitDiags &&
8954 CollapsedLoopInductionVars.count(Ptr: LoopVar->getCanonicalDecl())) {
8955 SemaRef.Diag(Loc, DiagID: diag::err_omp_loop_var_reused_in_collapsed_loop)
8956 << LoopVar;
8957 return true;
8958 }
8959 return false;
8960 };
8961
8962 InitSrcRange = S->getSourceRange();
8963 if (Expr *E = dyn_cast<Expr>(Val: S))
8964 S = E->IgnoreParens();
8965 if (auto *BO = dyn_cast<BinaryOperator>(Val: S)) {
8966 if (BO->getOpcode() == BO_Assign) {
8967 Expr *LHS = BO->getLHS()->IgnoreParens();
8968 if (auto *DRE = dyn_cast<DeclRefExpr>(Val: LHS)) {
8969 if (auto *CED = dyn_cast<OMPCapturedExprDecl>(Val: DRE->getDecl()))
8970 if (auto *ME =
8971 dyn_cast<MemberExpr>(Val: getExprAsWritten(E: CED->getInit()))) {
8972 ValueDecl *LoopVar = ME->getMemberDecl();
8973 if (CheckLoopVarReuse(LoopVar, DRE->getLocation()))
8974 return true;
8975 return setLCDeclAndLB(NewLCDecl: LoopVar, NewLCRefExpr: ME, NewLB: BO->getRHS(), EmitDiags);
8976 }
8977 ValueDecl *LoopVar = DRE->getDecl();
8978 if (CheckBindingAsLoopVar(LoopVar, DRE->getLocation()))
8979 return true;
8980 if (CheckLoopVarReuse(LoopVar, DRE->getLocation()))
8981 return true;
8982 return setLCDeclAndLB(NewLCDecl: LoopVar, NewLCRefExpr: DRE, NewLB: BO->getRHS(), EmitDiags);
8983 }
8984 if (auto *ME = dyn_cast<MemberExpr>(Val: LHS)) {
8985 if (ME->isArrow() &&
8986 isa<CXXThisExpr>(Val: ME->getBase()->IgnoreParenImpCasts())) {
8987 ValueDecl *LoopVar = ME->getMemberDecl();
8988 if (CheckLoopVarReuse(LoopVar, LHS->getBeginLoc()))
8989 return true;
8990 return setLCDeclAndLB(NewLCDecl: LoopVar, NewLCRefExpr: ME, NewLB: BO->getRHS(), EmitDiags);
8991 }
8992 }
8993 }
8994 } else if (auto *DS = dyn_cast<DeclStmt>(Val: S)) {
8995 if (DS->isSingleDecl()) {
8996 if (auto *Var = dyn_cast_or_null<VarDecl>(Val: DS->getSingleDecl())) {
8997 if (Var->hasInit() && !Var->getType()->isReferenceType()) {
8998 // Accept non-canonical init form here but emit ext. warning.
8999 if (Var->getInitStyle() != VarDecl::CInit && EmitDiags)
9000 SemaRef.Diag(Loc: S->getBeginLoc(),
9001 DiagID: diag::ext_omp_loop_not_canonical_init)
9002 << S->getSourceRange();
9003 if (CheckLoopVarReuse(Var, Var->getLocation()))
9004 return true;
9005 return setLCDeclAndLB(
9006 NewLCDecl: Var,
9007 NewLCRefExpr: buildDeclRefExpr(S&: SemaRef, D: Var,
9008 Ty: Var->getType().getNonReferenceType(),
9009 Loc: DS->getBeginLoc()),
9010 NewLB: Var->getInit(), EmitDiags);
9011 }
9012 }
9013 }
9014 } else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(Val: S)) {
9015 if (CE->getOperator() == OO_Equal) {
9016 Expr *LHS = CE->getArg(Arg: 0);
9017 if (auto *DRE = dyn_cast<DeclRefExpr>(Val: LHS)) {
9018 if (auto *CED = dyn_cast<OMPCapturedExprDecl>(Val: DRE->getDecl()))
9019 if (auto *ME =
9020 dyn_cast<MemberExpr>(Val: getExprAsWritten(E: CED->getInit()))) {
9021 ValueDecl *LoopVar = ME->getMemberDecl();
9022 if (CheckLoopVarReuse(LoopVar, DRE->getLocation()))
9023 return true;
9024 return setLCDeclAndLB(NewLCDecl: LoopVar, NewLCRefExpr: ME, NewLB: CE->getArg(Arg: 1), EmitDiags);
9025 }
9026 ValueDecl *LoopVar = DRE->getDecl();
9027 if (CheckBindingAsLoopVar(LoopVar, DRE->getLocation()))
9028 return true;
9029 if (CheckLoopVarReuse(LoopVar, DRE->getLocation()))
9030 return true;
9031 return setLCDeclAndLB(NewLCDecl: LoopVar, NewLCRefExpr: DRE, NewLB: CE->getArg(Arg: 1), EmitDiags);
9032 }
9033 if (auto *ME = dyn_cast<MemberExpr>(Val: LHS)) {
9034 if (ME->isArrow() &&
9035 isa<CXXThisExpr>(Val: ME->getBase()->IgnoreParenImpCasts())) {
9036 ValueDecl *LoopVar = ME->getMemberDecl();
9037 if (CheckLoopVarReuse(LoopVar, LHS->getBeginLoc()))
9038 return true;
9039 return setLCDeclAndLB(NewLCDecl: LoopVar, NewLCRefExpr: ME, NewLB: CE->getArg(Arg: 1), EmitDiags);
9040 }
9041 }
9042 }
9043 }
9044
9045 if (dependent() || SemaRef.CurContext->isDependentContext())
9046 return false;
9047 if (EmitDiags) {
9048 SemaRef.Diag(Loc: S->getBeginLoc(), DiagID: diag::err_omp_loop_not_canonical_init)
9049 << S->getSourceRange();
9050 }
9051 return true;
9052}
9053
9054/// Ignore parenthesizes, implicit casts, copy constructor and return the
9055/// variable (which may be the loop variable) if possible.
9056static const ValueDecl *getInitLCDecl(const Expr *E) {
9057 if (!E)
9058 return nullptr;
9059 E = getExprAsWritten(E);
9060 if (const auto *CE = dyn_cast_or_null<CXXConstructExpr>(Val: E))
9061 if (const CXXConstructorDecl *Ctor = CE->getConstructor())
9062 if ((Ctor->isCopyOrMoveConstructor() ||
9063 Ctor->isConvertingConstructor(/*AllowExplicit=*/false)) &&
9064 CE->getNumArgs() > 0 && CE->getArg(Arg: 0) != nullptr)
9065 E = CE->getArg(Arg: 0)->IgnoreParenImpCasts();
9066 if (const auto *DRE = dyn_cast_or_null<DeclRefExpr>(Val: E)) {
9067 if (const auto *VD = dyn_cast<VarDecl>(Val: DRE->getDecl()))
9068 return getCanonicalDecl(D: VD);
9069 }
9070 if (const auto *ME = dyn_cast_or_null<MemberExpr>(Val: E))
9071 if (ME->isArrow() && isa<CXXThisExpr>(Val: ME->getBase()->IgnoreParenImpCasts()))
9072 return getCanonicalDecl(D: ME->getMemberDecl());
9073 return nullptr;
9074}
9075
9076bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
9077 // Check test-expr for canonical form, save upper-bound UB, flags for
9078 // less/greater and for strict/non-strict comparison.
9079 // OpenMP [2.9] Canonical loop form. Test-expr may be one of the following:
9080 // var relational-op b
9081 // b relational-op var
9082 //
9083 bool IneqCondIsCanonical = SemaRef.getLangOpts().OpenMP >= 50;
9084 if (!S) {
9085 SemaRef.Diag(Loc: DefaultLoc, DiagID: diag::err_omp_loop_not_canonical_cond)
9086 << (IneqCondIsCanonical ? 1 : 0) << LCDecl;
9087 return true;
9088 }
9089 Condition = S;
9090 S = getExprAsWritten(E: S);
9091
9092 if (!CollapsedLoopVarDecls.empty()) {
9093 ForSubExprChecker FSEC{CollapsedLoopVarDecls};
9094 if (!FSEC.TraverseStmt(S)) {
9095 SourceRange Range = FSEC.getErrRange();
9096 SemaRef.Diag(Loc: Range.getBegin(), DiagID: diag::err_omp_loop_bad_collapse_var)
9097 << Range.getEnd() << 1 << FSEC.getForbiddenVar();
9098 return true;
9099 }
9100 }
9101
9102 SourceLocation CondLoc = S->getBeginLoc();
9103 auto &&CheckAndSetCond =
9104 [this, IneqCondIsCanonical](BinaryOperatorKind Opcode, const Expr *LHS,
9105 const Expr *RHS, SourceRange SR,
9106 SourceLocation OpLoc) -> std::optional<bool> {
9107 if (BinaryOperator::isRelationalOp(Opc: Opcode)) {
9108 if (getInitLCDecl(E: LHS) == LCDecl)
9109 return setUB(NewUB: const_cast<Expr *>(RHS),
9110 LessOp: (Opcode == BO_LT || Opcode == BO_LE),
9111 StrictOp: (Opcode == BO_LT || Opcode == BO_GT), SR, SL: OpLoc);
9112 if (getInitLCDecl(E: RHS) == LCDecl)
9113 return setUB(NewUB: const_cast<Expr *>(LHS),
9114 LessOp: (Opcode == BO_GT || Opcode == BO_GE),
9115 StrictOp: (Opcode == BO_LT || Opcode == BO_GT), SR, SL: OpLoc);
9116 } else if (IneqCondIsCanonical && Opcode == BO_NE) {
9117 return setUB(NewUB: const_cast<Expr *>(getInitLCDecl(E: LHS) == LCDecl ? RHS : LHS),
9118 /*LessOp=*/std::nullopt,
9119 /*StrictOp=*/true, SR, SL: OpLoc);
9120 }
9121 return std::nullopt;
9122 };
9123 std::optional<bool> Res;
9124 if (auto *RBO = dyn_cast<CXXRewrittenBinaryOperator>(Val: S)) {
9125 CXXRewrittenBinaryOperator::DecomposedForm DF = RBO->getDecomposedForm();
9126 Res = CheckAndSetCond(DF.Opcode, DF.LHS, DF.RHS, RBO->getSourceRange(),
9127 RBO->getOperatorLoc());
9128 } else if (auto *BO = dyn_cast<BinaryOperator>(Val: S)) {
9129 Res = CheckAndSetCond(BO->getOpcode(), BO->getLHS(), BO->getRHS(),
9130 BO->getSourceRange(), BO->getOperatorLoc());
9131 } else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(Val: S)) {
9132 if (CE->getNumArgs() == 2) {
9133 Res = CheckAndSetCond(
9134 BinaryOperator::getOverloadedOpcode(OO: CE->getOperator()), CE->getArg(Arg: 0),
9135 CE->getArg(Arg: 1), CE->getSourceRange(), CE->getOperatorLoc());
9136 }
9137 }
9138 if (Res)
9139 return *Res;
9140 if (dependent() || SemaRef.CurContext->isDependentContext())
9141 return false;
9142 SemaRef.Diag(Loc: CondLoc, DiagID: diag::err_omp_loop_not_canonical_cond)
9143 << (IneqCondIsCanonical ? 1 : 0) << S->getSourceRange() << LCDecl;
9144 return true;
9145}
9146
9147bool OpenMPIterationSpaceChecker::checkAndSetIncRHS(Expr *RHS) {
9148 // RHS of canonical loop form increment can be:
9149 // var + incr
9150 // incr + var
9151 // var - incr
9152 //
9153 RHS = RHS->IgnoreParenImpCasts();
9154 if (auto *BO = dyn_cast<BinaryOperator>(Val: RHS)) {
9155 if (BO->isAdditiveOp()) {
9156 bool IsAdd = BO->getOpcode() == BO_Add;
9157 if (getInitLCDecl(E: BO->getLHS()) == LCDecl)
9158 return setStep(NewStep: BO->getRHS(), Subtract: !IsAdd);
9159 if (IsAdd && getInitLCDecl(E: BO->getRHS()) == LCDecl)
9160 return setStep(NewStep: BO->getLHS(), /*Subtract=*/false);
9161 }
9162 } else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(Val: RHS)) {
9163 bool IsAdd = CE->getOperator() == OO_Plus;
9164 if ((IsAdd || CE->getOperator() == OO_Minus) && CE->getNumArgs() == 2) {
9165 if (getInitLCDecl(E: CE->getArg(Arg: 0)) == LCDecl)
9166 return setStep(NewStep: CE->getArg(Arg: 1), Subtract: !IsAdd);
9167 if (IsAdd && getInitLCDecl(E: CE->getArg(Arg: 1)) == LCDecl)
9168 return setStep(NewStep: CE->getArg(Arg: 0), /*Subtract=*/false);
9169 }
9170 }
9171 if (dependent() || SemaRef.CurContext->isDependentContext())
9172 return false;
9173 SemaRef.Diag(Loc: RHS->getBeginLoc(), DiagID: diag::err_omp_loop_not_canonical_incr)
9174 << RHS->getSourceRange() << LCDecl;
9175 return true;
9176}
9177
9178bool OpenMPIterationSpaceChecker::checkAndSetInc(Expr *S) {
9179 // Check incr-expr for canonical loop form and return true if it
9180 // does not conform.
9181 // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following:
9182 // ++var
9183 // var++
9184 // --var
9185 // var--
9186 // var += incr
9187 // var -= incr
9188 // var = var + incr
9189 // var = incr + var
9190 // var = var - incr
9191 //
9192 if (!S) {
9193 SemaRef.Diag(Loc: DefaultLoc, DiagID: diag::err_omp_loop_not_canonical_incr) << LCDecl;
9194 return true;
9195 }
9196 if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(Val: S))
9197 if (!ExprTemp->cleanupsHaveSideEffects())
9198 S = ExprTemp->getSubExpr();
9199
9200 if (!CollapsedLoopVarDecls.empty()) {
9201 ForSubExprChecker FSEC{CollapsedLoopVarDecls};
9202 if (!FSEC.TraverseStmt(S)) {
9203 SourceRange Range = FSEC.getErrRange();
9204 SemaRef.Diag(Loc: Range.getBegin(), DiagID: diag::err_omp_loop_bad_collapse_var)
9205 << Range.getEnd() << 2 << FSEC.getForbiddenVar();
9206 return true;
9207 }
9208 }
9209
9210 IncrementSrcRange = S->getSourceRange();
9211 S = S->IgnoreParens();
9212 if (auto *UO = dyn_cast<UnaryOperator>(Val: S)) {
9213 if (UO->isIncrementDecrementOp() &&
9214 getInitLCDecl(E: UO->getSubExpr()) == LCDecl)
9215 return setStep(NewStep: SemaRef
9216 .ActOnIntegerConstant(Loc: UO->getBeginLoc(),
9217 Val: (UO->isDecrementOp() ? -1 : 1))
9218 .get(),
9219 /*Subtract=*/false);
9220 } else if (auto *BO = dyn_cast<BinaryOperator>(Val: S)) {
9221 switch (BO->getOpcode()) {
9222 case BO_AddAssign:
9223 case BO_SubAssign:
9224 if (getInitLCDecl(E: BO->getLHS()) == LCDecl)
9225 return setStep(NewStep: BO->getRHS(), Subtract: BO->getOpcode() == BO_SubAssign);
9226 break;
9227 case BO_Assign:
9228 if (getInitLCDecl(E: BO->getLHS()) == LCDecl)
9229 return checkAndSetIncRHS(RHS: BO->getRHS());
9230 break;
9231 default:
9232 break;
9233 }
9234 } else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(Val: S)) {
9235 switch (CE->getOperator()) {
9236 case OO_PlusPlus:
9237 case OO_MinusMinus:
9238 if (getInitLCDecl(E: CE->getArg(Arg: 0)) == LCDecl)
9239 return setStep(NewStep: SemaRef
9240 .ActOnIntegerConstant(
9241 Loc: CE->getBeginLoc(),
9242 Val: ((CE->getOperator() == OO_MinusMinus) ? -1 : 1))
9243 .get(),
9244 /*Subtract=*/false);
9245 break;
9246 case OO_PlusEqual:
9247 case OO_MinusEqual:
9248 if (getInitLCDecl(E: CE->getArg(Arg: 0)) == LCDecl)
9249 return setStep(NewStep: CE->getArg(Arg: 1), Subtract: CE->getOperator() == OO_MinusEqual);
9250 break;
9251 case OO_Equal:
9252 if (getInitLCDecl(E: CE->getArg(Arg: 0)) == LCDecl)
9253 return checkAndSetIncRHS(RHS: CE->getArg(Arg: 1));
9254 break;
9255 default:
9256 break;
9257 }
9258 }
9259 if (dependent() || SemaRef.CurContext->isDependentContext())
9260 return false;
9261 SemaRef.Diag(Loc: S->getBeginLoc(), DiagID: diag::err_omp_loop_not_canonical_incr)
9262 << S->getSourceRange() << LCDecl;
9263 return true;
9264}
9265
9266static ExprResult
9267tryBuildCapture(Sema &SemaRef, Expr *Capture,
9268 llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
9269 StringRef Name = ".capture_expr.") {
9270 if (SemaRef.CurContext->isDependentContext() || Capture->containsErrors())
9271 return Capture;
9272 // A statement expression must be captured even if it is constant, since the
9273 // declarations inside it can only be emitted once.
9274 if (Capture->isEvaluatable(Ctx: SemaRef.Context, AllowSideEffects: Expr::SE_AllowSideEffects) &&
9275 !findStmtExpr(E: Capture))
9276 return SemaRef.PerformImplicitConversion(From: Capture->IgnoreImpCasts(),
9277 ToType: Capture->getType(),
9278 Action: AssignmentAction::Converting,
9279 /*AllowExplicit=*/true);
9280 auto I = Captures.find(Key: Capture);
9281 if (I != Captures.end())
9282 return buildCapture(S&: SemaRef, CaptureExpr: Capture, Ref&: I->second, Name);
9283 DeclRefExpr *Ref = nullptr;
9284 ExprResult Res = buildCapture(S&: SemaRef, CaptureExpr: Capture, Ref, Name);
9285 Captures[Capture] = Ref;
9286 return Res;
9287}
9288
9289/// Calculate number of iterations, transforming to unsigned, if number of
9290/// iterations may be larger than the original type.
9291static Expr *
9292calculateNumIters(Sema &SemaRef, Scope *S, SourceLocation DefaultLoc,
9293 Expr *Lower, Expr *Upper, Expr *Step, QualType LCTy,
9294 bool TestIsStrictOp, bool RoundToStep,
9295 llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
9296 std::optional<unsigned> InitDependOnLC,
9297 std::optional<unsigned> CondDependOnLC) {
9298 ExprResult NewStep = tryBuildCapture(SemaRef, Capture: Step, Captures, Name: ".new_step");
9299 if (!NewStep.isUsable())
9300 return nullptr;
9301 llvm::APSInt LRes, SRes;
9302 bool IsLowerConst = false, IsStepConst = false;
9303 if (std::optional<llvm::APSInt> Res =
9304 Lower->getIntegerConstantExpr(Ctx: SemaRef.Context)) {
9305 LRes = *Res;
9306 IsLowerConst = true;
9307 }
9308 if (std::optional<llvm::APSInt> Res =
9309 Step->getIntegerConstantExpr(Ctx: SemaRef.Context)) {
9310 SRes = *Res;
9311 IsStepConst = true;
9312 }
9313 bool NoNeedToConvert = IsLowerConst && !RoundToStep &&
9314 ((!TestIsStrictOp && LRes.isNonNegative()) ||
9315 (TestIsStrictOp && LRes.isStrictlyPositive()));
9316 bool NeedToReorganize = false;
9317 // Check if any subexpressions in Lower -Step [+ 1] lead to overflow.
9318 if (!NoNeedToConvert && IsLowerConst &&
9319 (TestIsStrictOp || (RoundToStep && IsStepConst))) {
9320 NoNeedToConvert = true;
9321 if (RoundToStep) {
9322 unsigned BW = LRes.getBitWidth() > SRes.getBitWidth()
9323 ? LRes.getBitWidth()
9324 : SRes.getBitWidth();
9325 LRes = LRes.extend(width: BW + 1);
9326 LRes.setIsSigned(true);
9327 SRes = SRes.extend(width: BW + 1);
9328 SRes.setIsSigned(true);
9329 LRes -= SRes;
9330 NoNeedToConvert = LRes.trunc(width: BW).extend(width: BW + 1) == LRes;
9331 LRes = LRes.trunc(width: BW);
9332 }
9333 if (TestIsStrictOp) {
9334 unsigned BW = LRes.getBitWidth();
9335 LRes = LRes.extend(width: BW + 1);
9336 LRes.setIsSigned(true);
9337 ++LRes;
9338 NoNeedToConvert =
9339 NoNeedToConvert && LRes.trunc(width: BW).extend(width: BW + 1) == LRes;
9340 // truncate to the original bitwidth.
9341 LRes = LRes.trunc(width: BW);
9342 }
9343 NeedToReorganize = NoNeedToConvert;
9344 }
9345 llvm::APSInt URes;
9346 bool IsUpperConst = false;
9347 if (std::optional<llvm::APSInt> Res =
9348 Upper->getIntegerConstantExpr(Ctx: SemaRef.Context)) {
9349 URes = *Res;
9350 IsUpperConst = true;
9351 }
9352 if (NoNeedToConvert && IsLowerConst && IsUpperConst &&
9353 (!RoundToStep || IsStepConst)) {
9354 unsigned BW = LRes.getBitWidth() > URes.getBitWidth() ? LRes.getBitWidth()
9355 : URes.getBitWidth();
9356 LRes = LRes.extend(width: BW + 1);
9357 LRes.setIsSigned(true);
9358 URes = URes.extend(width: BW + 1);
9359 URes.setIsSigned(true);
9360 URes -= LRes;
9361 NoNeedToConvert = URes.trunc(width: BW).extend(width: BW + 1) == URes;
9362 NeedToReorganize = NoNeedToConvert;
9363 }
9364 // If the boundaries are not constant or (Lower - Step [+ 1]) is not constant
9365 // or less than zero (Upper - (Lower - Step [+ 1]) may overflow) - promote to
9366 // unsigned.
9367 if ((!NoNeedToConvert || (LRes.isNegative() && !IsUpperConst)) &&
9368 !LCTy->isDependentType() && LCTy->isIntegerType()) {
9369 QualType LowerTy = Lower->getType();
9370 QualType UpperTy = Upper->getType();
9371 uint64_t LowerSize = SemaRef.Context.getTypeSize(T: LowerTy);
9372 uint64_t UpperSize = SemaRef.Context.getTypeSize(T: UpperTy);
9373 if ((LowerSize <= UpperSize && UpperTy->hasSignedIntegerRepresentation()) ||
9374 (LowerSize > UpperSize && LowerTy->hasSignedIntegerRepresentation())) {
9375 QualType CastType = getIntTypeForBitwidthOrBitInt(
9376 C&: SemaRef.Context, Bits: LowerSize > UpperSize ? LowerSize : UpperSize,
9377 /*Signed=*/false);
9378 Upper =
9379 SemaRef
9380 .PerformImplicitConversion(
9381 From: SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: Upper).get(),
9382 ToType: CastType, Action: AssignmentAction::Converting)
9383 .get();
9384 Lower = SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: Lower).get();
9385 NewStep = SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: NewStep.get());
9386 }
9387 }
9388 if (!Lower || !Upper || NewStep.isInvalid())
9389 return nullptr;
9390
9391 ExprResult Diff;
9392
9393 // For nested triangular loops (depth >= 2), use already computed Upper and
9394 // Lower bounds to calculate the number of iterations: Upper - Lower + 1.
9395 // Don't apply to first-level triangular loops as the standard formula handles
9396 // those correctly.
9397 if (TestIsStrictOp && InitDependOnLC.has_value() &&
9398 InitDependOnLC.value() >= 2 && !CondDependOnLC.has_value()) {
9399 Diff = SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Sub, LHSExpr: Upper, RHSExpr: Lower);
9400 if (!Diff.isUsable())
9401 return nullptr;
9402
9403 Diff =
9404 SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Add, LHSExpr: Diff.get(),
9405 RHSExpr: SemaRef.ActOnIntegerConstant(Loc: DefaultLoc, Val: 1).get());
9406 if (!Diff.isUsable())
9407 return nullptr;
9408
9409 return Diff.get();
9410 }
9411
9412 // If need to reorganize, then calculate the form as Upper - (Lower - Step [+
9413 // 1]).
9414 if (NeedToReorganize) {
9415 Diff = Lower;
9416
9417 if (RoundToStep) {
9418 // Lower - Step
9419 Diff =
9420 SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Sub, LHSExpr: Diff.get(), RHSExpr: NewStep.get());
9421 if (!Diff.isUsable())
9422 return nullptr;
9423 }
9424
9425 // Lower - Step [+ 1]
9426 if (TestIsStrictOp)
9427 Diff = SemaRef.BuildBinOp(
9428 S, OpLoc: DefaultLoc, Opc: BO_Add, LHSExpr: Diff.get(),
9429 RHSExpr: SemaRef.ActOnIntegerConstant(Loc: SourceLocation(), Val: 1).get());
9430 if (!Diff.isUsable())
9431 return nullptr;
9432
9433 Diff = SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: Diff.get());
9434 if (!Diff.isUsable())
9435 return nullptr;
9436
9437 // Upper - (Lower - Step [+ 1]).
9438 Diff = SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Sub, LHSExpr: Upper, RHSExpr: Diff.get());
9439 if (!Diff.isUsable())
9440 return nullptr;
9441 } else {
9442 Diff = SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Sub, LHSExpr: Upper, RHSExpr: Lower);
9443
9444 if (!Diff.isUsable() && LCTy->getAsCXXRecordDecl()) {
9445 // BuildBinOp already emitted error, this one is to point user to upper
9446 // and lower bound, and to tell what is passed to 'operator-'.
9447 SemaRef.Diag(Loc: Upper->getBeginLoc(), DiagID: diag::err_omp_loop_diff_cxx)
9448 << Upper->getSourceRange() << Lower->getSourceRange();
9449 return nullptr;
9450 }
9451
9452 if (!Diff.isUsable())
9453 return nullptr;
9454
9455 // Upper - Lower [- 1]
9456 if (TestIsStrictOp)
9457 Diff = SemaRef.BuildBinOp(
9458 S, OpLoc: DefaultLoc, Opc: BO_Sub, LHSExpr: Diff.get(),
9459 RHSExpr: SemaRef.ActOnIntegerConstant(Loc: SourceLocation(), Val: 1).get());
9460 if (!Diff.isUsable())
9461 return nullptr;
9462
9463 if (RoundToStep) {
9464 // Upper - Lower [- 1] + Step
9465 Diff =
9466 SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Add, LHSExpr: Diff.get(), RHSExpr: NewStep.get());
9467 if (!Diff.isUsable())
9468 return nullptr;
9469 }
9470 }
9471
9472 // Parentheses (for dumping/debugging purposes only).
9473 Diff = SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: Diff.get());
9474 if (!Diff.isUsable())
9475 return nullptr;
9476
9477 // (Upper - Lower [- 1] + Step) / Step or (Upper - Lower) / Step
9478 Diff = SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Div, LHSExpr: Diff.get(), RHSExpr: NewStep.get());
9479 if (!Diff.isUsable())
9480 return nullptr;
9481
9482 return Diff.get();
9483}
9484
9485/// Build the expression to calculate the number of iterations.
9486Expr *OpenMPIterationSpaceChecker::buildNumIterations(
9487 Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType,
9488 llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
9489 QualType VarType = LCDecl->getType().getNonReferenceType();
9490 if (!VarType->isIntegerType() && !VarType->isPointerType() &&
9491 !SemaRef.getLangOpts().CPlusPlus)
9492 return nullptr;
9493 Expr *LBVal = LB;
9494 Expr *UBVal = UB;
9495 // OuterVar = (LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) :
9496 // max(LB(MinVal), LB(MaxVal)))
9497 if (InitDependOnLC) {
9498 const LoopIterationSpace &IS = ResultIterSpaces[*InitDependOnLC - 1];
9499 if (!IS.MinValue || !IS.MaxValue)
9500 return nullptr;
9501 // OuterVar = Min
9502 ExprResult MinValue =
9503 SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: IS.MinValue);
9504 if (!MinValue.isUsable())
9505 return nullptr;
9506
9507 ExprResult LBMinVal = SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Assign,
9508 LHSExpr: IS.CounterVar, RHSExpr: MinValue.get());
9509 if (!LBMinVal.isUsable())
9510 return nullptr;
9511 // OuterVar = Min, LBVal
9512 LBMinVal =
9513 SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Comma, LHSExpr: LBMinVal.get(), RHSExpr: LBVal);
9514 if (!LBMinVal.isUsable())
9515 return nullptr;
9516 // (OuterVar = Min, LBVal)
9517 LBMinVal = SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: LBMinVal.get());
9518 if (!LBMinVal.isUsable())
9519 return nullptr;
9520
9521 // OuterVar = Max
9522 ExprResult MaxValue =
9523 SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: IS.MaxValue);
9524 if (!MaxValue.isUsable())
9525 return nullptr;
9526
9527 ExprResult LBMaxVal = SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Assign,
9528 LHSExpr: IS.CounterVar, RHSExpr: MaxValue.get());
9529 if (!LBMaxVal.isUsable())
9530 return nullptr;
9531 // OuterVar = Max, LBVal
9532 LBMaxVal =
9533 SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Comma, LHSExpr: LBMaxVal.get(), RHSExpr: LBVal);
9534 if (!LBMaxVal.isUsable())
9535 return nullptr;
9536 // (OuterVar = Max, LBVal)
9537 LBMaxVal = SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: LBMaxVal.get());
9538 if (!LBMaxVal.isUsable())
9539 return nullptr;
9540
9541 Expr *LBMin =
9542 tryBuildCapture(SemaRef, Capture: LBMinVal.get(), Captures, Name: ".lb_min").get();
9543 Expr *LBMax =
9544 tryBuildCapture(SemaRef, Capture: LBMaxVal.get(), Captures, Name: ".lb_max").get();
9545 if (!LBMin || !LBMax)
9546 return nullptr;
9547 // LB(MinVal) < LB(MaxVal)
9548 ExprResult MinLessMaxRes =
9549 SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_LT, LHSExpr: LBMin, RHSExpr: LBMax);
9550 if (!MinLessMaxRes.isUsable())
9551 return nullptr;
9552 Expr *MinLessMax =
9553 tryBuildCapture(SemaRef, Capture: MinLessMaxRes.get(), Captures, Name: ".min_less_max")
9554 .get();
9555 if (!MinLessMax)
9556 return nullptr;
9557 if (*TestIsLessOp) {
9558 // LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal),
9559 // LB(MaxVal))
9560 ExprResult MinLB = SemaRef.ActOnConditionalOp(QuestionLoc: DefaultLoc, ColonLoc: DefaultLoc,
9561 CondExpr: MinLessMax, LHSExpr: LBMin, RHSExpr: LBMax);
9562 if (!MinLB.isUsable())
9563 return nullptr;
9564 LBVal = MinLB.get();
9565 } else {
9566 // LB(MinVal) < LB(MaxVal) ? LB(MaxVal) : LB(MinVal) - max(LB(MinVal),
9567 // LB(MaxVal))
9568 ExprResult MaxLB = SemaRef.ActOnConditionalOp(QuestionLoc: DefaultLoc, ColonLoc: DefaultLoc,
9569 CondExpr: MinLessMax, LHSExpr: LBMax, RHSExpr: LBMin);
9570 if (!MaxLB.isUsable())
9571 return nullptr;
9572 LBVal = MaxLB.get();
9573 }
9574 // OuterVar = LB
9575 LBMinVal =
9576 SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Assign, LHSExpr: IS.CounterVar, RHSExpr: LBVal);
9577 if (!LBMinVal.isUsable())
9578 return nullptr;
9579 LBVal = LBMinVal.get();
9580 }
9581 // UB = TestIsLessOp.getValue() ? max(UB(MinVal), UB(MaxVal)) :
9582 // min(UB(MinVal), UB(MaxVal))
9583 if (CondDependOnLC) {
9584 const LoopIterationSpace &IS = ResultIterSpaces[*CondDependOnLC - 1];
9585 if (!IS.MinValue || !IS.MaxValue)
9586 return nullptr;
9587 // OuterVar = Min
9588 ExprResult MinValue =
9589 SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: IS.MinValue);
9590 if (!MinValue.isUsable())
9591 return nullptr;
9592
9593 ExprResult UBMinVal = SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Assign,
9594 LHSExpr: IS.CounterVar, RHSExpr: MinValue.get());
9595 if (!UBMinVal.isUsable())
9596 return nullptr;
9597 // OuterVar = Min, UBVal
9598 UBMinVal =
9599 SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Comma, LHSExpr: UBMinVal.get(), RHSExpr: UBVal);
9600 if (!UBMinVal.isUsable())
9601 return nullptr;
9602 // (OuterVar = Min, UBVal)
9603 UBMinVal = SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: UBMinVal.get());
9604 if (!UBMinVal.isUsable())
9605 return nullptr;
9606
9607 // OuterVar = Max
9608 ExprResult MaxValue =
9609 SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: IS.MaxValue);
9610 if (!MaxValue.isUsable())
9611 return nullptr;
9612
9613 ExprResult UBMaxVal = SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Assign,
9614 LHSExpr: IS.CounterVar, RHSExpr: MaxValue.get());
9615 if (!UBMaxVal.isUsable())
9616 return nullptr;
9617 // OuterVar = Max, UBVal
9618 UBMaxVal =
9619 SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Comma, LHSExpr: UBMaxVal.get(), RHSExpr: UBVal);
9620 if (!UBMaxVal.isUsable())
9621 return nullptr;
9622 // (OuterVar = Max, UBVal)
9623 UBMaxVal = SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: UBMaxVal.get());
9624 if (!UBMaxVal.isUsable())
9625 return nullptr;
9626
9627 Expr *UBMin =
9628 tryBuildCapture(SemaRef, Capture: UBMinVal.get(), Captures, Name: ".ub_min").get();
9629 Expr *UBMax =
9630 tryBuildCapture(SemaRef, Capture: UBMaxVal.get(), Captures, Name: ".ub_max").get();
9631 if (!UBMin || !UBMax)
9632 return nullptr;
9633 // UB(MinVal) > UB(MaxVal)
9634 ExprResult MinGreaterMaxRes =
9635 SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_GT, LHSExpr: UBMin, RHSExpr: UBMax);
9636 if (!MinGreaterMaxRes.isUsable())
9637 return nullptr;
9638 Expr *MinGreaterMax = tryBuildCapture(SemaRef, Capture: MinGreaterMaxRes.get(),
9639 Captures, Name: ".min_greater_max")
9640 .get();
9641 if (!MinGreaterMax)
9642 return nullptr;
9643 if (*TestIsLessOp) {
9644 // UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal),
9645 // UB(MaxVal))
9646 ExprResult MaxUB = SemaRef.ActOnConditionalOp(
9647 QuestionLoc: DefaultLoc, ColonLoc: DefaultLoc, CondExpr: MinGreaterMax, LHSExpr: UBMin, RHSExpr: UBMax);
9648 if (!MaxUB.isUsable())
9649 return nullptr;
9650 UBVal = MaxUB.get();
9651 } else {
9652 // UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal),
9653 // UB(MaxVal))
9654 ExprResult MinUB = SemaRef.ActOnConditionalOp(
9655 QuestionLoc: DefaultLoc, ColonLoc: DefaultLoc, CondExpr: MinGreaterMax, LHSExpr: UBMax, RHSExpr: UBMin);
9656 if (!MinUB.isUsable())
9657 return nullptr;
9658 UBVal = MinUB.get();
9659 }
9660 }
9661 Expr *UBExpr = *TestIsLessOp ? UBVal : LBVal;
9662 Expr *LBExpr = *TestIsLessOp ? LBVal : UBVal;
9663 Expr *Upper = tryBuildCapture(SemaRef, Capture: UBExpr, Captures, Name: ".upper").get();
9664 Expr *Lower = tryBuildCapture(SemaRef, Capture: LBExpr, Captures, Name: ".lower").get();
9665 if (!Upper || !Lower)
9666 return nullptr;
9667
9668 ExprResult Diff = calculateNumIters(
9669 SemaRef, S, DefaultLoc, Lower, Upper, Step, LCTy: VarType, TestIsStrictOp,
9670 /*RoundToStep=*/true, Captures, InitDependOnLC, CondDependOnLC);
9671 if (!Diff.isUsable())
9672 return nullptr;
9673
9674 // OpenMP runtime requires 32-bit or 64-bit loop variables.
9675 QualType Type = Diff.get()->getType();
9676 ASTContext &C = SemaRef.Context;
9677 bool UseVarType = VarType->hasIntegerRepresentation() &&
9678 C.getTypeSize(T: Type) > C.getTypeSize(T: VarType);
9679 if (!Type->isIntegerType() || UseVarType) {
9680 unsigned NewSize =
9681 UseVarType ? C.getTypeSize(T: VarType) : C.getTypeSize(T: Type);
9682 bool IsSigned = UseVarType ? VarType->hasSignedIntegerRepresentation()
9683 : Type->hasSignedIntegerRepresentation();
9684 Type = getIntTypeForBitwidthOrBitInt(C, Bits: NewSize, Signed: IsSigned);
9685 if (!SemaRef.Context.hasSameType(T1: Diff.get()->getType(), T2: Type)) {
9686 Diff = SemaRef.PerformImplicitConversion(From: Diff.get(), ToType: Type,
9687 Action: AssignmentAction::Converting,
9688 /*AllowExplicit=*/true);
9689 if (!Diff.isUsable())
9690 return nullptr;
9691 }
9692 }
9693 if (LimitedType) {
9694 unsigned NewSize = (C.getTypeSize(T: Type) > 32) ? 64 : 32;
9695 if (NewSize != C.getTypeSize(T: Type)) {
9696 if (NewSize < C.getTypeSize(T: Type)) {
9697 assert(NewSize == 64 && "incorrect loop var size");
9698 SemaRef.Diag(Loc: DefaultLoc, DiagID: diag::warn_omp_loop_64_bit_var)
9699 << InitSrcRange << ConditionSrcRange;
9700 }
9701 QualType NewType = C.getIntTypeForBitwidth(
9702 DestWidth: NewSize, Signed: Type->hasSignedIntegerRepresentation() ||
9703 C.getTypeSize(T: Type) < NewSize);
9704 if (!SemaRef.Context.hasSameType(T1: Diff.get()->getType(), T2: NewType)) {
9705 Diff = SemaRef.PerformImplicitConversion(From: Diff.get(), ToType: NewType,
9706 Action: AssignmentAction::Converting,
9707 /*AllowExplicit=*/true);
9708 if (!Diff.isUsable())
9709 return nullptr;
9710 }
9711 }
9712 }
9713
9714 return Diff.get();
9715}
9716
9717std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
9718 Scope *S, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
9719 // Do not build for iterators, they cannot be used in non-rectangular loop
9720 // nests.
9721 if (LCDecl->getType()->isRecordType())
9722 return std::make_pair(x: nullptr, y: nullptr);
9723 // If we subtract, the min is in the condition, otherwise the min is in the
9724 // init value.
9725 Expr *MinExpr = nullptr;
9726 Expr *MaxExpr = nullptr;
9727 Expr *LBExpr = *TestIsLessOp ? LB : UB;
9728 Expr *UBExpr = *TestIsLessOp ? UB : LB;
9729 bool LBNonRect =
9730 *TestIsLessOp ? InitDependOnLC.has_value() : CondDependOnLC.has_value();
9731 bool UBNonRect =
9732 *TestIsLessOp ? CondDependOnLC.has_value() : InitDependOnLC.has_value();
9733 Expr *Lower =
9734 LBNonRect ? LBExpr : tryBuildCapture(SemaRef, Capture: LBExpr, Captures).get();
9735 Expr *Upper =
9736 UBNonRect ? UBExpr : tryBuildCapture(SemaRef, Capture: UBExpr, Captures).get();
9737 if (!Upper || !Lower)
9738 return std::make_pair(x: nullptr, y: nullptr);
9739
9740 if (*TestIsLessOp)
9741 MinExpr = Lower;
9742 else
9743 MaxExpr = Upper;
9744
9745 // Build minimum/maximum value based on number of iterations.
9746 QualType VarType = LCDecl->getType().getNonReferenceType();
9747
9748 ExprResult Diff = calculateNumIters(
9749 SemaRef, S, DefaultLoc, Lower, Upper, Step, LCTy: VarType, TestIsStrictOp,
9750 /*RoundToStep=*/false, Captures, InitDependOnLC, CondDependOnLC);
9751
9752 if (!Diff.isUsable())
9753 return std::make_pair(x: nullptr, y: nullptr);
9754
9755 // ((Upper - Lower [- 1]) / Step) * Step
9756 // Parentheses (for dumping/debugging purposes only).
9757 Diff = SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: Diff.get());
9758 if (!Diff.isUsable())
9759 return std::make_pair(x: nullptr, y: nullptr);
9760
9761 ExprResult NewStep = tryBuildCapture(SemaRef, Capture: Step, Captures, Name: ".new_step");
9762 if (!NewStep.isUsable())
9763 return std::make_pair(x: nullptr, y: nullptr);
9764 Diff = SemaRef.BuildBinOp(S, OpLoc: DefaultLoc, Opc: BO_Mul, LHSExpr: Diff.get(), RHSExpr: NewStep.get());
9765 if (!Diff.isUsable())
9766 return std::make_pair(x: nullptr, y: nullptr);
9767
9768 // Parentheses (for dumping/debugging purposes only).
9769 Diff = SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: Diff.get());
9770 if (!Diff.isUsable())
9771 return std::make_pair(x: nullptr, y: nullptr);
9772
9773 // Convert to the ptrdiff_t, if original type is pointer.
9774 if (VarType->isAnyPointerType() &&
9775 !SemaRef.Context.hasSameType(
9776 T1: Diff.get()->getType(),
9777 T2: SemaRef.Context.getUnsignedPointerDiffType())) {
9778 Diff = SemaRef.PerformImplicitConversion(
9779 From: Diff.get(), ToType: SemaRef.Context.getUnsignedPointerDiffType(),
9780 Action: AssignmentAction::Converting, /*AllowExplicit=*/true);
9781 }
9782 if (!Diff.isUsable())
9783 return std::make_pair(x: nullptr, y: nullptr);
9784
9785 if (*TestIsLessOp) {
9786 // MinExpr = Lower;
9787 // MaxExpr = Lower + (((Upper - Lower [- 1]) / Step) * Step)
9788 Diff = SemaRef.BuildBinOp(
9789 S, OpLoc: DefaultLoc, Opc: BO_Add,
9790 LHSExpr: SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: Lower).get(),
9791 RHSExpr: Diff.get());
9792 if (!Diff.isUsable())
9793 return std::make_pair(x: nullptr, y: nullptr);
9794 } else {
9795 // MaxExpr = Upper;
9796 // MinExpr = Upper - (((Upper - Lower [- 1]) / Step) * Step)
9797 Diff = SemaRef.BuildBinOp(
9798 S, OpLoc: DefaultLoc, Opc: BO_Sub,
9799 LHSExpr: SemaRef.ActOnParenExpr(L: DefaultLoc, R: DefaultLoc, E: Upper).get(),
9800 RHSExpr: Diff.get());
9801 if (!Diff.isUsable())
9802 return std::make_pair(x: nullptr, y: nullptr);
9803 }
9804
9805 // Convert to the original type.
9806 if (SemaRef.Context.hasSameType(T1: Diff.get()->getType(), T2: VarType))
9807 Diff = SemaRef.PerformImplicitConversion(From: Diff.get(), ToType: VarType,
9808 Action: AssignmentAction::Converting,
9809 /*AllowExplicit=*/true);
9810 if (!Diff.isUsable())
9811 return std::make_pair(x: nullptr, y: nullptr);
9812
9813 Sema::TentativeAnalysisScope Trap(SemaRef);
9814 Diff = SemaRef.ActOnFinishFullExpr(Expr: Diff.get(), /*DiscardedValue=*/false);
9815 if (!Diff.isUsable())
9816 return std::make_pair(x: nullptr, y: nullptr);
9817
9818 if (*TestIsLessOp)
9819 MaxExpr = Diff.get();
9820 else
9821 MinExpr = Diff.get();
9822
9823 return std::make_pair(x&: MinExpr, y&: MaxExpr);
9824}
9825
9826Expr *OpenMPIterationSpaceChecker::buildFinalCondition(Scope *S) const {
9827 if (InitDependOnLC || CondDependOnLC)
9828 return Condition;
9829 return nullptr;
9830}
9831
9832Expr *OpenMPIterationSpaceChecker::buildPreCond(
9833 Scope *S, Expr *Cond,
9834 llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
9835 // Do not build a precondition when the condition/initialization is dependent
9836 // to prevent pessimistic early loop exit.
9837 // TODO: this can be improved by calculating min/max values but not sure that
9838 // it will be very effective.
9839 if (CondDependOnLC || InitDependOnLC)
9840 return SemaRef
9841 .PerformImplicitConversion(
9842 From: SemaRef.ActOnIntegerConstant(Loc: SourceLocation(), Val: 1).get(),
9843 ToType: SemaRef.Context.BoolTy, /*Action=*/AssignmentAction::Casting,
9844 /*AllowExplicit=*/true)
9845 .get();
9846
9847 // Try to build LB <op> UB, where <op> is <, >, <=, or >=.
9848 Sema::TentativeAnalysisScope Trap(SemaRef);
9849
9850 ExprResult NewLB = tryBuildCapture(SemaRef, Capture: LB, Captures);
9851 ExprResult NewUB = tryBuildCapture(SemaRef, Capture: UB, Captures);
9852 if (!NewLB.isUsable() || !NewUB.isUsable())
9853 return nullptr;
9854
9855 ExprResult CondExpr =
9856 SemaRef.BuildBinOp(S, OpLoc: DefaultLoc,
9857 Opc: *TestIsLessOp ? (TestIsStrictOp ? BO_LT : BO_LE)
9858 : (TestIsStrictOp ? BO_GT : BO_GE),
9859 LHSExpr: NewLB.get(), RHSExpr: NewUB.get());
9860 if (CondExpr.isUsable()) {
9861 if (!SemaRef.Context.hasSameUnqualifiedType(T1: CondExpr.get()->getType(),
9862 T2: SemaRef.Context.BoolTy))
9863 CondExpr = SemaRef.PerformImplicitConversion(
9864 From: CondExpr.get(), ToType: SemaRef.Context.BoolTy,
9865 /*Action=*/AssignmentAction::Casting,
9866 /*AllowExplicit=*/true);
9867 }
9868
9869 // Otherwise use original loop condition and evaluate it in runtime.
9870 return CondExpr.isUsable() ? CondExpr.get() : Cond;
9871}
9872
9873/// Build reference expression to the counter be used for codegen.
9874DeclRefExpr *OpenMPIterationSpaceChecker::buildCounterVar(
9875 llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
9876 DSAStackTy &DSA) const {
9877 auto *VD = dyn_cast<VarDecl>(Val: LCDecl);
9878 if (!VD) {
9879 VD = SemaRef.OpenMP().isOpenMPCapturedDecl(D: LCDecl);
9880 DeclRefExpr *Ref = buildDeclRefExpr(
9881 S&: SemaRef, D: VD, Ty: VD->getType().getNonReferenceType(), Loc: DefaultLoc);
9882 const DSAStackTy::DSAVarData Data =
9883 DSA.getTopDSA(D: LCDecl, /*FromParent=*/false);
9884 // If the loop control decl is explicitly marked as private, do not mark it
9885 // as captured again.
9886 if (!isOpenMPPrivate(Kind: Data.CKind) || !Data.RefExpr)
9887 Captures.insert(KV: std::make_pair(x: LCRef, y&: Ref));
9888 return Ref;
9889 }
9890 return cast<DeclRefExpr>(Val: LCRef);
9891}
9892
9893Expr *OpenMPIterationSpaceChecker::buildPrivateCounterVar() const {
9894 if (LCDecl && !LCDecl->isInvalidDecl()) {
9895 QualType Type = LCDecl->getType().getNonReferenceType();
9896 VarDecl *PrivateVar = buildVarDecl(
9897 SemaRef, Loc: DefaultLoc, Type, Name: LCDecl->getName(),
9898 Attrs: LCDecl->hasAttrs() ? &LCDecl->getAttrs() : nullptr,
9899 OrigRef: isa<VarDecl>(Val: LCDecl)
9900 ? buildDeclRefExpr(S&: SemaRef, D: cast<VarDecl>(Val: LCDecl), Ty: Type, Loc: DefaultLoc)
9901 : nullptr);
9902 if (PrivateVar->isInvalidDecl())
9903 return nullptr;
9904 return buildDeclRefExpr(S&: SemaRef, D: PrivateVar, Ty: Type, Loc: DefaultLoc);
9905 }
9906 return nullptr;
9907}
9908
9909/// Build initialization of the counter to be used for codegen.
9910Expr *OpenMPIterationSpaceChecker::buildCounterInit() const { return LB; }
9911
9912/// Build step of the counter be used for codegen.
9913Expr *OpenMPIterationSpaceChecker::buildCounterStep() const { return Step; }
9914
9915Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
9916 Scope *S, Expr *Counter,
9917 llvm::MapVector<const Expr *, DeclRefExpr *> &Captures, SourceLocation Loc,
9918 Expr *Inc, OverloadedOperatorKind OOK) {
9919 Expr *Cnt = SemaRef.DefaultLvalueConversion(E: Counter).get();
9920 if (!Cnt)
9921 return nullptr;
9922 if (Inc) {
9923 assert((OOK == OO_Plus || OOK == OO_Minus) &&
9924 "Expected only + or - operations for depend clauses.");
9925 BinaryOperatorKind BOK = (OOK == OO_Plus) ? BO_Add : BO_Sub;
9926 Cnt = SemaRef.BuildBinOp(S, OpLoc: Loc, Opc: BOK, LHSExpr: Cnt, RHSExpr: Inc).get();
9927 if (!Cnt)
9928 return nullptr;
9929 }
9930 QualType VarType = LCDecl->getType().getNonReferenceType();
9931 if (!VarType->isIntegerType() && !VarType->isPointerType() &&
9932 !SemaRef.getLangOpts().CPlusPlus)
9933 return nullptr;
9934 // Upper - Lower
9935 Expr *Upper =
9936 *TestIsLessOp ? Cnt : tryBuildCapture(SemaRef, Capture: LB, Captures).get();
9937 Expr *Lower =
9938 *TestIsLessOp ? tryBuildCapture(SemaRef, Capture: LB, Captures).get() : Cnt;
9939 if (!Upper || !Lower)
9940 return nullptr;
9941
9942 ExprResult Diff =
9943 calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper, Step, LCTy: VarType,
9944 /*TestIsStrictOp=*/false, /*RoundToStep=*/false,
9945 Captures, InitDependOnLC, CondDependOnLC);
9946 if (!Diff.isUsable())
9947 return nullptr;
9948
9949 return Diff.get();
9950}
9951} // namespace
9952
9953void SemaOpenMP::ActOnOpenMPLoopInitialization(SourceLocation ForLoc,
9954 Stmt *Init) {
9955 assert(getLangOpts().OpenMP && "OpenMP is not active.");
9956 assert(Init && "Expected loop in canonical form.");
9957 unsigned AssociatedLoops = DSAStack->getAssociatedLoops();
9958 OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
9959 if (AssociatedLoops == 0 || !isOpenMPLoopDirective(DKind))
9960 return;
9961
9962 DSAStack->loopStart();
9963 llvm::SmallPtrSet<const Decl *, 1> EmptyDeclSet;
9964 OpenMPIterationSpaceChecker ISC(SemaRef, /*SupportsNonRectangular=*/true,
9965 *DSAStack, ForLoc, EmptyDeclSet,
9966 EmptyDeclSet);
9967 if (!ISC.checkAndSetInit(S: Init, /*EmitDiags=*/false)) {
9968 if (ValueDecl *D = ISC.getLoopDecl()) {
9969 auto *VD = dyn_cast<VarDecl>(Val: D);
9970 DeclRefExpr *PrivateRef = nullptr;
9971 if (!VD) {
9972 if (VarDecl *Private = isOpenMPCapturedDecl(D)) {
9973 VD = Private;
9974 } else {
9975 PrivateRef = buildCapture(S&: SemaRef, D, CaptureExpr: ISC.getLoopDeclRefExpr(),
9976 /*WithInit=*/false);
9977 VD = cast<VarDecl>(Val: PrivateRef->getDecl());
9978 }
9979 }
9980 DSAStack->addLoopControlVariable(D, Capture: VD);
9981 const Decl *LD = DSAStack->getPossiblyLoopCounter();
9982 if (LD != D->getCanonicalDecl()) {
9983 DSAStack->resetPossibleLoopCounter();
9984 if (auto *Var = dyn_cast_or_null<VarDecl>(Val: LD))
9985 SemaRef.MarkDeclarationsReferencedInExpr(E: buildDeclRefExpr(
9986 S&: SemaRef, D: const_cast<VarDecl *>(Var),
9987 Ty: Var->getType().getNonLValueExprType(Context: getASTContext()), Loc: ForLoc,
9988 /*RefersToCapture=*/true));
9989 }
9990 // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables
9991 // Referenced in a Construct, C/C++]. The loop iteration variable in the
9992 // associated for-loop of a simd construct with just one associated
9993 // for-loop may be listed in a linear clause with a constant-linear-step
9994 // that is the increment of the associated for-loop. The loop iteration
9995 // variable(s) in the associated for-loop(s) of a for or parallel for
9996 // construct may be listed in a private or lastprivate clause.
9997 DSAStackTy::DSAVarData DVar =
9998 DSAStack->getTopDSA(D, /*FromParent=*/false);
9999 // If LoopVarRefExpr is nullptr it means the corresponding loop variable
10000 // is declared in the loop and it is predetermined as a private.
10001 Expr *LoopDeclRefExpr = ISC.getLoopDeclRefExpr();
10002 OpenMPClauseKind PredeterminedCKind =
10003 isOpenMPSimdDirective(DKind)
10004 ? (DSAStack->hasMutipleLoops() ? OMPC_lastprivate : OMPC_linear)
10005 : OMPC_private;
10006 auto IsOpenMPTaskloopDirective = [](OpenMPDirectiveKind DK) {
10007 return getLeafConstructsOrSelf(D: DK).back() == OMPD_taskloop;
10008 };
10009 if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
10010 DVar.CKind != PredeterminedCKind && DVar.RefExpr &&
10011 (getLangOpts().OpenMP <= 45 ||
10012 (DVar.CKind != OMPC_lastprivate && DVar.CKind != OMPC_private))) ||
10013 ((isOpenMPWorksharingDirective(DKind) ||
10014 IsOpenMPTaskloopDirective(DKind) ||
10015 isOpenMPDistributeDirective(DKind)) &&
10016 !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
10017 DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) &&
10018 (DVar.CKind != OMPC_private || DVar.RefExpr)) {
10019 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
10020 Diag(Loc: Init->getBeginLoc(), DiagID: diag::err_omp_loop_var_dsa)
10021 << getOpenMPClauseNameForDiag(C: DVar.CKind)
10022 << getOpenMPDirectiveName(D: DKind, V: OMPVersion)
10023 << getOpenMPClauseNameForDiag(C: PredeterminedCKind);
10024 if (DVar.RefExpr == nullptr)
10025 DVar.CKind = PredeterminedCKind;
10026 reportOriginalDsa(SemaRef, DSAStack, D, DVar, /*IsLoopIterVar=*/true);
10027 } else if (LoopDeclRefExpr) {
10028 // Make the loop iteration variable private (for worksharing
10029 // constructs), linear (for simd directives with the only one
10030 // associated loop) or lastprivate (for simd directives with several
10031 // collapsed or ordered loops).
10032 if (DVar.CKind == OMPC_unknown)
10033 DSAStack->addDSA(D, E: LoopDeclRefExpr, A: PredeterminedCKind, PrivateCopy: PrivateRef);
10034 }
10035 }
10036 }
10037 DSAStack->setAssociatedLoops(AssociatedLoops - 1);
10038}
10039
10040namespace {
10041// Utility for OpenMP doacross clause kind
10042class OMPDoacrossKind {
10043public:
10044 bool isSource(const OMPDoacrossClause *C) {
10045 return C->getDependenceType() == OMPC_DOACROSS_source ||
10046 C->getDependenceType() == OMPC_DOACROSS_source_omp_cur_iteration;
10047 }
10048 bool isSink(const OMPDoacrossClause *C) {
10049 return C->getDependenceType() == OMPC_DOACROSS_sink;
10050 }
10051 bool isSinkIter(const OMPDoacrossClause *C) {
10052 return C->getDependenceType() == OMPC_DOACROSS_sink_omp_cur_iteration;
10053 }
10054};
10055} // namespace
10056/// Called on a for stmt to check and extract its iteration space
10057/// for further processing (such as collapsing).
10058static bool checkOpenMPIterationSpace(
10059 OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA,
10060 unsigned CurrentNestedLoopCount, unsigned NestedLoopCount,
10061 unsigned TotalNestedLoopCount, Expr *CollapseLoopCountExpr,
10062 Expr *OrderedLoopCountExpr,
10063 SemaOpenMP::VarsWithInheritedDSAType &VarsWithImplicitDSA,
10064 llvm::MutableArrayRef<LoopIterationSpace> ResultIterSpaces,
10065 llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
10066 const llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopVarDecls,
10067 llvm::SmallPtrSetImpl<const Decl *> &CollapsedLoopInductionVars) {
10068 bool SupportsNonRectangular = !isOpenMPLoopTransformationDirective(DKind);
10069
10070 // See the tile reinterpretation design note in ActOnOpenMPTileDirective.
10071 // If the loop carries the hint, analyze its rectangular form instead.
10072 //
10073 // Only directives that emit the per-iteration body guard (i.e. those going
10074 // through EmitOMPLoopBody's finals-conditions handling) may reinterpret the
10075 // loop; a loop transformation such as an enclosing 'tile' has nowhere to put
10076 // the overshoot guard, so for those the stored min-bounded form is analyzed
10077 // exactly as it is on a build without this hint.
10078 // OpenMP [2.9.1, Canonical Loop Form]
10079 // for (init-expr; test-expr; incr-expr) structured-block
10080 // for (range-decl: range-expr) structured-block
10081 if (auto *CanonLoop = dyn_cast_or_null<OMPCanonicalLoop>(Val: S))
10082 S = CanonLoop->getLoopStmt();
10083 const OMPInvariantPredicateBoundAttr *IntraTileHint =
10084 OMPLoopBasedDirective::getIntraTileHint(S);
10085 if (IntraTileHint)
10086 S = OMPLoopBasedDirective::ignoreIntraTileHint(S);
10087 Expr *TileRectCond = nullptr;
10088 Expr *TileBodyPredicate = nullptr;
10089 Expr *TileTripCount = nullptr;
10090 if (IntraTileHint && !isOpenMPLoopTransformationDirective(DKind)) {
10091 TileRectCond = IntraTileHint->getRectCond();
10092 TileBodyPredicate = IntraTileHint->getPredicate();
10093 TileTripCount = IntraTileHint->getTileSize();
10094 }
10095 auto *For = dyn_cast_or_null<ForStmt>(Val: S);
10096 auto *CXXFor = dyn_cast_or_null<CXXForRangeStmt>(Val: S);
10097 // Ranged for is supported only in OpenMP 5.0.
10098 if (!For && (SemaRef.LangOpts.OpenMP <= 45 || !CXXFor)) {
10099 llvm::omp::Version OMPVersion = SemaRef.getLangOpts().getOpenMPVersion();
10100 SemaRef.Diag(Loc: S->getBeginLoc(), DiagID: diag::err_omp_not_for)
10101 << (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr)
10102 << getOpenMPDirectiveName(D: DKind, V: OMPVersion) << TotalNestedLoopCount
10103 << (CurrentNestedLoopCount > 0) << CurrentNestedLoopCount;
10104 if (TotalNestedLoopCount > 1) {
10105 if (CollapseLoopCountExpr && OrderedLoopCountExpr)
10106 SemaRef.Diag(Loc: DSA.getConstructLoc(),
10107 DiagID: diag::note_omp_collapse_ordered_expr)
10108 << 2 << CollapseLoopCountExpr->getSourceRange()
10109 << OrderedLoopCountExpr->getSourceRange();
10110 else if (CollapseLoopCountExpr)
10111 SemaRef.Diag(Loc: CollapseLoopCountExpr->getExprLoc(),
10112 DiagID: diag::note_omp_collapse_ordered_expr)
10113 << 0 << CollapseLoopCountExpr->getSourceRange();
10114 else if (OrderedLoopCountExpr)
10115 SemaRef.Diag(Loc: OrderedLoopCountExpr->getExprLoc(),
10116 DiagID: diag::note_omp_collapse_ordered_expr)
10117 << 1 << OrderedLoopCountExpr->getSourceRange();
10118 }
10119 return true;
10120 }
10121 assert(((For && For->getBody()) || (CXXFor && CXXFor->getBody())) &&
10122 "No loop body.");
10123 // Postpone analysis in dependent contexts for ranged for loops.
10124 if (CXXFor && SemaRef.CurContext->isDependentContext())
10125 return false;
10126
10127 OpenMPIterationSpaceChecker ISC(SemaRef, SupportsNonRectangular, DSA,
10128 For ? For->getForLoc() : CXXFor->getForLoc(),
10129 CollapsedLoopVarDecls,
10130 CollapsedLoopInductionVars);
10131
10132 // Check init.
10133 Stmt *Init = For ? For->getInit() : CXXFor->getBeginStmt();
10134 if (ISC.checkAndSetInit(S: Init))
10135 return true;
10136
10137 bool HasErrors = false;
10138
10139 // Condition used for iteration-space analysis: the rectangular hint when
10140 // reinterpreting an intra-tile loop, otherwise the loop's own condition.
10141 Expr *EffectiveCond =
10142 TileRectCond ? TileRectCond : (For ? For->getCond() : CXXFor->getCond());
10143
10144 // Check loop variable's type.
10145 if (ValueDecl *LCDecl = ISC.getLoopDecl()) {
10146 // OpenMP [2.6, Canonical Loop Form]
10147 // Var is one of the following:
10148 // A variable of signed or unsigned integer type.
10149 // For C++, a variable of a random access iterator type.
10150 // For C, a variable of a pointer type.
10151 QualType VarType = LCDecl->getType().getNonReferenceType();
10152 if (!VarType->isDependentType() && !VarType->isIntegerType() &&
10153 !VarType->isPointerType() &&
10154 !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) {
10155 SemaRef.Diag(Loc: Init->getBeginLoc(), DiagID: diag::err_omp_loop_variable_type)
10156 << SemaRef.getLangOpts().CPlusPlus;
10157 HasErrors = true;
10158 }
10159
10160 // OpenMP, 2.14.1.1 Data-sharing Attribute Rules for Variables Referenced in
10161 // a Construct
10162 // The loop iteration variable(s) in the associated for-loop(s) of a for or
10163 // parallel for construct is (are) private.
10164 // The loop iteration variable in the associated for-loop of a simd
10165 // construct with just one associated for-loop is linear with a
10166 // constant-linear-step that is the increment of the associated for-loop.
10167 // Exclude loop var from the list of variables with implicitly defined data
10168 // sharing attributes.
10169 VarsWithImplicitDSA.erase(Val: LCDecl);
10170
10171 assert((isOpenMPLoopDirective(DKind) ||
10172 isOpenMPCanonicalLoopSequenceTransformationDirective(DKind)) &&
10173 "DSA for non-loop vars");
10174
10175 // Check test-expr.
10176 HasErrors |= ISC.checkAndSetCond(S: EffectiveCond);
10177
10178 // Check incr-expr.
10179 HasErrors |= ISC.checkAndSetInc(S: For ? For->getInc() : CXXFor->getInc());
10180 }
10181
10182 if (ISC.dependent() || SemaRef.CurContext->isDependentContext() || HasErrors)
10183 return HasErrors;
10184
10185 // Build the loop's iteration space representation.
10186 //
10187 // A reinterpreted intra-tile loop takes all three of these from the hint
10188 // instead of deriving them: the precondition is trivially true (the floor
10189 // loop's own precondition already covers an empty iteration space), the trip
10190 // count is the constant tile size, and any overshoot on the remainder tile
10191 // is handled by the body guard.
10192 if (TileRectCond) {
10193 ResultIterSpaces[CurrentNestedLoopCount].PreCond =
10194 SemaRef
10195 .PerformImplicitConversion(
10196 From: SemaRef.ActOnIntegerConstant(Loc: SourceLocation(), Val: 1).get(),
10197 ToType: SemaRef.Context.BoolTy, Action: AssignmentAction::Casting,
10198 /*AllowExplicit=*/true)
10199 .get();
10200 ResultIterSpaces[CurrentNestedLoopCount].NumIterations = TileTripCount;
10201 } else {
10202 ResultIterSpaces[CurrentNestedLoopCount].PreCond =
10203 ISC.buildPreCond(S: DSA.getCurScope(), Cond: EffectiveCond, Captures);
10204 ResultIterSpaces[CurrentNestedLoopCount].NumIterations =
10205 ISC.buildNumIterations(S: DSA.getCurScope(), ResultIterSpaces,
10206 LimitedType: (isOpenMPWorksharingDirective(DKind) ||
10207 isOpenMPGenericLoopDirective(DKind) ||
10208 isOpenMPTaskLoopDirective(DKind) ||
10209 isOpenMPDistributeDirective(DKind) ||
10210 isOpenMPLoopTransformationDirective(DKind)),
10211 Captures);
10212 }
10213 ResultIterSpaces[CurrentNestedLoopCount].CounterVar =
10214 ISC.buildCounterVar(Captures, DSA);
10215 ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar =
10216 ISC.buildPrivateCounterVar();
10217 ResultIterSpaces[CurrentNestedLoopCount].CounterInit = ISC.buildCounterInit();
10218 ResultIterSpaces[CurrentNestedLoopCount].CounterStep = ISC.buildCounterStep();
10219 ResultIterSpaces[CurrentNestedLoopCount].InitSrcRange = ISC.getInitSrcRange();
10220 ResultIterSpaces[CurrentNestedLoopCount].CondSrcRange =
10221 ISC.getConditionSrcRange();
10222 ResultIterSpaces[CurrentNestedLoopCount].IncSrcRange =
10223 ISC.getIncrementSrcRange();
10224 ResultIterSpaces[CurrentNestedLoopCount].Subtract = ISC.shouldSubtractStep();
10225 ResultIterSpaces[CurrentNestedLoopCount].IsStrictCompare =
10226 ISC.isStrictTestOp();
10227 std::tie(args&: ResultIterSpaces[CurrentNestedLoopCount].MinValue,
10228 args&: ResultIterSpaces[CurrentNestedLoopCount].MaxValue) =
10229 ISC.buildMinMaxValues(S: DSA.getCurScope(), Captures);
10230 if (TileRectCond) {
10231 // Floor is not a registered loop-control variable, so this helper is null.
10232 // Use the overshoot guard only (null when N % T == 0).
10233 assert(!ISC.buildFinalCondition(DSA.getCurScope()) &&
10234 "intra-tile floor is not a registered loop-control variable");
10235 ResultIterSpaces[CurrentNestedLoopCount].FinalCondition = TileBodyPredicate;
10236
10237 // Re-read .floor.iv each outer trip. Match it to an outer collapsed
10238 // counter.
10239 bool FoundFloor = false;
10240 if (Expr *InitExpr = ResultIterSpaces[CurrentNestedLoopCount].CounterInit) {
10241 if (const auto *LBRef =
10242 dyn_cast<DeclRefExpr>(Val: InitExpr->IgnoreParenImpCasts())) {
10243 const Decl *FloorDecl = LBRef->getDecl()->getCanonicalDecl();
10244 for (unsigned K = 0; K < CurrentNestedLoopCount; ++K) {
10245 const auto *CV =
10246 dyn_cast_or_null<DeclRefExpr>(Val: ResultIterSpaces[K].CounterVar);
10247 if (CV && CV->getDecl()->getCanonicalDecl() == FloorDecl) {
10248 ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularLB = true;
10249 ResultIterSpaces[CurrentNestedLoopCount].LoopDependentIdx = K + 1;
10250 FoundFloor = true;
10251 break;
10252 }
10253 }
10254 }
10255 }
10256 if (!FoundFloor) {
10257 // The floor this intra-tile loop starts from is not one of the
10258 // collapsed counters: it is assigned in the body of an enclosing
10259 // transformed loop, so the collapsed nest would read a stale value
10260 // instead of recomputing it per iteration. Diagnose to avoid silently
10261 // producing the wrong iteration space.
10262 SemaRef.Diag(Loc: ISC.getInitSrcRange().getBegin(),
10263 DiagID: diag::err_omp_collapse_stacked_tile)
10264 << /*Collapse=*/0;
10265 return true;
10266 }
10267 } else {
10268 ResultIterSpaces[CurrentNestedLoopCount].FinalCondition =
10269 ISC.buildFinalCondition(S: DSA.getCurScope());
10270 ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularLB =
10271 ISC.doesInitDependOnLC();
10272 ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularUB =
10273 ISC.doesCondDependOnLC();
10274 ResultIterSpaces[CurrentNestedLoopCount].LoopDependentIdx =
10275 ISC.getLoopDependentIdx();
10276 }
10277
10278 HasErrors |=
10279 (ResultIterSpaces[CurrentNestedLoopCount].PreCond == nullptr ||
10280 ResultIterSpaces[CurrentNestedLoopCount].NumIterations == nullptr ||
10281 ResultIterSpaces[CurrentNestedLoopCount].CounterVar == nullptr ||
10282 ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar == nullptr ||
10283 ResultIterSpaces[CurrentNestedLoopCount].CounterInit == nullptr ||
10284 ResultIterSpaces[CurrentNestedLoopCount].CounterStep == nullptr);
10285 if (!HasErrors && DSA.isOrderedRegion()) {
10286 if (DSA.getOrderedRegionParam().second->getNumForLoops()) {
10287 if (CurrentNestedLoopCount <
10288 DSA.getOrderedRegionParam().second->getLoopNumIterations().size()) {
10289 DSA.getOrderedRegionParam().second->setLoopNumIterations(
10290 NumLoop: CurrentNestedLoopCount,
10291 NumIterations: ResultIterSpaces[CurrentNestedLoopCount].NumIterations);
10292 DSA.getOrderedRegionParam().second->setLoopCounter(
10293 NumLoop: CurrentNestedLoopCount,
10294 Counter: ResultIterSpaces[CurrentNestedLoopCount].CounterVar);
10295 }
10296 }
10297 for (auto &Pair : DSA.getDoacrossDependClauses()) {
10298 auto *DependC = dyn_cast<OMPDependClause>(Val: Pair.first);
10299 auto *DoacrossC = dyn_cast<OMPDoacrossClause>(Val: Pair.first);
10300 unsigned NumLoops =
10301 DependC ? DependC->getNumLoops() : DoacrossC->getNumLoops();
10302 if (CurrentNestedLoopCount >= NumLoops) {
10303 // Erroneous case - clause has some problems.
10304 continue;
10305 }
10306 if (DependC && DependC->getDependencyKind() == OMPC_DEPEND_sink &&
10307 Pair.second.size() <= CurrentNestedLoopCount) {
10308 // Erroneous case - clause has some problems.
10309 DependC->setLoopData(NumLoop: CurrentNestedLoopCount, Cnt: nullptr);
10310 continue;
10311 }
10312 OMPDoacrossKind ODK;
10313 if (DoacrossC && ODK.isSink(C: DoacrossC) &&
10314 Pair.second.size() <= CurrentNestedLoopCount) {
10315 // Erroneous case - clause has some problems.
10316 DoacrossC->setLoopData(NumLoop: CurrentNestedLoopCount, Cnt: nullptr);
10317 continue;
10318 }
10319 Expr *CntValue;
10320 SourceLocation DepLoc =
10321 DependC ? DependC->getDependencyLoc() : DoacrossC->getDependenceLoc();
10322 if ((DependC && DependC->getDependencyKind() == OMPC_DEPEND_source) ||
10323 (DoacrossC && ODK.isSource(C: DoacrossC)))
10324 CntValue = ISC.buildOrderedLoopData(
10325 S: DSA.getCurScope(),
10326 Counter: ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures,
10327 Loc: DepLoc);
10328 else if (DoacrossC && ODK.isSinkIter(C: DoacrossC)) {
10329 Expr *Cnt = SemaRef
10330 .DefaultLvalueConversion(
10331 E: ResultIterSpaces[CurrentNestedLoopCount].CounterVar)
10332 .get();
10333 if (!Cnt)
10334 continue;
10335 // build CounterVar - 1
10336 Expr *Inc =
10337 SemaRef.ActOnIntegerConstant(Loc: DoacrossC->getColonLoc(), /*Val=*/1)
10338 .get();
10339 CntValue = ISC.buildOrderedLoopData(
10340 S: DSA.getCurScope(),
10341 Counter: ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures,
10342 Loc: DepLoc, Inc, OOK: clang::OO_Minus);
10343 } else
10344 CntValue = ISC.buildOrderedLoopData(
10345 S: DSA.getCurScope(),
10346 Counter: ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures,
10347 Loc: DepLoc, Inc: Pair.second[CurrentNestedLoopCount].first,
10348 OOK: Pair.second[CurrentNestedLoopCount].second);
10349 if (DependC)
10350 DependC->setLoopData(NumLoop: CurrentNestedLoopCount, Cnt: CntValue);
10351 else
10352 DoacrossC->setLoopData(NumLoop: CurrentNestedLoopCount, Cnt: CntValue);
10353 }
10354 }
10355 // Record the loop induction variable for nested loop reuse checking.
10356 if (CurrentNestedLoopCount < NestedLoopCount && !HasErrors) {
10357 if (const ValueDecl *LCDecl = ISC.getLoopDecl())
10358 CollapsedLoopInductionVars.insert(Ptr: LCDecl->getCanonicalDecl());
10359 }
10360 return HasErrors;
10361}
10362
10363/// Build 'VarRef = Start.
10364static ExprResult
10365buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef,
10366 ExprResult Start, bool IsNonRectangularLB,
10367 llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
10368 // Build 'VarRef = Start.
10369 ExprResult NewStart = IsNonRectangularLB
10370 ? Start.get()
10371 : tryBuildCapture(SemaRef, Capture: Start.get(), Captures);
10372 if (!NewStart.isUsable())
10373 return ExprError();
10374 if (!SemaRef.Context.hasSameType(T1: NewStart.get()->getType(),
10375 T2: VarRef.get()->getType())) {
10376 NewStart = SemaRef.PerformImplicitConversion(
10377 From: NewStart.get(), ToType: VarRef.get()->getType(), Action: AssignmentAction::Converting,
10378 /*AllowExplicit=*/true);
10379 if (!NewStart.isUsable())
10380 return ExprError();
10381 }
10382
10383 ExprResult Init =
10384 SemaRef.BuildBinOp(S, OpLoc: Loc, Opc: BO_Assign, LHSExpr: VarRef.get(), RHSExpr: NewStart.get());
10385 return Init;
10386}
10387
10388/// Build 'VarRef = Start + Iter * Step'.
10389static ExprResult buildCounterUpdate(
10390 Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef,
10391 ExprResult Start, ExprResult Iter, ExprResult Step, bool Subtract,
10392 bool IsNonRectangularLB,
10393 llvm::MapVector<const Expr *, DeclRefExpr *> *Captures = nullptr) {
10394 // Add parentheses (for debugging purposes only).
10395 Iter = SemaRef.ActOnParenExpr(L: Loc, R: Loc, E: Iter.get());
10396 if (!VarRef.isUsable() || !Start.isUsable() || !Iter.isUsable() ||
10397 !Step.isUsable())
10398 return ExprError();
10399
10400 ExprResult NewStep = Step;
10401 if (Captures)
10402 NewStep = tryBuildCapture(SemaRef, Capture: Step.get(), Captures&: *Captures);
10403 if (NewStep.isInvalid())
10404 return ExprError();
10405 ExprResult Update =
10406 SemaRef.BuildBinOp(S, OpLoc: Loc, Opc: BO_Mul, LHSExpr: Iter.get(), RHSExpr: NewStep.get());
10407 if (!Update.isUsable())
10408 return ExprError();
10409
10410 // Try to build 'VarRef = Start, VarRef (+|-)= Iter * Step' or
10411 // 'VarRef = Start (+|-) Iter * Step'.
10412 if (!Start.isUsable())
10413 return ExprError();
10414 ExprResult NewStart = SemaRef.ActOnParenExpr(L: Loc, R: Loc, E: Start.get());
10415 if (!NewStart.isUsable())
10416 return ExprError();
10417 if (Captures && !IsNonRectangularLB)
10418 NewStart = tryBuildCapture(SemaRef, Capture: Start.get(), Captures&: *Captures);
10419 if (NewStart.isInvalid())
10420 return ExprError();
10421
10422 // First attempt: try to build 'VarRef = Start, VarRef += Iter * Step'.
10423 ExprResult SavedUpdate = Update;
10424 ExprResult UpdateVal;
10425 if (VarRef.get()->getType()->isOverloadableType() ||
10426 NewStart.get()->getType()->isOverloadableType() ||
10427 Update.get()->getType()->isOverloadableType()) {
10428 Sema::TentativeAnalysisScope Trap(SemaRef);
10429
10430 Update =
10431 SemaRef.BuildBinOp(S, OpLoc: Loc, Opc: BO_Assign, LHSExpr: VarRef.get(), RHSExpr: NewStart.get());
10432 if (Update.isUsable()) {
10433 UpdateVal =
10434 SemaRef.BuildBinOp(S, OpLoc: Loc, Opc: Subtract ? BO_SubAssign : BO_AddAssign,
10435 LHSExpr: VarRef.get(), RHSExpr: SavedUpdate.get());
10436 if (UpdateVal.isUsable()) {
10437 Update = SemaRef.CreateBuiltinBinOp(OpLoc: Loc, Opc: BO_Comma, LHSExpr: Update.get(),
10438 RHSExpr: UpdateVal.get());
10439 }
10440 }
10441 }
10442
10443 // Second attempt: try to build 'VarRef = Start (+|-) Iter * Step'.
10444 if (!Update.isUsable() || !UpdateVal.isUsable()) {
10445 Update = SemaRef.BuildBinOp(S, OpLoc: Loc, Opc: Subtract ? BO_Sub : BO_Add,
10446 LHSExpr: NewStart.get(), RHSExpr: SavedUpdate.get());
10447 if (!Update.isUsable())
10448 return ExprError();
10449
10450 if (!SemaRef.Context.hasSameType(T1: Update.get()->getType(),
10451 T2: VarRef.get()->getType())) {
10452 Update = SemaRef.PerformImplicitConversion(
10453 From: Update.get(), ToType: VarRef.get()->getType(), Action: AssignmentAction::Converting,
10454 /*AllowExplicit=*/true);
10455 if (!Update.isUsable())
10456 return ExprError();
10457 }
10458
10459 Update = SemaRef.BuildBinOp(S, OpLoc: Loc, Opc: BO_Assign, LHSExpr: VarRef.get(), RHSExpr: Update.get());
10460 }
10461 return Update;
10462}
10463
10464/// Convert integer expression \a E to make it have at least \a Bits
10465/// bits.
10466static ExprResult widenIterationCount(unsigned Bits, Expr *E, Sema &SemaRef) {
10467 if (E == nullptr)
10468 return ExprError();
10469 ASTContext &C = SemaRef.Context;
10470 QualType OldType = E->getType();
10471 unsigned HasBits = C.getTypeSize(T: OldType);
10472 if (HasBits >= Bits)
10473 return ExprResult(E);
10474 // OK to convert to signed, because new type has more bits than old.
10475 QualType NewType = C.getIntTypeForBitwidth(DestWidth: Bits, /*Signed=*/true);
10476 return SemaRef.PerformImplicitConversion(
10477 From: E, ToType: NewType, Action: AssignmentAction::Converting, /*AllowExplicit=*/true);
10478}
10479
10480/// Check if the given expression \a E is a constant integer that fits
10481/// into \a Bits bits.
10482static bool fitsInto(unsigned Bits, bool Signed, const Expr *E, Sema &SemaRef) {
10483 if (E == nullptr)
10484 return false;
10485 if (std::optional<llvm::APSInt> Result =
10486 E->getIntegerConstantExpr(Ctx: SemaRef.Context))
10487 return Signed ? Result->isSignedIntN(N: Bits) : Result->isIntN(N: Bits);
10488 return false;
10489}
10490
10491/// Build preinits statement for the given declarations.
10492static Stmt *buildPreInits(ASTContext &Context,
10493 MutableArrayRef<Decl *> PreInits) {
10494 if (!PreInits.empty()) {
10495 return new (Context) DeclStmt(
10496 DeclGroupRef::Create(C&: Context, Decls: PreInits.begin(), NumDecls: PreInits.size()),
10497 SourceLocation(), SourceLocation());
10498 }
10499 return nullptr;
10500}
10501
10502/// Append the \p Item or the content of a CompoundStmt to the list \p
10503/// TargetList.
10504///
10505/// A CompoundStmt is used as container in case multiple statements need to be
10506/// stored in lieu of using an explicit list. Flattening is necessary because
10507/// contained DeclStmts need to be visible after the execution of the list. Used
10508/// for OpenMP pre-init declarations/statements.
10509static void appendFlattenedStmtList(SmallVectorImpl<Stmt *> &TargetList,
10510 Stmt *Item) {
10511 // nullptr represents an empty list.
10512 if (!Item)
10513 return;
10514
10515 if (auto *CS = dyn_cast<CompoundStmt>(Val: Item))
10516 llvm::append_range(C&: TargetList, R: CS->body());
10517 else
10518 TargetList.push_back(Elt: Item);
10519}
10520
10521/// Build preinits statement for the given declarations.
10522static Stmt *
10523buildPreInits(ASTContext &Context,
10524 const llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
10525 if (!Captures.empty()) {
10526 SmallVector<Decl *, 16> PreInits;
10527 for (const auto &Pair : Captures)
10528 PreInits.push_back(Elt: Pair.second->getDecl());
10529 return buildPreInits(Context, PreInits);
10530 }
10531 return nullptr;
10532}
10533
10534/// Build pre-init statement for the given statements.
10535static Stmt *buildPreInits(ASTContext &Context, ArrayRef<Stmt *> PreInits) {
10536 if (PreInits.empty())
10537 return nullptr;
10538
10539 SmallVector<Stmt *> Stmts;
10540 for (Stmt *S : PreInits)
10541 appendFlattenedStmtList(TargetList&: Stmts, Item: S);
10542 return CompoundStmt::Create(C: Context, Stmts: PreInits, FPFeatures: FPOptionsOverride(), LB: {}, RB: {});
10543}
10544
10545/// Build postupdate expression for the given list of postupdates expressions.
10546static Expr *buildPostUpdate(Sema &S, ArrayRef<Expr *> PostUpdates) {
10547 Expr *PostUpdate = nullptr;
10548 if (!PostUpdates.empty()) {
10549 for (Expr *E : PostUpdates) {
10550 Expr *ConvE = S.BuildCStyleCastExpr(
10551 LParenLoc: E->getExprLoc(),
10552 Ty: S.Context.getTrivialTypeSourceInfo(T: S.Context.VoidTy),
10553 RParenLoc: E->getExprLoc(), Op: E)
10554 .get();
10555 PostUpdate = PostUpdate
10556 ? S.CreateBuiltinBinOp(OpLoc: ConvE->getExprLoc(), Opc: BO_Comma,
10557 LHSExpr: PostUpdate, RHSExpr: ConvE)
10558 .get()
10559 : ConvE;
10560 }
10561 }
10562 return PostUpdate;
10563}
10564
10565/// Look for variables declared in the body parts of a for-loop nest. Used
10566/// for verifying loop nest structure before performing a loop collapse
10567/// operation.
10568class ForVarDeclFinder : public DynamicRecursiveASTVisitor {
10569 int NestingDepth = 0;
10570 llvm::SmallPtrSetImpl<const Decl *> &VarDecls;
10571
10572public:
10573 explicit ForVarDeclFinder(llvm::SmallPtrSetImpl<const Decl *> &VD)
10574 : VarDecls(VD) {}
10575
10576 bool VisitForStmt(ForStmt *F) override {
10577 ++NestingDepth;
10578 TraverseStmt(S: F->getBody());
10579 --NestingDepth;
10580 return false;
10581 }
10582
10583 bool VisitCXXForRangeStmt(CXXForRangeStmt *RF) override {
10584 ++NestingDepth;
10585 TraverseStmt(S: RF->getBody());
10586 --NestingDepth;
10587 return false;
10588 }
10589
10590 bool VisitVarDecl(VarDecl *D) override {
10591 Decl *C = D->getCanonicalDecl();
10592 if (NestingDepth > 0)
10593 VarDecls.insert(Ptr: C);
10594 return true;
10595 }
10596};
10597
10598/// Called on a for stmt to check itself and nested loops (if any).
10599/// \return Returns 0 if one of the collapsed stmts is not canonical for loop,
10600/// number of collapsed loops otherwise.
10601static unsigned
10602checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
10603 Expr *OrderedLoopCountExpr, Stmt *AStmt, Sema &SemaRef,
10604 DSAStackTy &DSA,
10605 SemaOpenMP::VarsWithInheritedDSAType &VarsWithImplicitDSA,
10606 OMPLoopBasedDirective::HelperExprs &Built) {
10607 // If either of the loop expressions exist and contain errors, we bail out
10608 // early because diagnostics have already been emitted and we can't reliably
10609 // check more about the loop.
10610 if ((CollapseLoopCountExpr && CollapseLoopCountExpr->containsErrors()) ||
10611 (OrderedLoopCountExpr && OrderedLoopCountExpr->containsErrors()))
10612 return 0;
10613
10614 unsigned NestedLoopCount = 1;
10615 bool SupportsNonPerfectlyNested = (SemaRef.LangOpts.OpenMP >= 50) &&
10616 !isOpenMPLoopTransformationDirective(DKind);
10617 llvm::SmallPtrSet<const Decl *, 4> CollapsedLoopVarDecls;
10618 llvm::SmallPtrSet<const Decl *, 4> CollapsedLoopInductionVars;
10619
10620 if (CollapseLoopCountExpr) {
10621 // Found 'collapse' clause - calculate collapse number.
10622 Expr::EvalResult Result;
10623 if (!CollapseLoopCountExpr->isInstantiationDependent() &&
10624 CollapseLoopCountExpr->EvaluateAsInt(Result, Ctx: SemaRef.getASTContext())) {
10625 NestedLoopCount = Result.Val.getInt().getLimitedValue();
10626
10627 ForVarDeclFinder FVDF{CollapsedLoopVarDecls};
10628 FVDF.TraverseStmt(S: AStmt);
10629 } else {
10630 Built.clear(/*Size=*/1);
10631 return 1;
10632 }
10633 }
10634 unsigned OrderedLoopCount = 1;
10635 if (OrderedLoopCountExpr) {
10636 // Found 'ordered' clause - calculate collapse number.
10637 Expr::EvalResult EVResult;
10638 if (!OrderedLoopCountExpr->isInstantiationDependent() &&
10639 OrderedLoopCountExpr->EvaluateAsInt(Result&: EVResult,
10640 Ctx: SemaRef.getASTContext())) {
10641 llvm::APSInt Result = EVResult.Val.getInt();
10642 if (Result.getLimitedValue() < NestedLoopCount) {
10643 SemaRef.Diag(Loc: OrderedLoopCountExpr->getExprLoc(),
10644 DiagID: diag::err_omp_wrong_ordered_loop_count)
10645 << OrderedLoopCountExpr->getSourceRange();
10646 SemaRef.Diag(Loc: CollapseLoopCountExpr->getExprLoc(),
10647 DiagID: diag::note_collapse_loop_count)
10648 << CollapseLoopCountExpr->getSourceRange();
10649 }
10650 OrderedLoopCount = Result.getLimitedValue();
10651 } else {
10652 Built.clear(/*Size=*/1);
10653 return 1;
10654 }
10655 }
10656 // This is helper routine for loop directives (e.g., 'for', 'simd',
10657 // 'for simd', etc.).
10658 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
10659 unsigned NumLoops = std::max(a: OrderedLoopCount, b: NestedLoopCount);
10660 SmallVector<LoopIterationSpace, 4> IterSpaces(NumLoops);
10661 if (!OMPLoopBasedDirective::doForAllLoops(
10662 CurStmt: AStmt->IgnoreContainers(
10663 IgnoreCaptured: !isOpenMPCanonicalLoopNestTransformationDirective(DKind)),
10664 TryImperfectlyNestedLoops: SupportsNonPerfectlyNested, NumLoops,
10665 Callback: [DKind, &SemaRef, &DSA, NumLoops, NestedLoopCount,
10666 CollapseLoopCountExpr, OrderedLoopCountExpr, &VarsWithImplicitDSA,
10667 &IterSpaces, &Captures, &CollapsedLoopVarDecls,
10668 &CollapsedLoopInductionVars](unsigned Cnt, Stmt *Loop,
10669 Stmt *HintWrapper) {
10670 Stmt *CurStmt = HintWrapper ? HintWrapper : Loop;
10671 if (checkOpenMPIterationSpace(
10672 DKind, S: CurStmt, SemaRef, DSA, CurrentNestedLoopCount: Cnt, NestedLoopCount,
10673 TotalNestedLoopCount: NumLoops, CollapseLoopCountExpr, OrderedLoopCountExpr,
10674 VarsWithImplicitDSA, ResultIterSpaces: IterSpaces, Captures,
10675 CollapsedLoopVarDecls, CollapsedLoopInductionVars))
10676 return true;
10677 if (Cnt > 0 && Cnt >= NestedLoopCount &&
10678 IterSpaces[Cnt].CounterVar) {
10679 // Handle initialization of captured loop iterator variables.
10680 auto *DRE = cast<DeclRefExpr>(Val: IterSpaces[Cnt].CounterVar);
10681 if (isa<OMPCapturedExprDecl>(Val: DRE->getDecl())) {
10682 Captures[DRE] = DRE;
10683 }
10684 }
10685 return false;
10686 },
10687 OnTransformationCallback: [&SemaRef, &Captures](OMPLoopTransformationDirective *Transform) {
10688 Stmt *DependentPreInits = Transform->getPreInits();
10689 if (!DependentPreInits)
10690 return;
10691
10692 // Search for pre-init declared variables that need to be captured
10693 // to be referenceable inside the directive.
10694 SmallVector<Stmt *> Constituents;
10695 appendFlattenedStmtList(TargetList&: Constituents, Item: DependentPreInits);
10696 for (Stmt *S : Constituents) {
10697 if (auto *DC = dyn_cast<DeclStmt>(Val: S)) {
10698 for (Decl *C : DC->decls()) {
10699 auto *D = cast<VarDecl>(Val: C);
10700 DeclRefExpr *Ref = buildDeclRefExpr(
10701 S&: SemaRef, D, Ty: D->getType().getNonReferenceType(),
10702 Loc: cast<OMPExecutableDirective>(Val: Transform->getDirective())
10703 ->getBeginLoc());
10704 Captures[Ref] = Ref;
10705 }
10706 }
10707 }
10708 }))
10709 return 0;
10710
10711 Built.clear(/*size=*/Size: NestedLoopCount);
10712
10713 if (SemaRef.CurContext->isDependentContext())
10714 return NestedLoopCount;
10715
10716 // An example of what is generated for the following code:
10717 //
10718 // #pragma omp simd collapse(2) ordered(2)
10719 // for (i = 0; i < NI; ++i)
10720 // for (k = 0; k < NK; ++k)
10721 // for (j = J0; j < NJ; j+=2) {
10722 // <loop body>
10723 // }
10724 //
10725 // We generate the code below.
10726 // Note: the loop body may be outlined in CodeGen.
10727 // Note: some counters may be C++ classes, operator- is used to find number of
10728 // iterations and operator+= to calculate counter value.
10729 // Note: decltype(NumIterations) must be integer type (in 'omp for', only i32
10730 // or i64 is currently supported).
10731 //
10732 // #define NumIterations (NI * ((NJ - J0 - 1 + 2) / 2))
10733 // for (int[32|64]_t IV = 0; IV < NumIterations; ++IV ) {
10734 // .local.i = IV / ((NJ - J0 - 1 + 2) / 2);
10735 // .local.j = J0 + (IV % ((NJ - J0 - 1 + 2) / 2)) * 2;
10736 // // similar updates for vars in clauses (e.g. 'linear')
10737 // <loop body (using local i and j)>
10738 // }
10739 // i = NI; // assign final values of counters
10740 // j = NJ;
10741 //
10742
10743 // Last iteration number is (I1 * I2 * ... In) - 1, where I1, I2 ... In are
10744 // the iteration counts of the collapsed for loops.
10745 // Precondition tests if there is at least one iteration (all conditions are
10746 // true).
10747 auto PreCond = ExprResult(IterSpaces[0].PreCond);
10748 ASTContext &C = SemaRef.Context;
10749 unsigned FirstCountBits =
10750 C.getTypeSize(T: IterSpaces[0].NumIterations->getType());
10751 bool AllCountsNeedLessThan32Bits = FirstCountBits < 32;
10752
10753 Scope *CurScope = DSA.getCurScope();
10754 for (unsigned Cnt = 1; Cnt < NestedLoopCount; ++Cnt) {
10755 if (PreCond.isUsable()) {
10756 PreCond =
10757 SemaRef.BuildBinOp(S: CurScope, OpLoc: PreCond.get()->getExprLoc(), Opc: BO_LAnd,
10758 LHSExpr: PreCond.get(), RHSExpr: IterSpaces[Cnt].PreCond);
10759 }
10760 Expr *N = IterSpaces[Cnt].NumIterations;
10761 AllCountsNeedLessThan32Bits &= C.getTypeSize(T: N->getType()) < 32;
10762 }
10763
10764 auto BuildLastIteration = [&](unsigned Bits) -> ExprResult {
10765 ExprResult Result;
10766 for (unsigned Cnt : llvm::seq<unsigned>(Size: NestedLoopCount)) {
10767 Expr *N = IterSpaces[Cnt].NumIterations;
10768 ExprResult Count = widenIterationCount(
10769 Bits,
10770 E: SemaRef
10771 .PerformImplicitConversion(From: N->IgnoreImpCasts(), ToType: N->getType(),
10772 Action: AssignmentAction::Converting,
10773 /*AllowExplicit=*/true)
10774 .get(),
10775 SemaRef);
10776 if (!Count.isUsable())
10777 return ExprError();
10778 if (Cnt == 0)
10779 Result = Count;
10780 else
10781 Result = SemaRef.BuildBinOp(S: CurScope, OpLoc: N->getExprLoc(), Opc: BO_Mul,
10782 LHSExpr: Result.get(), RHSExpr: Count.get());
10783 if (!Result.isUsable())
10784 return ExprError();
10785 }
10786 return Result;
10787 };
10788
10789 // Build the 32-bit tree immediately only when it is always selected.
10790 // Otherwise, build the 64-bit tree first and build the 32-bit tree only when
10791 // the constant product may fit.
10792 ExprResult LastIteration;
10793 if (SemaRef.getLangOpts().OpenMPOptimisticCollapse ||
10794 AllCountsNeedLessThan32Bits ||
10795 (NestedLoopCount == 1 && FirstCountBits == 32)) {
10796 LastIteration = BuildLastIteration(/*Bits=*/32);
10797 } else {
10798 ExprResult LastIteration64 = BuildLastIteration(/*Bits=*/64);
10799 if (!LastIteration64.isUsable())
10800 return NestedLoopCount;
10801 LastIteration = LastIteration64;
10802 if (LastIteration64.get()->isIntegerConstantExpr(Ctx: C)) {
10803 ExprResult LastIteration32 = BuildLastIteration(/*Bits=*/32);
10804 if (LastIteration32.isUsable() &&
10805 C.getTypeSize(T: LastIteration32.get()->getType()) == 32 &&
10806 fitsInto(
10807 /*Bits=*/32,
10808 Signed: LastIteration32.get()
10809 ->getType()
10810 ->hasSignedIntegerRepresentation(),
10811 E: LastIteration64.get(), SemaRef))
10812 LastIteration = LastIteration32;
10813 }
10814 }
10815 if (!LastIteration.isUsable())
10816 return NestedLoopCount;
10817
10818 QualType VType = LastIteration.get()->getType();
10819 QualType RealVType = VType;
10820 QualType StrideVType = VType;
10821 if (isOpenMPTaskLoopDirective(DKind)) {
10822 VType =
10823 SemaRef.Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0);
10824 StrideVType =
10825 SemaRef.Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1);
10826 }
10827
10828 // Save the number of iterations.
10829 ExprResult NumIterations = LastIteration;
10830 {
10831 LastIteration = SemaRef.BuildBinOp(
10832 S: CurScope, OpLoc: LastIteration.get()->getExprLoc(), Opc: BO_Sub,
10833 LHSExpr: LastIteration.get(),
10834 RHSExpr: SemaRef.ActOnIntegerConstant(Loc: SourceLocation(), Val: 1).get());
10835 if (!LastIteration.isUsable())
10836 return 0;
10837 }
10838
10839 // Calculate the last iteration number beforehand instead of doing this on
10840 // each iteration. Do not do this if the number of iterations may be kfold-ed.
10841 bool IsConstant = LastIteration.get()->isIntegerConstantExpr(Ctx: SemaRef.Context);
10842 ExprResult CalcLastIteration;
10843 if (!IsConstant) {
10844 ExprResult SaveRef =
10845 tryBuildCapture(SemaRef, Capture: LastIteration.get(), Captures);
10846 LastIteration = SaveRef;
10847
10848 // Prepare SaveRef + 1.
10849 NumIterations = SemaRef.BuildBinOp(
10850 S: CurScope, OpLoc: SaveRef.get()->getExprLoc(), Opc: BO_Add, LHSExpr: SaveRef.get(),
10851 RHSExpr: SemaRef.ActOnIntegerConstant(Loc: SourceLocation(), Val: 1).get());
10852 if (!NumIterations.isUsable())
10853 return 0;
10854 }
10855
10856 SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin();
10857
10858 // Build variables passed into runtime, necessary for worksharing directives.
10859 ExprResult LB, UB, IL, ST, EUB, CombLB, CombUB, PrevLB, PrevUB, CombEUB;
10860 if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) ||
10861 isOpenMPDistributeDirective(DKind) ||
10862 isOpenMPGenericLoopDirective(DKind) ||
10863 isOpenMPLoopTransformationDirective(DKind)) {
10864 // Lower bound variable, initialized with zero.
10865 VarDecl *LBDecl = buildVarDecl(SemaRef, Loc: InitLoc, Type: VType, Name: ".omp.lb");
10866 LB = buildDeclRefExpr(S&: SemaRef, D: LBDecl, Ty: VType, Loc: InitLoc);
10867 SemaRef.AddInitializerToDecl(dcl: LBDecl,
10868 init: SemaRef.ActOnIntegerConstant(Loc: InitLoc, Val: 0).get(),
10869 /*DirectInit=*/false);
10870
10871 // Upper bound variable, initialized with last iteration number.
10872 VarDecl *UBDecl = buildVarDecl(SemaRef, Loc: InitLoc, Type: VType, Name: ".omp.ub");
10873 UB = buildDeclRefExpr(S&: SemaRef, D: UBDecl, Ty: VType, Loc: InitLoc);
10874 SemaRef.AddInitializerToDecl(dcl: UBDecl, init: LastIteration.get(),
10875 /*DirectInit=*/false);
10876
10877 // A 32-bit variable-flag where runtime returns 1 for the last iteration.
10878 // This will be used to implement clause 'lastprivate'.
10879 QualType Int32Ty = SemaRef.Context.getIntTypeForBitwidth(DestWidth: 32, Signed: true);
10880 VarDecl *ILDecl = buildVarDecl(SemaRef, Loc: InitLoc, Type: Int32Ty, Name: ".omp.is_last");
10881 IL = buildDeclRefExpr(S&: SemaRef, D: ILDecl, Ty: Int32Ty, Loc: InitLoc);
10882 SemaRef.AddInitializerToDecl(dcl: ILDecl,
10883 init: SemaRef.ActOnIntegerConstant(Loc: InitLoc, Val: 0).get(),
10884 /*DirectInit=*/false);
10885
10886 // Stride variable returned by runtime (we initialize it to 1 by default).
10887 VarDecl *STDecl =
10888 buildVarDecl(SemaRef, Loc: InitLoc, Type: StrideVType, Name: ".omp.stride");
10889 ST = buildDeclRefExpr(S&: SemaRef, D: STDecl, Ty: StrideVType, Loc: InitLoc);
10890 SemaRef.AddInitializerToDecl(dcl: STDecl,
10891 init: SemaRef.ActOnIntegerConstant(Loc: InitLoc, Val: 1).get(),
10892 /*DirectInit=*/false);
10893
10894 // Build expression: UB = min(UB, LastIteration)
10895 // It is necessary for CodeGen of directives with static scheduling.
10896 ExprResult IsUBGreater = SemaRef.BuildBinOp(S: CurScope, OpLoc: InitLoc, Opc: BO_GT,
10897 LHSExpr: UB.get(), RHSExpr: LastIteration.get());
10898 ExprResult CondOp = SemaRef.ActOnConditionalOp(
10899 QuestionLoc: LastIteration.get()->getExprLoc(), ColonLoc: InitLoc, CondExpr: IsUBGreater.get(),
10900 LHSExpr: LastIteration.get(), RHSExpr: UB.get());
10901 EUB = SemaRef.BuildBinOp(S: CurScope, OpLoc: InitLoc, Opc: BO_Assign, LHSExpr: UB.get(),
10902 RHSExpr: CondOp.get());
10903 EUB = SemaRef.ActOnFinishFullExpr(Expr: EUB.get(), /*DiscardedValue=*/false);
10904
10905 // If we have a combined directive that combines 'distribute', 'for' or
10906 // 'simd' we need to be able to access the bounds of the schedule of the
10907 // enclosing region. E.g. in 'distribute parallel for' the bounds obtained
10908 // by scheduling 'distribute' have to be passed to the schedule of 'for'.
10909 if (isOpenMPLoopBoundSharingDirective(Kind: DKind)) {
10910 // Lower bound variable, initialized with zero.
10911 VarDecl *CombLBDecl =
10912 buildVarDecl(SemaRef, Loc: InitLoc, Type: VType, Name: ".omp.comb.lb");
10913 CombLB = buildDeclRefExpr(S&: SemaRef, D: CombLBDecl, Ty: VType, Loc: InitLoc);
10914 SemaRef.AddInitializerToDecl(
10915 dcl: CombLBDecl, init: SemaRef.ActOnIntegerConstant(Loc: InitLoc, Val: 0).get(),
10916 /*DirectInit=*/false);
10917
10918 // Upper bound variable, initialized with last iteration number.
10919 VarDecl *CombUBDecl =
10920 buildVarDecl(SemaRef, Loc: InitLoc, Type: VType, Name: ".omp.comb.ub");
10921 CombUB = buildDeclRefExpr(S&: SemaRef, D: CombUBDecl, Ty: VType, Loc: InitLoc);
10922 SemaRef.AddInitializerToDecl(dcl: CombUBDecl, init: LastIteration.get(),
10923 /*DirectInit=*/false);
10924
10925 ExprResult CombIsUBGreater = SemaRef.BuildBinOp(
10926 S: CurScope, OpLoc: InitLoc, Opc: BO_GT, LHSExpr: CombUB.get(), RHSExpr: LastIteration.get());
10927 ExprResult CombCondOp =
10928 SemaRef.ActOnConditionalOp(QuestionLoc: InitLoc, ColonLoc: InitLoc, CondExpr: CombIsUBGreater.get(),
10929 LHSExpr: LastIteration.get(), RHSExpr: CombUB.get());
10930 CombEUB = SemaRef.BuildBinOp(S: CurScope, OpLoc: InitLoc, Opc: BO_Assign, LHSExpr: CombUB.get(),
10931 RHSExpr: CombCondOp.get());
10932 CombEUB =
10933 SemaRef.ActOnFinishFullExpr(Expr: CombEUB.get(), /*DiscardedValue=*/false);
10934
10935 const CapturedDecl *CD = cast<CapturedStmt>(Val: AStmt)->getCapturedDecl();
10936 // We expect to have at least 2 more parameters than the 'parallel'
10937 // directive does - the lower and upper bounds of the previous schedule.
10938 assert(CD->getNumParams() >= 4 &&
10939 "Unexpected number of parameters in loop combined directive");
10940
10941 // Set the proper type for the bounds given what we learned from the
10942 // enclosed loops.
10943 ImplicitParamDecl *PrevLBDecl = CD->getParam(/*PrevLB=*/i: 2);
10944 ImplicitParamDecl *PrevUBDecl = CD->getParam(/*PrevUB=*/i: 3);
10945
10946 // Previous lower and upper bounds are obtained from the region
10947 // parameters.
10948 PrevLB =
10949 buildDeclRefExpr(S&: SemaRef, D: PrevLBDecl, Ty: PrevLBDecl->getType(), Loc: InitLoc);
10950 PrevUB =
10951 buildDeclRefExpr(S&: SemaRef, D: PrevUBDecl, Ty: PrevUBDecl->getType(), Loc: InitLoc);
10952 }
10953 }
10954
10955 // Build the iteration variable and its initialization before loop.
10956 ExprResult IV;
10957 ExprResult Init, CombInit;
10958 {
10959 VarDecl *IVDecl = buildVarDecl(SemaRef, Loc: InitLoc, Type: RealVType, Name: ".omp.iv");
10960 IV = buildDeclRefExpr(S&: SemaRef, D: IVDecl, Ty: RealVType, Loc: InitLoc);
10961 Expr *RHS = (isOpenMPWorksharingDirective(DKind) ||
10962 isOpenMPGenericLoopDirective(DKind) ||
10963 isOpenMPTaskLoopDirective(DKind) ||
10964 isOpenMPDistributeDirective(DKind) ||
10965 isOpenMPLoopTransformationDirective(DKind))
10966 ? LB.get()
10967 : SemaRef.ActOnIntegerConstant(Loc: SourceLocation(), Val: 0).get();
10968 Init = SemaRef.BuildBinOp(S: CurScope, OpLoc: InitLoc, Opc: BO_Assign, LHSExpr: IV.get(), RHSExpr: RHS);
10969 Init = SemaRef.ActOnFinishFullExpr(Expr: Init.get(), /*DiscardedValue=*/false);
10970
10971 if (isOpenMPLoopBoundSharingDirective(Kind: DKind)) {
10972 Expr *CombRHS =
10973 (isOpenMPWorksharingDirective(DKind) ||
10974 isOpenMPGenericLoopDirective(DKind) ||
10975 isOpenMPTaskLoopDirective(DKind) ||
10976 isOpenMPDistributeDirective(DKind))
10977 ? CombLB.get()
10978 : SemaRef.ActOnIntegerConstant(Loc: SourceLocation(), Val: 0).get();
10979 CombInit =
10980 SemaRef.BuildBinOp(S: CurScope, OpLoc: InitLoc, Opc: BO_Assign, LHSExpr: IV.get(), RHSExpr: CombRHS);
10981 CombInit =
10982 SemaRef.ActOnFinishFullExpr(Expr: CombInit.get(), /*DiscardedValue=*/false);
10983 }
10984 }
10985
10986 bool UseStrictCompare =
10987 RealVType->hasUnsignedIntegerRepresentation() &&
10988 llvm::all_of(Range&: IterSpaces, P: [](const LoopIterationSpace &LIS) {
10989 return LIS.IsStrictCompare;
10990 });
10991 // Loop condition (IV < NumIterations) or (IV <= UB or IV < UB + 1 (for
10992 // unsigned IV)) for worksharing loops.
10993 SourceLocation CondLoc = AStmt->getBeginLoc();
10994 Expr *BoundUB = UB.get();
10995 if (UseStrictCompare) {
10996 BoundUB =
10997 SemaRef
10998 .BuildBinOp(S: CurScope, OpLoc: CondLoc, Opc: BO_Add, LHSExpr: BoundUB,
10999 RHSExpr: SemaRef.ActOnIntegerConstant(Loc: SourceLocation(), Val: 1).get())
11000 .get();
11001 BoundUB =
11002 SemaRef.ActOnFinishFullExpr(Expr: BoundUB, /*DiscardedValue=*/false).get();
11003 }
11004 ExprResult Cond =
11005 (isOpenMPWorksharingDirective(DKind) ||
11006 isOpenMPGenericLoopDirective(DKind) ||
11007 isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind) ||
11008 isOpenMPLoopTransformationDirective(DKind))
11009 ? SemaRef.BuildBinOp(S: CurScope, OpLoc: CondLoc,
11010 Opc: UseStrictCompare ? BO_LT : BO_LE, LHSExpr: IV.get(),
11011 RHSExpr: BoundUB)
11012 : SemaRef.BuildBinOp(S: CurScope, OpLoc: CondLoc, Opc: BO_LT, LHSExpr: IV.get(),
11013 RHSExpr: NumIterations.get());
11014 ExprResult CombDistCond;
11015 if (isOpenMPLoopBoundSharingDirective(Kind: DKind)) {
11016 CombDistCond = SemaRef.BuildBinOp(S: CurScope, OpLoc: CondLoc, Opc: BO_LT, LHSExpr: IV.get(),
11017 RHSExpr: NumIterations.get());
11018 }
11019
11020 ExprResult CombCond;
11021 if (isOpenMPLoopBoundSharingDirective(Kind: DKind)) {
11022 Expr *BoundCombUB = CombUB.get();
11023 if (UseStrictCompare) {
11024 BoundCombUB =
11025 SemaRef
11026 .BuildBinOp(
11027 S: CurScope, OpLoc: CondLoc, Opc: BO_Add, LHSExpr: BoundCombUB,
11028 RHSExpr: SemaRef.ActOnIntegerConstant(Loc: SourceLocation(), Val: 1).get())
11029 .get();
11030 BoundCombUB =
11031 SemaRef.ActOnFinishFullExpr(Expr: BoundCombUB, /*DiscardedValue=*/false)
11032 .get();
11033 }
11034 CombCond =
11035 SemaRef.BuildBinOp(S: CurScope, OpLoc: CondLoc, Opc: UseStrictCompare ? BO_LT : BO_LE,
11036 LHSExpr: IV.get(), RHSExpr: BoundCombUB);
11037 }
11038 // Loop increment (IV = IV + 1)
11039 SourceLocation IncLoc = AStmt->getBeginLoc();
11040 ExprResult Inc =
11041 SemaRef.BuildBinOp(S: CurScope, OpLoc: IncLoc, Opc: BO_Add, LHSExpr: IV.get(),
11042 RHSExpr: SemaRef.ActOnIntegerConstant(Loc: IncLoc, Val: 1).get());
11043 if (!Inc.isUsable())
11044 return 0;
11045 Inc = SemaRef.BuildBinOp(S: CurScope, OpLoc: IncLoc, Opc: BO_Assign, LHSExpr: IV.get(), RHSExpr: Inc.get());
11046 Inc = SemaRef.ActOnFinishFullExpr(Expr: Inc.get(), /*DiscardedValue=*/false);
11047 if (!Inc.isUsable())
11048 return 0;
11049
11050 // Increments for worksharing loops (LB = LB + ST; UB = UB + ST).
11051 // Used for directives with static scheduling.
11052 // In combined construct, add combined version that use CombLB and CombUB
11053 // base variables for the update
11054 ExprResult NextLB, NextUB, CombNextLB, CombNextUB;
11055 if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) ||
11056 isOpenMPGenericLoopDirective(DKind) ||
11057 isOpenMPDistributeDirective(DKind) ||
11058 isOpenMPLoopTransformationDirective(DKind)) {
11059 // LB + ST
11060 NextLB = SemaRef.BuildBinOp(S: CurScope, OpLoc: IncLoc, Opc: BO_Add, LHSExpr: LB.get(), RHSExpr: ST.get());
11061 if (!NextLB.isUsable())
11062 return 0;
11063 // LB = LB + ST
11064 NextLB =
11065 SemaRef.BuildBinOp(S: CurScope, OpLoc: IncLoc, Opc: BO_Assign, LHSExpr: LB.get(), RHSExpr: NextLB.get());
11066 NextLB =
11067 SemaRef.ActOnFinishFullExpr(Expr: NextLB.get(), /*DiscardedValue=*/false);
11068 if (!NextLB.isUsable())
11069 return 0;
11070 // UB + ST
11071 NextUB = SemaRef.BuildBinOp(S: CurScope, OpLoc: IncLoc, Opc: BO_Add, LHSExpr: UB.get(), RHSExpr: ST.get());
11072 if (!NextUB.isUsable())
11073 return 0;
11074 // UB = UB + ST
11075 NextUB =
11076 SemaRef.BuildBinOp(S: CurScope, OpLoc: IncLoc, Opc: BO_Assign, LHSExpr: UB.get(), RHSExpr: NextUB.get());
11077 NextUB =
11078 SemaRef.ActOnFinishFullExpr(Expr: NextUB.get(), /*DiscardedValue=*/false);
11079 if (!NextUB.isUsable())
11080 return 0;
11081 if (isOpenMPLoopBoundSharingDirective(Kind: DKind)) {
11082 CombNextLB =
11083 SemaRef.BuildBinOp(S: CurScope, OpLoc: IncLoc, Opc: BO_Add, LHSExpr: CombLB.get(), RHSExpr: ST.get());
11084 if (!NextLB.isUsable())
11085 return 0;
11086 // LB = LB + ST
11087 CombNextLB = SemaRef.BuildBinOp(S: CurScope, OpLoc: IncLoc, Opc: BO_Assign, LHSExpr: CombLB.get(),
11088 RHSExpr: CombNextLB.get());
11089 CombNextLB = SemaRef.ActOnFinishFullExpr(Expr: CombNextLB.get(),
11090 /*DiscardedValue=*/false);
11091 if (!CombNextLB.isUsable())
11092 return 0;
11093 // UB + ST
11094 CombNextUB =
11095 SemaRef.BuildBinOp(S: CurScope, OpLoc: IncLoc, Opc: BO_Add, LHSExpr: CombUB.get(), RHSExpr: ST.get());
11096 if (!CombNextUB.isUsable())
11097 return 0;
11098 // UB = UB + ST
11099 CombNextUB = SemaRef.BuildBinOp(S: CurScope, OpLoc: IncLoc, Opc: BO_Assign, LHSExpr: CombUB.get(),
11100 RHSExpr: CombNextUB.get());
11101 CombNextUB = SemaRef.ActOnFinishFullExpr(Expr: CombNextUB.get(),
11102 /*DiscardedValue=*/false);
11103 if (!CombNextUB.isUsable())
11104 return 0;
11105 }
11106 }
11107
11108 // Create increment expression for distribute loop when combined in a same
11109 // directive with for as IV = IV + ST; ensure upper bound expression based
11110 // on PrevUB instead of NumIterations - used to implement 'for' when found
11111 // in combination with 'distribute', like in 'distribute parallel for'
11112 SourceLocation DistIncLoc = AStmt->getBeginLoc();
11113 ExprResult DistCond, DistInc, PrevEUB, ParForInDistCond;
11114 if (isOpenMPLoopBoundSharingDirective(Kind: DKind)) {
11115 DistCond = SemaRef.BuildBinOp(
11116 S: CurScope, OpLoc: CondLoc, Opc: UseStrictCompare ? BO_LT : BO_LE, LHSExpr: IV.get(), RHSExpr: BoundUB);
11117 assert(DistCond.isUsable() && "distribute cond expr was not built");
11118
11119 DistInc =
11120 SemaRef.BuildBinOp(S: CurScope, OpLoc: DistIncLoc, Opc: BO_Add, LHSExpr: IV.get(), RHSExpr: ST.get());
11121 assert(DistInc.isUsable() && "distribute inc expr was not built");
11122 DistInc = SemaRef.BuildBinOp(S: CurScope, OpLoc: DistIncLoc, Opc: BO_Assign, LHSExpr: IV.get(),
11123 RHSExpr: DistInc.get());
11124 DistInc =
11125 SemaRef.ActOnFinishFullExpr(Expr: DistInc.get(), /*DiscardedValue=*/false);
11126 assert(DistInc.isUsable() && "distribute inc expr was not built");
11127
11128 // Build expression: UB = min(UB, prevUB) for #for in composite or combined
11129 // construct
11130 ExprResult NewPrevUB = PrevUB;
11131 SourceLocation DistEUBLoc = AStmt->getBeginLoc();
11132 if (!SemaRef.Context.hasSameType(T1: UB.get()->getType(),
11133 T2: PrevUB.get()->getType())) {
11134 NewPrevUB = SemaRef.BuildCStyleCastExpr(
11135 LParenLoc: DistEUBLoc,
11136 Ty: SemaRef.Context.getTrivialTypeSourceInfo(T: UB.get()->getType()),
11137 RParenLoc: DistEUBLoc, Op: NewPrevUB.get());
11138 if (!NewPrevUB.isUsable())
11139 return 0;
11140 }
11141 ExprResult IsUBGreater = SemaRef.BuildBinOp(S: CurScope, OpLoc: DistEUBLoc, Opc: BO_GT,
11142 LHSExpr: UB.get(), RHSExpr: NewPrevUB.get());
11143 ExprResult CondOp = SemaRef.ActOnConditionalOp(
11144 QuestionLoc: DistEUBLoc, ColonLoc: DistEUBLoc, CondExpr: IsUBGreater.get(), LHSExpr: NewPrevUB.get(), RHSExpr: UB.get());
11145 PrevEUB = SemaRef.BuildBinOp(S: CurScope, OpLoc: DistIncLoc, Opc: BO_Assign, LHSExpr: UB.get(),
11146 RHSExpr: CondOp.get());
11147 PrevEUB =
11148 SemaRef.ActOnFinishFullExpr(Expr: PrevEUB.get(), /*DiscardedValue=*/false);
11149
11150 // Build IV <= PrevUB or IV < PrevUB + 1 for unsigned IV to be used in
11151 // parallel for is in combination with a distribute directive with
11152 // schedule(static, 1)
11153 Expr *BoundPrevUB = PrevUB.get();
11154 if (UseStrictCompare) {
11155 BoundPrevUB =
11156 SemaRef
11157 .BuildBinOp(
11158 S: CurScope, OpLoc: CondLoc, Opc: BO_Add, LHSExpr: BoundPrevUB,
11159 RHSExpr: SemaRef.ActOnIntegerConstant(Loc: SourceLocation(), Val: 1).get())
11160 .get();
11161 BoundPrevUB =
11162 SemaRef.ActOnFinishFullExpr(Expr: BoundPrevUB, /*DiscardedValue=*/false)
11163 .get();
11164 }
11165 ParForInDistCond =
11166 SemaRef.BuildBinOp(S: CurScope, OpLoc: CondLoc, Opc: UseStrictCompare ? BO_LT : BO_LE,
11167 LHSExpr: IV.get(), RHSExpr: BoundPrevUB);
11168 }
11169
11170 // Build updates and final values of the loop counters.
11171 bool HasErrors = false;
11172 Built.Counters.resize(N: NestedLoopCount);
11173 Built.Inits.resize(N: NestedLoopCount);
11174 Built.Updates.resize(N: NestedLoopCount);
11175 Built.Finals.resize(N: NestedLoopCount);
11176 Built.DependentCounters.resize(N: NestedLoopCount);
11177 Built.DependentInits.resize(N: NestedLoopCount);
11178 Built.FinalsConditions.resize(N: NestedLoopCount);
11179 {
11180 // We implement the following algorithm for obtaining the
11181 // original loop iteration variable values based on the
11182 // value of the collapsed loop iteration variable IV.
11183 //
11184 // Let n+1 be the number of collapsed loops in the nest.
11185 // Iteration variables (I0, I1, .... In)
11186 // Iteration counts (N0, N1, ... Nn)
11187 //
11188 // Acc = IV;
11189 //
11190 // To compute Ik for loop k, 0 <= k <= n, generate:
11191 // Prod = N(k+1) * N(k+2) * ... * Nn;
11192 // Ik = Acc / Prod;
11193 // Acc -= Ik * Prod;
11194 //
11195 ExprResult Acc = IV;
11196 for (unsigned int Cnt = 0; Cnt < NestedLoopCount; ++Cnt) {
11197 LoopIterationSpace &IS = IterSpaces[Cnt];
11198 SourceLocation UpdLoc = IS.IncSrcRange.getBegin();
11199 ExprResult Iter;
11200
11201 // Compute prod
11202 ExprResult Prod = SemaRef.ActOnIntegerConstant(Loc: SourceLocation(), Val: 1).get();
11203 for (unsigned int K = Cnt + 1; K < NestedLoopCount; ++K)
11204 Prod = SemaRef.BuildBinOp(S: CurScope, OpLoc: UpdLoc, Opc: BO_Mul, LHSExpr: Prod.get(),
11205 RHSExpr: IterSpaces[K].NumIterations);
11206
11207 // Iter = Acc / Prod
11208 // If there is at least one more inner loop to avoid
11209 // multiplication by 1.
11210 if (Cnt + 1 < NestedLoopCount)
11211 Iter =
11212 SemaRef.BuildBinOp(S: CurScope, OpLoc: UpdLoc, Opc: BO_Div, LHSExpr: Acc.get(), RHSExpr: Prod.get());
11213 else
11214 Iter = Acc;
11215 if (!Iter.isUsable()) {
11216 HasErrors = true;
11217 break;
11218 }
11219
11220 // Update Acc:
11221 // Acc -= Iter * Prod
11222 // Check if there is at least one more inner loop to avoid
11223 // multiplication by 1.
11224 if (Cnt + 1 < NestedLoopCount)
11225 Prod = SemaRef.BuildBinOp(S: CurScope, OpLoc: UpdLoc, Opc: BO_Mul, LHSExpr: Iter.get(),
11226 RHSExpr: Prod.get());
11227 else
11228 Prod = Iter;
11229 Acc = SemaRef.BuildBinOp(S: CurScope, OpLoc: UpdLoc, Opc: BO_Sub, LHSExpr: Acc.get(), RHSExpr: Prod.get());
11230
11231 // Build update: IS.CounterVar(Private) = IS.Start + Iter * IS.Step
11232 auto *VD = cast<VarDecl>(Val: cast<DeclRefExpr>(Val: IS.CounterVar)->getDecl());
11233 DeclRefExpr *CounterVar = buildDeclRefExpr(
11234 S&: SemaRef, D: VD, Ty: IS.CounterVar->getType(), Loc: IS.CounterVar->getExprLoc(),
11235 /*RefersToCapture=*/true);
11236 ExprResult Init =
11237 buildCounterInit(SemaRef, S: CurScope, Loc: UpdLoc, VarRef: CounterVar,
11238 Start: IS.CounterInit, IsNonRectangularLB: IS.IsNonRectangularLB, Captures);
11239 if (!Init.isUsable()) {
11240 HasErrors = true;
11241 break;
11242 }
11243 ExprResult Update = buildCounterUpdate(
11244 SemaRef, S: CurScope, Loc: UpdLoc, VarRef: CounterVar, Start: IS.CounterInit, Iter,
11245 Step: IS.CounterStep, Subtract: IS.Subtract, IsNonRectangularLB: IS.IsNonRectangularLB, Captures: &Captures);
11246 if (!Update.isUsable()) {
11247 HasErrors = true;
11248 break;
11249 }
11250
11251 // Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step
11252 ExprResult Final =
11253 buildCounterUpdate(SemaRef, S: CurScope, Loc: UpdLoc, VarRef: CounterVar,
11254 Start: IS.CounterInit, Iter: IS.NumIterations, Step: IS.CounterStep,
11255 Subtract: IS.Subtract, IsNonRectangularLB: IS.IsNonRectangularLB, Captures: &Captures);
11256 if (!Final.isUsable()) {
11257 HasErrors = true;
11258 break;
11259 }
11260
11261 if (!Update.isUsable() || !Final.isUsable()) {
11262 HasErrors = true;
11263 break;
11264 }
11265 // Save results
11266 Built.Counters[Cnt] = IS.CounterVar;
11267 Built.PrivateCounters[Cnt] = IS.PrivateCounterVar;
11268 Built.Inits[Cnt] = Init.get();
11269 Built.Updates[Cnt] = Update.get();
11270 Built.Finals[Cnt] = Final.get();
11271 Built.DependentCounters[Cnt] = nullptr;
11272 Built.DependentInits[Cnt] = nullptr;
11273 // Transfer the body-guard condition: the loop condition for
11274 // non-rectangular loops, the overshoot predicate for reinterpreted tiles,
11275 // null otherwise.
11276 Built.FinalsConditions[Cnt] = IS.FinalCondition;
11277 if (IS.IsNonRectangularLB || IS.IsNonRectangularUB) {
11278 Built.DependentCounters[Cnt] = Built.Counters[IS.LoopDependentIdx - 1];
11279 Built.DependentInits[Cnt] = Built.Inits[IS.LoopDependentIdx - 1];
11280 }
11281 }
11282 }
11283
11284 if (HasErrors)
11285 return 0;
11286
11287 // Save results
11288 Built.IterationVarRef = IV.get();
11289 Built.LastIteration = LastIteration.get();
11290 Built.NumIterations = NumIterations.get();
11291 Built.CalcLastIteration = SemaRef
11292 .ActOnFinishFullExpr(Expr: CalcLastIteration.get(),
11293 /*DiscardedValue=*/false)
11294 .get();
11295 Built.PreCond = PreCond.get();
11296 Built.PreInits = buildPreInits(Context&: C, Captures);
11297 Built.Cond = Cond.get();
11298 Built.Init = Init.get();
11299 Built.Inc = Inc.get();
11300 Built.LB = LB.get();
11301 Built.UB = UB.get();
11302 Built.IL = IL.get();
11303 Built.ST = ST.get();
11304 Built.EUB = EUB.get();
11305 Built.NLB = NextLB.get();
11306 Built.NUB = NextUB.get();
11307 Built.PrevLB = PrevLB.get();
11308 Built.PrevUB = PrevUB.get();
11309 Built.DistInc = DistInc.get();
11310 Built.PrevEUB = PrevEUB.get();
11311 Built.DistCombinedFields.LB = CombLB.get();
11312 Built.DistCombinedFields.UB = CombUB.get();
11313 Built.DistCombinedFields.EUB = CombEUB.get();
11314 Built.DistCombinedFields.Init = CombInit.get();
11315 Built.DistCombinedFields.Cond = CombCond.get();
11316 Built.DistCombinedFields.NLB = CombNextLB.get();
11317 Built.DistCombinedFields.NUB = CombNextUB.get();
11318 Built.DistCombinedFields.DistCond = CombDistCond.get();
11319 Built.DistCombinedFields.ParForInDistCond = ParForInDistCond.get();
11320
11321 return NestedLoopCount;
11322}
11323
11324static Expr *getCollapseNumberExpr(ArrayRef<OMPClause *> Clauses) {
11325 auto CollapseClauses =
11326 OMPExecutableDirective::getClausesOfKind<OMPCollapseClause>(Clauses);
11327 if (CollapseClauses.begin() != CollapseClauses.end())
11328 return (*CollapseClauses.begin())->getNumForLoops();
11329 return nullptr;
11330}
11331
11332static Expr *getOrderedNumberExpr(ArrayRef<OMPClause *> Clauses) {
11333 auto OrderedClauses =
11334 OMPExecutableDirective::getClausesOfKind<OMPOrderedClause>(Clauses);
11335 if (OrderedClauses.begin() != OrderedClauses.end())
11336 return (*OrderedClauses.begin())->getNumForLoops();
11337 return nullptr;
11338}
11339
11340static bool checkSimdlenSafelenSpecified(Sema &S,
11341 const ArrayRef<OMPClause *> Clauses) {
11342 const OMPSafelenClause *Safelen = nullptr;
11343 const OMPSimdlenClause *Simdlen = nullptr;
11344
11345 for (const OMPClause *Clause : Clauses) {
11346 if (Clause->getClauseKind() == OMPC_safelen)
11347 Safelen = cast<OMPSafelenClause>(Val: Clause);
11348 else if (Clause->getClauseKind() == OMPC_simdlen)
11349 Simdlen = cast<OMPSimdlenClause>(Val: Clause);
11350 if (Safelen && Simdlen)
11351 break;
11352 }
11353
11354 if (Simdlen && Safelen) {
11355 const Expr *SimdlenLength = Simdlen->getSimdlen();
11356 const Expr *SafelenLength = Safelen->getSafelen();
11357 if (SimdlenLength->isValueDependent() || SimdlenLength->isTypeDependent() ||
11358 SimdlenLength->isInstantiationDependent() ||
11359 SimdlenLength->containsUnexpandedParameterPack())
11360 return false;
11361 if (SafelenLength->isValueDependent() || SafelenLength->isTypeDependent() ||
11362 SafelenLength->isInstantiationDependent() ||
11363 SafelenLength->containsUnexpandedParameterPack())
11364 return false;
11365 Expr::EvalResult SimdlenResult, SafelenResult;
11366 SimdlenLength->EvaluateAsInt(Result&: SimdlenResult, Ctx: S.Context);
11367 SafelenLength->EvaluateAsInt(Result&: SafelenResult, Ctx: S.Context);
11368 llvm::APSInt SimdlenRes = SimdlenResult.Val.getInt();
11369 llvm::APSInt SafelenRes = SafelenResult.Val.getInt();
11370 // OpenMP 4.5 [2.8.1, simd Construct, Restrictions]
11371 // If both simdlen and safelen clauses are specified, the value of the
11372 // simdlen parameter must be less than or equal to the value of the safelen
11373 // parameter.
11374 if (llvm::APSInt::compareValues(I1: SimdlenRes, I2: SafelenRes) > 0) {
11375 S.Diag(Loc: SimdlenLength->getExprLoc(),
11376 DiagID: diag::err_omp_wrong_simdlen_safelen_values)
11377 << SimdlenLength->getSourceRange() << SafelenLength->getSourceRange();
11378 return true;
11379 }
11380 }
11381 return false;
11382}
11383
11384StmtResult SemaOpenMP::ActOnOpenMPSimdDirective(
11385 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
11386 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
11387 if (!AStmt)
11388 return StmtError();
11389
11390 CapturedStmt *CS = setBranchProtectedScope(SemaRef, DKind: OMPD_simd, AStmt);
11391
11392 assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
11393 OMPLoopBasedDirective::HelperExprs B;
11394 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
11395 // define the nested loops number.
11396 unsigned NestedLoopCount = checkOpenMPLoop(
11397 DKind: OMPD_simd, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses), OrderedLoopCountExpr: getOrderedNumberExpr(Clauses),
11398 AStmt: CS, SemaRef, DSA&: *DSAStack, VarsWithImplicitDSA, Built&: B);
11399 if (NestedLoopCount == 0)
11400 return StmtError();
11401
11402 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
11403 return StmtError();
11404
11405 if (checkSimdlenSafelenSpecified(S&: SemaRef, Clauses))
11406 return StmtError();
11407
11408 auto *SimdDirective = OMPSimdDirective::Create(
11409 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
11410 return SimdDirective;
11411}
11412
11413StmtResult SemaOpenMP::ActOnOpenMPForDirective(
11414 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
11415 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
11416 if (!AStmt)
11417 return StmtError();
11418
11419 assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
11420 OMPLoopBasedDirective::HelperExprs B;
11421 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
11422 // define the nested loops number.
11423 unsigned NestedLoopCount = checkOpenMPLoop(
11424 DKind: OMPD_for, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses), OrderedLoopCountExpr: getOrderedNumberExpr(Clauses),
11425 AStmt, SemaRef, DSA&: *DSAStack, VarsWithImplicitDSA, Built&: B);
11426 if (NestedLoopCount == 0)
11427 return StmtError();
11428
11429 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
11430 return StmtError();
11431
11432 auto *ForDirective = OMPForDirective::Create(
11433 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B,
11434 DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
11435 return ForDirective;
11436}
11437
11438StmtResult SemaOpenMP::ActOnOpenMPForSimdDirective(
11439 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
11440 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
11441 if (!AStmt)
11442 return StmtError();
11443
11444 CapturedStmt *CS = setBranchProtectedScope(SemaRef, DKind: OMPD_for_simd, AStmt);
11445
11446 assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
11447 OMPLoopBasedDirective::HelperExprs B;
11448 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
11449 // define the nested loops number.
11450 unsigned NestedLoopCount =
11451 checkOpenMPLoop(DKind: OMPD_for_simd, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
11452 OrderedLoopCountExpr: getOrderedNumberExpr(Clauses), AStmt: CS, SemaRef, DSA&: *DSAStack,
11453 VarsWithImplicitDSA, Built&: B);
11454 if (NestedLoopCount == 0)
11455 return StmtError();
11456
11457 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
11458 return StmtError();
11459
11460 if (checkSimdlenSafelenSpecified(S&: SemaRef, Clauses))
11461 return StmtError();
11462
11463 return OMPForSimdDirective::Create(C: getASTContext(), StartLoc, EndLoc,
11464 CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
11465}
11466
11467static bool checkSectionsDirective(Sema &SemaRef, OpenMPDirectiveKind DKind,
11468 Stmt *AStmt, DSAStackTy *Stack) {
11469 if (!AStmt)
11470 return true;
11471
11472 assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
11473 llvm::omp::Version OMPVersion = SemaRef.getLangOpts().getOpenMPVersion();
11474 auto BaseStmt = AStmt;
11475 while (auto *CS = dyn_cast_or_null<CapturedStmt>(Val: BaseStmt))
11476 BaseStmt = CS->getCapturedStmt();
11477 if (auto *C = dyn_cast_or_null<CompoundStmt>(Val: BaseStmt)) {
11478 auto S = C->children();
11479 if (S.begin() == S.end())
11480 return true;
11481 // All associated statements must be '#pragma omp section' except for
11482 // the first one.
11483 for (Stmt *SectionStmt : llvm::drop_begin(RangeOrContainer&: S)) {
11484 if (!SectionStmt || !isa<OMPSectionDirective>(Val: SectionStmt)) {
11485 if (SectionStmt)
11486 SemaRef.Diag(Loc: SectionStmt->getBeginLoc(),
11487 DiagID: diag::err_omp_sections_substmt_not_section)
11488 << getOpenMPDirectiveName(D: DKind, V: OMPVersion);
11489 return true;
11490 }
11491 cast<OMPSectionDirective>(Val: SectionStmt)
11492 ->setHasCancel(Stack->isCancelRegion());
11493 }
11494 } else {
11495 SemaRef.Diag(Loc: AStmt->getBeginLoc(), DiagID: diag::err_omp_sections_not_compound_stmt)
11496 << getOpenMPDirectiveName(D: DKind, V: OMPVersion);
11497 return true;
11498 }
11499 return false;
11500}
11501
11502StmtResult
11503SemaOpenMP::ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses,
11504 Stmt *AStmt, SourceLocation StartLoc,
11505 SourceLocation EndLoc) {
11506 if (checkSectionsDirective(SemaRef, DKind: OMPD_sections, AStmt, DSAStack))
11507 return StmtError();
11508
11509 SemaRef.setFunctionHasBranchProtectedScope();
11510
11511 return OMPSectionsDirective::Create(
11512 C: getASTContext(), StartLoc, EndLoc, Clauses, AssociatedStmt: AStmt,
11513 DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
11514}
11515
11516StmtResult SemaOpenMP::ActOnOpenMPSectionDirective(Stmt *AStmt,
11517 SourceLocation StartLoc,
11518 SourceLocation EndLoc) {
11519 if (!AStmt)
11520 return StmtError();
11521
11522 SemaRef.setFunctionHasBranchProtectedScope();
11523 DSAStack->setParentCancelRegion(DSAStack->isCancelRegion());
11524
11525 return OMPSectionDirective::Create(C: getASTContext(), StartLoc, EndLoc, AssociatedStmt: AStmt,
11526 DSAStack->isCancelRegion());
11527}
11528
11529static Expr *getDirectCallExpr(Expr *E) {
11530 E = E->IgnoreParenCasts()->IgnoreImplicit();
11531 if (auto *CE = dyn_cast<CallExpr>(Val: E))
11532 if (CE->getDirectCallee())
11533 return E;
11534 return nullptr;
11535}
11536
11537StmtResult
11538SemaOpenMP::ActOnOpenMPDispatchDirective(ArrayRef<OMPClause *> Clauses,
11539 Stmt *AStmt, SourceLocation StartLoc,
11540 SourceLocation EndLoc) {
11541 if (!AStmt)
11542 return StmtError();
11543
11544 Stmt *S = cast<CapturedStmt>(Val: AStmt)->getCapturedStmt();
11545
11546 // 5.1 OpenMP
11547 // expression-stmt : an expression statement with one of the following forms:
11548 // expression = target-call ( [expression-list] );
11549 // target-call ( [expression-list] );
11550
11551 SourceLocation TargetCallLoc;
11552
11553 if (!SemaRef.CurContext->isDependentContext()) {
11554 Expr *TargetCall = nullptr;
11555
11556 auto *E = dyn_cast<Expr>(Val: S);
11557 if (!E) {
11558 Diag(Loc: S->getBeginLoc(), DiagID: diag::err_omp_dispatch_statement_call);
11559 return StmtError();
11560 }
11561
11562 E = E->IgnoreParenCasts()->IgnoreImplicit();
11563
11564 if (auto *BO = dyn_cast<BinaryOperator>(Val: E)) {
11565 if (BO->getOpcode() == BO_Assign)
11566 TargetCall = getDirectCallExpr(E: BO->getRHS());
11567 } else {
11568 if (auto *COCE = dyn_cast<CXXOperatorCallExpr>(Val: E))
11569 if (COCE->getOperator() == OO_Equal)
11570 TargetCall = getDirectCallExpr(E: COCE->getArg(Arg: 1));
11571 if (!TargetCall)
11572 TargetCall = getDirectCallExpr(E);
11573 }
11574 if (!TargetCall) {
11575 Diag(Loc: E->getBeginLoc(), DiagID: diag::err_omp_dispatch_statement_call);
11576 return StmtError();
11577 }
11578 TargetCallLoc = TargetCall->getExprLoc();
11579 }
11580
11581 SemaRef.setFunctionHasBranchProtectedScope();
11582
11583 return OMPDispatchDirective::Create(C: getASTContext(), StartLoc, EndLoc,
11584 Clauses, AssociatedStmt: AStmt, TargetCallLoc);
11585}
11586
11587static bool checkGenericLoopLastprivate(Sema &S, ArrayRef<OMPClause *> Clauses,
11588 OpenMPDirectiveKind K,
11589 DSAStackTy *Stack) {
11590 bool ErrorFound = false;
11591 for (OMPClause *C : Clauses) {
11592 if (auto *LPC = dyn_cast<OMPLastprivateClause>(Val: C)) {
11593 for (Expr *RefExpr : LPC->varlist()) {
11594 SourceLocation ELoc;
11595 SourceRange ERange;
11596 Expr *SimpleRefExpr = RefExpr;
11597 auto Res = getPrivateItem(S, RefExpr&: SimpleRefExpr, ELoc, ERange);
11598 if (ValueDecl *D = Res.first) {
11599 auto &&Info = Stack->isLoopControlVariable(D);
11600 if (!Info.first) {
11601 llvm::omp::Version OMPVersion = S.getLangOpts().getOpenMPVersion();
11602 S.Diag(Loc: ELoc, DiagID: diag::err_omp_lastprivate_loop_var_non_loop_iteration)
11603 << getOpenMPDirectiveName(D: K, V: OMPVersion);
11604 ErrorFound = true;
11605 }
11606 }
11607 }
11608 }
11609 }
11610 return ErrorFound;
11611}
11612
11613StmtResult SemaOpenMP::ActOnOpenMPGenericLoopDirective(
11614 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
11615 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
11616 if (!AStmt)
11617 return StmtError();
11618
11619 // OpenMP 5.1 [2.11.7, loop construct, Restrictions]
11620 // A list item may not appear in a lastprivate clause unless it is the
11621 // loop iteration variable of a loop that is associated with the construct.
11622 if (checkGenericLoopLastprivate(S&: SemaRef, Clauses, K: OMPD_loop, DSAStack))
11623 return StmtError();
11624
11625 setBranchProtectedScope(SemaRef, DKind: OMPD_loop, AStmt);
11626
11627 OMPLoopDirective::HelperExprs B;
11628 // In presence of clause 'collapse', it will define the nested loops number.
11629 unsigned NestedLoopCount = checkOpenMPLoop(
11630 DKind: OMPD_loop, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses), OrderedLoopCountExpr: getOrderedNumberExpr(Clauses),
11631 AStmt, SemaRef, DSA&: *DSAStack, VarsWithImplicitDSA, Built&: B);
11632 if (NestedLoopCount == 0)
11633 return StmtError();
11634
11635 assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) &&
11636 "omp loop exprs were not built");
11637
11638 return OMPGenericLoopDirective::Create(C: getASTContext(), StartLoc, EndLoc,
11639 CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
11640}
11641
11642/// Check the number of expressions specified in a multidimensional clause and
11643/// return whether an error was encountered.
11644static bool validateMultidimClauseExprs(
11645 SemaBase &SemaRef, OpenMPClauseKind ClauseKind,
11646 SourceLocation ClauseBeginLoc, ArrayRef<const Expr *> ClauseVarList,
11647 const Expr *DimsModifierExpr, const OMPXBareClause *BareClause = nullptr) {
11648 const uint64_t NumVars = ClauseVarList.size();
11649
11650 // The ompx_bare clause allows up to three expressions.
11651 if (BareClause) {
11652 if (NumVars > 3) {
11653 SemaRef.Diag(Loc: ClauseBeginLoc,
11654 DiagID: diag::err_ompx_more_than_three_expr_not_allowed)
11655 << getOpenMPClauseName(C: ClauseKind);
11656 return true;
11657 }
11658 return false;
11659 }
11660
11661 // By default, only one expression accepted.
11662 uint64_t MaxExprs = 1;
11663 if (DimsModifierExpr) {
11664 // Cannot verify the expected size yet.
11665 if (DimsModifierExpr->isInstantiationDependent())
11666 return false;
11667
11668 // The dims modifier determines the exact number of expressions.
11669 MaxExprs = DimsModifierExpr->EvaluateKnownConstInt(Ctx: SemaRef.getASTContext())
11670 .getExtValue();
11671 }
11672
11673 if (NumVars != MaxExprs) {
11674 SemaRef.Diag(Loc: ClauseBeginLoc, DiagID: diag::err_omp_unexpected_num_exprs)
11675 << getOpenMPClauseName(C: ClauseKind) << MaxExprs << NumVars;
11676 return true;
11677 }
11678 if (NumVars > 3) {
11679 SemaRef.Diag(Loc: ClauseBeginLoc, DiagID: diag::err_omp_max_three_exprs)
11680 << getOpenMPClauseName(C: ClauseKind);
11681 return true;
11682 }
11683 return false;
11684}
11685
11686/// Check the number of expressions specified in a multidimensional clause and
11687/// return whether an error was encountered.
11688template <typename ClauseT>
11689static bool validateMultidimClauseExprs(SemaBase &SemaRef,
11690 const ClauseT *Clause,
11691 const OMPXBareClause *BareClause) {
11692 if (!Clause)
11693 return false;
11694 return validateMultidimClauseExprs(
11695 SemaRef, Clause->getClauseKind(), Clause->getBeginLoc(),
11696 Clause->getVarRefs(), Clause->getDimsModifierExpr(), BareClause);
11697}
11698
11699/// Check the number of expressions specified in clauses that can contain
11700/// multidimensional values, e.g., num_teams and thread_limit. The function
11701/// returns true on error.
11702static bool validateMultidimClauses(SemaBase &SemaRef,
11703 ArrayRef<OMPClause *> Clauses,
11704 bool MayHaveBareClause = false) {
11705 auto BareClauseIt =
11706 MayHaveBareClause ? llvm::find_if(Range&: Clauses, P: llvm::IsaPred<OMPXBareClause>)
11707 : Clauses.end();
11708 auto ThreadLimitIt =
11709 llvm::find_if(Range&: Clauses, P: llvm::IsaPred<OMPThreadLimitClause>);
11710 auto NumTeamsIt = llvm::find_if(Range&: Clauses, P: llvm::IsaPred<OMPNumTeamsClause>);
11711
11712 const auto *BareClause = BareClauseIt != Clauses.end()
11713 ? cast<OMPXBareClause>(Val: *BareClauseIt)
11714 : nullptr;
11715 const auto *ThreadLimitClause =
11716 ThreadLimitIt != Clauses.end()
11717 ? cast<OMPThreadLimitClause>(Val: *ThreadLimitIt)
11718 : nullptr;
11719 const auto *NumTeamsClause = NumTeamsIt != Clauses.end()
11720 ? cast<OMPNumTeamsClause>(Val: *NumTeamsIt)
11721 : nullptr;
11722
11723 if (BareClause) {
11724 if (!NumTeamsClause || !ThreadLimitClause) {
11725 SemaRef.Diag(Loc: BareClause->getBeginLoc(), DiagID: diag::err_ompx_bare_no_grid);
11726 return true;
11727 }
11728 if (ThreadLimitClause->getModifier() == OMPC_THREADLIMIT_dims ||
11729 NumTeamsClause->getModifier() == OMPC_NUMTEAMS_dims) {
11730 SemaRef.Diag(Loc: BareClause->getBeginLoc(), DiagID: diag::err_ompx_bare_no_dims);
11731 return true;
11732 }
11733 }
11734 return validateMultidimClauseExprs(SemaRef, Clause: ThreadLimitClause, BareClause) ||
11735 validateMultidimClauseExprs(SemaRef, Clause: NumTeamsClause, BareClause);
11736}
11737
11738StmtResult SemaOpenMP::ActOnOpenMPTeamsGenericLoopDirective(
11739 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
11740 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
11741 if (!AStmt)
11742 return StmtError();
11743
11744 if (validateMultidimClauses(SemaRef&: *this, Clauses))
11745 return StmtError();
11746
11747 if (checkClausesForDecompositionConflicts(SemaRef, DKind: OMPD_teams_loop, Clauses))
11748 return StmtError();
11749
11750 // OpenMP 5.1 [2.11.7, loop construct, Restrictions]
11751 // A list item may not appear in a lastprivate clause unless it is the
11752 // loop iteration variable of a loop that is associated with the construct.
11753 if (checkGenericLoopLastprivate(S&: SemaRef, Clauses, K: OMPD_teams_loop, DSAStack))
11754 return StmtError();
11755
11756 CapturedStmt *CS = setBranchProtectedScope(SemaRef, DKind: OMPD_teams_loop, AStmt);
11757
11758 OMPLoopDirective::HelperExprs B;
11759 // In presence of clause 'collapse', it will define the nested loops number.
11760 unsigned NestedLoopCount =
11761 checkOpenMPLoop(DKind: OMPD_teams_loop, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
11762 /*OrderedLoopCountExpr=*/nullptr, AStmt: CS, SemaRef, DSA&: *DSAStack,
11763 VarsWithImplicitDSA, Built&: B);
11764 if (NestedLoopCount == 0)
11765 return StmtError();
11766
11767 assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) &&
11768 "omp loop exprs were not built");
11769
11770 DSAStack->setParentTeamsRegionLoc(StartLoc);
11771
11772 return OMPTeamsGenericLoopDirective::Create(
11773 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
11774}
11775
11776StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsGenericLoopDirective(
11777 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
11778 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
11779 if (!AStmt)
11780 return StmtError();
11781
11782 if (validateMultidimClauses(SemaRef&: *this, Clauses))
11783 return StmtError();
11784
11785 // OpenMP 5.1 [2.11.7, loop construct, Restrictions]
11786 // A list item may not appear in a lastprivate clause unless it is the
11787 // loop iteration variable of a loop that is associated with the construct.
11788 if (checkGenericLoopLastprivate(S&: SemaRef, Clauses, K: OMPD_target_teams_loop,
11789 DSAStack))
11790 return StmtError();
11791
11792 if (checkClausesForDecompositionConflicts(SemaRef, DKind: OMPD_target_teams_loop,
11793 Clauses))
11794 return StmtError();
11795
11796 if (checkOriginalVarMappedButOnlyBindingsUsed(SemaRef, Clauses, Body: AStmt))
11797 return StmtError();
11798
11799 CapturedStmt *CS =
11800 setBranchProtectedScope(SemaRef, DKind: OMPD_target_teams_loop, AStmt);
11801
11802 OMPLoopDirective::HelperExprs B;
11803 // In presence of clause 'collapse', it will define the nested loops number.
11804 unsigned NestedLoopCount =
11805 checkOpenMPLoop(DKind: OMPD_target_teams_loop, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
11806 /*OrderedLoopCountExpr=*/nullptr, AStmt: CS, SemaRef, DSA&: *DSAStack,
11807 VarsWithImplicitDSA, Built&: B);
11808 if (NestedLoopCount == 0)
11809 return StmtError();
11810
11811 assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) &&
11812 "omp loop exprs were not built");
11813
11814 return OMPTargetTeamsGenericLoopDirective::Create(
11815 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B,
11816 CanBeParallelFor: teamsLoopCanBeParallelFor(AStmt, SemaRef));
11817}
11818
11819StmtResult SemaOpenMP::ActOnOpenMPParallelGenericLoopDirective(
11820 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
11821 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
11822 if (!AStmt)
11823 return StmtError();
11824
11825 // OpenMP 5.1 [2.11.7, loop construct, Restrictions]
11826 // A list item may not appear in a lastprivate clause unless it is the
11827 // loop iteration variable of a loop that is associated with the construct.
11828 if (checkGenericLoopLastprivate(S&: SemaRef, Clauses, K: OMPD_parallel_loop,
11829 DSAStack))
11830 return StmtError();
11831
11832 CapturedStmt *CS =
11833 setBranchProtectedScope(SemaRef, DKind: OMPD_parallel_loop, AStmt);
11834
11835 OMPLoopDirective::HelperExprs B;
11836 // In presence of clause 'collapse', it will define the nested loops number.
11837 unsigned NestedLoopCount =
11838 checkOpenMPLoop(DKind: OMPD_parallel_loop, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
11839 /*OrderedLoopCountExpr=*/nullptr, AStmt: CS, SemaRef, DSA&: *DSAStack,
11840 VarsWithImplicitDSA, Built&: B);
11841 if (NestedLoopCount == 0)
11842 return StmtError();
11843
11844 assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) &&
11845 "omp loop exprs were not built");
11846
11847 return OMPParallelGenericLoopDirective::Create(
11848 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
11849}
11850
11851StmtResult SemaOpenMP::ActOnOpenMPTargetParallelGenericLoopDirective(
11852 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
11853 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
11854 if (!AStmt)
11855 return StmtError();
11856
11857 if (validateMultidimClauses(SemaRef&: *this, Clauses))
11858 return StmtError();
11859
11860 if (checkClausesForDecompositionConflicts(SemaRef, DKind: OMPD_target_parallel_loop,
11861 Clauses))
11862 return StmtError();
11863
11864 if (checkOriginalVarMappedButOnlyBindingsUsed(SemaRef, Clauses, Body: AStmt))
11865 return StmtError();
11866
11867 // OpenMP 5.1 [2.11.7, loop construct, Restrictions]
11868 // A list item may not appear in a lastprivate clause unless it is the
11869 // loop iteration variable of a loop that is associated with the construct.
11870 if (checkGenericLoopLastprivate(S&: SemaRef, Clauses, K: OMPD_target_parallel_loop,
11871 DSAStack))
11872 return StmtError();
11873
11874 CapturedStmt *CS =
11875 setBranchProtectedScope(SemaRef, DKind: OMPD_target_parallel_loop, AStmt);
11876
11877 OMPLoopDirective::HelperExprs B;
11878 // In presence of clause 'collapse', it will define the nested loops number.
11879 unsigned NestedLoopCount =
11880 checkOpenMPLoop(DKind: OMPD_target_parallel_loop, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
11881 /*OrderedLoopCountExpr=*/nullptr, AStmt: CS, SemaRef, DSA&: *DSAStack,
11882 VarsWithImplicitDSA, Built&: B);
11883 if (NestedLoopCount == 0)
11884 return StmtError();
11885
11886 assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) &&
11887 "omp loop exprs were not built");
11888
11889 return OMPTargetParallelGenericLoopDirective::Create(
11890 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
11891}
11892
11893StmtResult SemaOpenMP::ActOnOpenMPSingleDirective(ArrayRef<OMPClause *> Clauses,
11894 Stmt *AStmt,
11895 SourceLocation StartLoc,
11896 SourceLocation EndLoc) {
11897 if (!AStmt)
11898 return StmtError();
11899
11900 assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
11901
11902 SemaRef.setFunctionHasBranchProtectedScope();
11903
11904 // OpenMP [2.7.3, single Construct, Restrictions]
11905 // The copyprivate clause must not be used with the nowait clause.
11906 const OMPClause *Nowait = nullptr;
11907 const OMPClause *Copyprivate = nullptr;
11908 for (const OMPClause *Clause : Clauses) {
11909 if (Clause->getClauseKind() == OMPC_nowait)
11910 Nowait = Clause;
11911 else if (Clause->getClauseKind() == OMPC_copyprivate)
11912 Copyprivate = Clause;
11913 if (Copyprivate && Nowait) {
11914 Diag(Loc: Copyprivate->getBeginLoc(),
11915 DiagID: diag::err_omp_single_copyprivate_with_nowait);
11916 Diag(Loc: Nowait->getBeginLoc(), DiagID: diag::note_omp_nowait_clause_here);
11917 return StmtError();
11918 }
11919 }
11920
11921 return OMPSingleDirective::Create(C: getASTContext(), StartLoc, EndLoc, Clauses,
11922 AssociatedStmt: AStmt);
11923}
11924
11925StmtResult SemaOpenMP::ActOnOpenMPMasterDirective(Stmt *AStmt,
11926 SourceLocation StartLoc,
11927 SourceLocation EndLoc) {
11928 if (!AStmt)
11929 return StmtError();
11930
11931 SemaRef.setFunctionHasBranchProtectedScope();
11932
11933 return OMPMasterDirective::Create(C: getASTContext(), StartLoc, EndLoc, AssociatedStmt: AStmt);
11934}
11935
11936StmtResult SemaOpenMP::ActOnOpenMPMaskedDirective(ArrayRef<OMPClause *> Clauses,
11937 Stmt *AStmt,
11938 SourceLocation StartLoc,
11939 SourceLocation EndLoc) {
11940 if (!AStmt)
11941 return StmtError();
11942
11943 SemaRef.setFunctionHasBranchProtectedScope();
11944
11945 return OMPMaskedDirective::Create(C: getASTContext(), StartLoc, EndLoc, Clauses,
11946 AssociatedStmt: AStmt);
11947}
11948
11949StmtResult SemaOpenMP::ActOnOpenMPCriticalDirective(
11950 const DeclarationNameInfo &DirName, ArrayRef<OMPClause *> Clauses,
11951 Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) {
11952 if (!AStmt)
11953 return StmtError();
11954
11955 bool ErrorFound = false;
11956 llvm::APSInt Hint;
11957 SourceLocation HintLoc;
11958 bool DependentHint = false;
11959 for (const OMPClause *C : Clauses) {
11960 if (C->getClauseKind() == OMPC_hint) {
11961 if (!DirName.getName()) {
11962 Diag(Loc: C->getBeginLoc(), DiagID: diag::err_omp_hint_clause_no_name);
11963 ErrorFound = true;
11964 }
11965 Expr *E = cast<OMPHintClause>(Val: C)->getHint();
11966 if (E->isTypeDependent() || E->isValueDependent() ||
11967 E->isInstantiationDependent()) {
11968 DependentHint = true;
11969 } else {
11970 Hint = E->EvaluateKnownConstInt(Ctx: getASTContext());
11971 HintLoc = C->getBeginLoc();
11972 }
11973 }
11974 }
11975 if (ErrorFound)
11976 return StmtError();
11977 const auto Pair = DSAStack->getCriticalWithHint(Name: DirName);
11978 if (Pair.first && DirName.getName() && !DependentHint) {
11979 if (llvm::APSInt::compareValues(I1: Hint, I2: Pair.second) != 0) {
11980 Diag(Loc: StartLoc, DiagID: diag::err_omp_critical_with_hint);
11981 if (HintLoc.isValid())
11982 Diag(Loc: HintLoc, DiagID: diag::note_omp_critical_hint_here)
11983 << 0 << toString(I: Hint, /*Radix=*/10, /*Signed=*/false);
11984 else
11985 Diag(Loc: StartLoc, DiagID: diag::note_omp_critical_no_hint) << 0;
11986 if (const auto *C = Pair.first->getSingleClause<OMPHintClause>()) {
11987 Diag(Loc: C->getBeginLoc(), DiagID: diag::note_omp_critical_hint_here)
11988 << 1
11989 << toString(I: C->getHint()->EvaluateKnownConstInt(Ctx: getASTContext()),
11990 /*Radix=*/10, /*Signed=*/false);
11991 } else {
11992 Diag(Loc: Pair.first->getBeginLoc(), DiagID: diag::note_omp_critical_no_hint) << 1;
11993 }
11994 }
11995 }
11996
11997 SemaRef.setFunctionHasBranchProtectedScope();
11998
11999 auto *Dir = OMPCriticalDirective::Create(C: getASTContext(), Name: DirName, StartLoc,
12000 EndLoc, Clauses, AssociatedStmt: AStmt);
12001 if (!Pair.first && DirName.getName() && !DependentHint)
12002 DSAStack->addCriticalWithHint(D: Dir, Hint);
12003 return Dir;
12004}
12005
12006StmtResult SemaOpenMP::ActOnOpenMPParallelForDirective(
12007 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
12008 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
12009 if (!AStmt)
12010 return StmtError();
12011
12012 setBranchProtectedScope(SemaRef, DKind: OMPD_parallel_for, AStmt);
12013
12014 OMPLoopBasedDirective::HelperExprs B;
12015 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
12016 // define the nested loops number.
12017 unsigned NestedLoopCount =
12018 checkOpenMPLoop(DKind: OMPD_parallel_for, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
12019 OrderedLoopCountExpr: getOrderedNumberExpr(Clauses), AStmt, SemaRef, DSA&: *DSAStack,
12020 VarsWithImplicitDSA, Built&: B);
12021 if (NestedLoopCount == 0)
12022 return StmtError();
12023
12024 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
12025 return StmtError();
12026
12027 return OMPParallelForDirective::Create(
12028 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B,
12029 DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
12030}
12031
12032StmtResult SemaOpenMP::ActOnOpenMPParallelForSimdDirective(
12033 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
12034 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
12035 if (!AStmt)
12036 return StmtError();
12037
12038 CapturedStmt *CS =
12039 setBranchProtectedScope(SemaRef, DKind: OMPD_parallel_for_simd, AStmt);
12040
12041 OMPLoopBasedDirective::HelperExprs B;
12042 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
12043 // define the nested loops number.
12044 unsigned NestedLoopCount =
12045 checkOpenMPLoop(DKind: OMPD_parallel_for_simd, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
12046 OrderedLoopCountExpr: getOrderedNumberExpr(Clauses), AStmt: CS, SemaRef, DSA&: *DSAStack,
12047 VarsWithImplicitDSA, Built&: B);
12048 if (NestedLoopCount == 0)
12049 return StmtError();
12050
12051 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
12052 return StmtError();
12053
12054 if (checkSimdlenSafelenSpecified(S&: SemaRef, Clauses))
12055 return StmtError();
12056
12057 return OMPParallelForSimdDirective::Create(
12058 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
12059}
12060
12061StmtResult SemaOpenMP::ActOnOpenMPParallelMasterDirective(
12062 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
12063 SourceLocation EndLoc) {
12064 if (!AStmt)
12065 return StmtError();
12066
12067 setBranchProtectedScope(SemaRef, DKind: OMPD_parallel_master, AStmt);
12068
12069 return OMPParallelMasterDirective::Create(
12070 C: getASTContext(), StartLoc, EndLoc, Clauses, AssociatedStmt: AStmt,
12071 DSAStack->getTaskgroupReductionRef());
12072}
12073
12074StmtResult SemaOpenMP::ActOnOpenMPParallelMaskedDirective(
12075 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
12076 SourceLocation EndLoc) {
12077 if (!AStmt)
12078 return StmtError();
12079
12080 setBranchProtectedScope(SemaRef, DKind: OMPD_parallel_masked, AStmt);
12081
12082 return OMPParallelMaskedDirective::Create(
12083 C: getASTContext(), StartLoc, EndLoc, Clauses, AssociatedStmt: AStmt,
12084 DSAStack->getTaskgroupReductionRef());
12085}
12086
12087StmtResult SemaOpenMP::ActOnOpenMPParallelSectionsDirective(
12088 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
12089 SourceLocation EndLoc) {
12090 if (checkSectionsDirective(SemaRef, DKind: OMPD_parallel_sections, AStmt, DSAStack))
12091 return StmtError();
12092
12093 SemaRef.setFunctionHasBranchProtectedScope();
12094
12095 return OMPParallelSectionsDirective::Create(
12096 C: getASTContext(), StartLoc, EndLoc, Clauses, AssociatedStmt: AStmt,
12097 DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
12098}
12099
12100/// Find and diagnose mutually exclusive clause kinds.
12101static bool checkMutuallyExclusiveClauses(
12102 Sema &S, ArrayRef<OMPClause *> Clauses,
12103 ArrayRef<OpenMPClauseKind> MutuallyExclusiveClauses) {
12104 const OMPClause *PrevClause = nullptr;
12105 bool ErrorFound = false;
12106 for (const OMPClause *C : Clauses) {
12107 if (llvm::is_contained(Range&: MutuallyExclusiveClauses, Element: C->getClauseKind())) {
12108 if (!PrevClause) {
12109 PrevClause = C;
12110 } else if (PrevClause->getClauseKind() != C->getClauseKind()) {
12111 S.Diag(Loc: C->getBeginLoc(), DiagID: diag::err_omp_clauses_mutually_exclusive)
12112 << getOpenMPClauseNameForDiag(C: C->getClauseKind())
12113 << getOpenMPClauseNameForDiag(C: PrevClause->getClauseKind());
12114 S.Diag(Loc: PrevClause->getBeginLoc(), DiagID: diag::note_omp_previous_clause)
12115 << getOpenMPClauseNameForDiag(C: PrevClause->getClauseKind());
12116 ErrorFound = true;
12117 }
12118 }
12119 }
12120 return ErrorFound;
12121}
12122
12123StmtResult SemaOpenMP::ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses,
12124 Stmt *AStmt,
12125 SourceLocation StartLoc,
12126 SourceLocation EndLoc) {
12127 if (!AStmt)
12128 return StmtError();
12129
12130 // OpenMP 5.0, 2.10.1 task Construct
12131 // If a detach clause appears on the directive, then a mergeable clause cannot
12132 // appear on the same directive.
12133 if (checkMutuallyExclusiveClauses(S&: SemaRef, Clauses,
12134 MutuallyExclusiveClauses: {OMPC_detach, OMPC_mergeable}))
12135 return StmtError();
12136
12137 // Check for conflicting capture kinds on structured bindings.
12138 if (checkClausesForDecompositionConflicts(SemaRef, DKind: OMPD_task, Clauses, Body: AStmt))
12139 return StmtError();
12140
12141 setBranchProtectedScope(SemaRef, DKind: OMPD_task, AStmt);
12142
12143 return OMPTaskDirective::Create(C: getASTContext(), StartLoc, EndLoc, Clauses,
12144 AssociatedStmt: AStmt, DSAStack->isCancelRegion());
12145}
12146
12147StmtResult SemaOpenMP::ActOnOpenMPTaskyieldDirective(SourceLocation StartLoc,
12148 SourceLocation EndLoc) {
12149 return OMPTaskyieldDirective::Create(C: getASTContext(), StartLoc, EndLoc);
12150}
12151
12152StmtResult SemaOpenMP::ActOnOpenMPBarrierDirective(SourceLocation StartLoc,
12153 SourceLocation EndLoc) {
12154 return OMPBarrierDirective::Create(C: getASTContext(), StartLoc, EndLoc);
12155}
12156
12157StmtResult SemaOpenMP::ActOnOpenMPErrorDirective(ArrayRef<OMPClause *> Clauses,
12158 SourceLocation StartLoc,
12159 SourceLocation EndLoc,
12160 bool InExContext) {
12161 const OMPAtClause *AtC =
12162 OMPExecutableDirective::getSingleClause<OMPAtClause>(Clauses);
12163
12164 if (AtC && !InExContext && AtC->getAtKind() == OMPC_AT_execution) {
12165 Diag(Loc: AtC->getAtKindKwLoc(), DiagID: diag::err_omp_unexpected_execution_modifier);
12166 return StmtError();
12167 }
12168
12169 if (!AtC || AtC->getAtKind() == OMPC_AT_compilation) {
12170 const OMPSeverityClause *SeverityC =
12171 OMPExecutableDirective::getSingleClause<OMPSeverityClause>(Clauses);
12172 const OMPMessageClause *MessageC =
12173 OMPExecutableDirective::getSingleClause<OMPMessageClause>(Clauses);
12174 std::optional<std::string> SL =
12175 MessageC ? MessageC->tryEvaluateString(Ctx&: getASTContext()) : std::nullopt;
12176
12177 if (MessageC && !SL)
12178 Diag(Loc: MessageC->getMessageString()->getBeginLoc(),
12179 DiagID: diag::warn_clause_expected_string)
12180 << getOpenMPClauseNameForDiag(C: OMPC_message) << 1;
12181 if (SeverityC && SeverityC->getSeverityKind() == OMPC_SEVERITY_warning)
12182 Diag(Loc: SeverityC->getSeverityKindKwLoc(), DiagID: diag::warn_diagnose_if_succeeded)
12183 << SL.value_or(u: "WARNING");
12184 else
12185 Diag(Loc: StartLoc, DiagID: diag::err_diagnose_if_succeeded) << SL.value_or(u: "ERROR");
12186 if (!SeverityC || SeverityC->getSeverityKind() != OMPC_SEVERITY_warning)
12187 return StmtError();
12188 }
12189
12190 return OMPErrorDirective::Create(C: getASTContext(), StartLoc, EndLoc, Clauses);
12191}
12192
12193StmtResult
12194SemaOpenMP::ActOnOpenMPTaskwaitDirective(ArrayRef<OMPClause *> Clauses,
12195 SourceLocation StartLoc,
12196 SourceLocation EndLoc) {
12197 const OMPNowaitClause *NowaitC =
12198 OMPExecutableDirective::getSingleClause<OMPNowaitClause>(Clauses);
12199 bool HasDependC =
12200 !OMPExecutableDirective::getClausesOfKind<OMPDependClause>(Clauses)
12201 .empty();
12202 if (NowaitC && !HasDependC) {
12203 Diag(Loc: StartLoc, DiagID: diag::err_omp_nowait_clause_without_depend);
12204 return StmtError();
12205 }
12206
12207 return OMPTaskwaitDirective::Create(C: getASTContext(), StartLoc, EndLoc,
12208 Clauses);
12209}
12210
12211StmtResult
12212SemaOpenMP::ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses,
12213 Stmt *AStmt, SourceLocation StartLoc,
12214 SourceLocation EndLoc) {
12215 if (!AStmt)
12216 return StmtError();
12217
12218 assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
12219
12220 SemaRef.setFunctionHasBranchProtectedScope();
12221
12222 return OMPTaskgroupDirective::Create(C: getASTContext(), StartLoc, EndLoc,
12223 Clauses, AssociatedStmt: AStmt,
12224 DSAStack->getTaskgroupReductionRef());
12225}
12226
12227StmtResult SemaOpenMP::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses,
12228 SourceLocation StartLoc,
12229 SourceLocation EndLoc) {
12230 OMPFlushClause *FC = nullptr;
12231 OMPClause *OrderClause = nullptr;
12232 for (OMPClause *C : Clauses) {
12233 if (C->getClauseKind() == OMPC_flush)
12234 FC = cast<OMPFlushClause>(Val: C);
12235 else
12236 OrderClause = C;
12237 }
12238 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
12239 OpenMPClauseKind MemOrderKind = OMPC_unknown;
12240 SourceLocation MemOrderLoc;
12241 for (const OMPClause *C : Clauses) {
12242 if (C->getClauseKind() == OMPC_acq_rel ||
12243 C->getClauseKind() == OMPC_acquire ||
12244 C->getClauseKind() == OMPC_release ||
12245 C->getClauseKind() == OMPC_seq_cst /*OpenMP 5.1*/) {
12246 if (MemOrderKind != OMPC_unknown) {
12247 Diag(Loc: C->getBeginLoc(), DiagID: diag::err_omp_several_mem_order_clauses)
12248 << getOpenMPDirectiveName(D: OMPD_flush, V: OMPVersion) << 1
12249 << SourceRange(C->getBeginLoc(), C->getEndLoc());
12250 Diag(Loc: MemOrderLoc, DiagID: diag::note_omp_previous_mem_order_clause)
12251 << getOpenMPClauseNameForDiag(C: MemOrderKind);
12252 } else {
12253 MemOrderKind = C->getClauseKind();
12254 MemOrderLoc = C->getBeginLoc();
12255 }
12256 }
12257 }
12258 if (FC && OrderClause) {
12259 Diag(Loc: FC->getLParenLoc(), DiagID: diag::err_omp_flush_order_clause_and_list)
12260 << getOpenMPClauseNameForDiag(C: OrderClause->getClauseKind());
12261 Diag(Loc: OrderClause->getBeginLoc(), DiagID: diag::note_omp_flush_order_clause_here)
12262 << getOpenMPClauseNameForDiag(C: OrderClause->getClauseKind());
12263 return StmtError();
12264 }
12265 return OMPFlushDirective::Create(C: getASTContext(), StartLoc, EndLoc, Clauses);
12266}
12267
12268StmtResult SemaOpenMP::ActOnOpenMPDepobjDirective(ArrayRef<OMPClause *> Clauses,
12269 SourceLocation StartLoc,
12270 SourceLocation EndLoc) {
12271 if (Clauses.empty()) {
12272 Diag(Loc: StartLoc, DiagID: diag::err_omp_depobj_expected);
12273 return StmtError();
12274 } else if (Clauses[0]->getClauseKind() != OMPC_depobj) {
12275 Diag(Loc: Clauses[0]->getBeginLoc(), DiagID: diag::err_omp_depobj_expected);
12276 return StmtError();
12277 }
12278 // Only depobj expression and another single clause is allowed.
12279 if (Clauses.size() > 2) {
12280 Diag(Loc: Clauses[2]->getBeginLoc(),
12281 DiagID: diag::err_omp_depobj_single_clause_expected);
12282 return StmtError();
12283 } else if (Clauses.size() < 1) {
12284 Diag(Loc: Clauses[0]->getEndLoc(), DiagID: diag::err_omp_depobj_single_clause_expected);
12285 return StmtError();
12286 }
12287 return OMPDepobjDirective::Create(C: getASTContext(), StartLoc, EndLoc, Clauses);
12288}
12289
12290StmtResult SemaOpenMP::ActOnOpenMPScanDirective(ArrayRef<OMPClause *> Clauses,
12291 SourceLocation StartLoc,
12292 SourceLocation EndLoc) {
12293 // Check that exactly one clause is specified.
12294 if (Clauses.size() != 1) {
12295 Diag(Loc: Clauses.empty() ? EndLoc : Clauses[1]->getBeginLoc(),
12296 DiagID: diag::err_omp_scan_single_clause_expected);
12297 return StmtError();
12298 }
12299 // Check that scan directive is used in the scope of the OpenMP loop body.
12300 if (Scope *S = DSAStack->getCurScope()) {
12301 Scope *ParentS = S->getParent();
12302 if (!ParentS || ParentS->getParent() != ParentS->getBreakParent() ||
12303 !ParentS->getBreakParent()->isOpenMPLoopScope()) {
12304 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
12305 return StmtError(Diag(Loc: StartLoc, DiagID: diag::err_omp_orphaned_device_directive)
12306 << getOpenMPDirectiveName(D: OMPD_scan, V: OMPVersion) << 5);
12307 }
12308 }
12309 // Check that only one instance of scan directives is used in the same outer
12310 // region.
12311 if (DSAStack->doesParentHasScanDirective()) {
12312 Diag(Loc: StartLoc, DiagID: diag::err_omp_several_directives_in_region) << "scan";
12313 Diag(DSAStack->getParentScanDirectiveLoc(),
12314 DiagID: diag::note_omp_previous_directive)
12315 << "scan";
12316 return StmtError();
12317 }
12318 DSAStack->setParentHasScanDirective(StartLoc);
12319 return OMPScanDirective::Create(C: getASTContext(), StartLoc, EndLoc, Clauses);
12320}
12321
12322StmtResult
12323SemaOpenMP::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses,
12324 Stmt *AStmt, SourceLocation StartLoc,
12325 SourceLocation EndLoc) {
12326 const OMPClause *DependFound = nullptr;
12327 const OMPClause *DependSourceClause = nullptr;
12328 const OMPClause *DependSinkClause = nullptr;
12329 const OMPClause *DoacrossFound = nullptr;
12330 const OMPClause *DoacrossSourceClause = nullptr;
12331 const OMPClause *DoacrossSinkClause = nullptr;
12332 bool ErrorFound = false;
12333 const OMPThreadsClause *TC = nullptr;
12334 const OMPSIMDClause *SC = nullptr;
12335 for (const OMPClause *C : Clauses) {
12336 auto DOC = dyn_cast<OMPDoacrossClause>(Val: C);
12337 auto DC = dyn_cast<OMPDependClause>(Val: C);
12338 if (DC || DOC) {
12339 DependFound = DC ? C : nullptr;
12340 DoacrossFound = DOC ? C : nullptr;
12341 OMPDoacrossKind ODK;
12342 if ((DC && DC->getDependencyKind() == OMPC_DEPEND_source) ||
12343 (DOC && (ODK.isSource(C: DOC)))) {
12344 if ((DC && DependSourceClause) || (DOC && DoacrossSourceClause)) {
12345 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
12346 Diag(Loc: C->getBeginLoc(), DiagID: diag::err_omp_more_one_clause)
12347 << getOpenMPDirectiveName(DSAStack->getCurrentDirective(),
12348 V: OMPVersion)
12349 << getOpenMPClauseNameForDiag(C: DC ? OMPC_depend : OMPC_doacross)
12350 << 2;
12351 ErrorFound = true;
12352 } else {
12353 if (DC)
12354 DependSourceClause = C;
12355 else
12356 DoacrossSourceClause = C;
12357 }
12358 if ((DC && DependSinkClause) || (DOC && DoacrossSinkClause)) {
12359 Diag(Loc: C->getBeginLoc(), DiagID: diag::err_omp_sink_and_source_not_allowed)
12360 << (DC ? "depend" : "doacross") << 0;
12361 ErrorFound = true;
12362 }
12363 } else if ((DC && DC->getDependencyKind() == OMPC_DEPEND_sink) ||
12364 (DOC && (ODK.isSink(C: DOC) || ODK.isSinkIter(C: DOC)))) {
12365 if (DependSourceClause || DoacrossSourceClause) {
12366 Diag(Loc: C->getBeginLoc(), DiagID: diag::err_omp_sink_and_source_not_allowed)
12367 << (DC ? "depend" : "doacross") << 1;
12368 ErrorFound = true;
12369 }
12370 if (DC)
12371 DependSinkClause = C;
12372 else
12373 DoacrossSinkClause = C;
12374 }
12375 } else if (C->getClauseKind() == OMPC_threads) {
12376 TC = cast<OMPThreadsClause>(Val: C);
12377 } else if (C->getClauseKind() == OMPC_simd) {
12378 SC = cast<OMPSIMDClause>(Val: C);
12379 }
12380 }
12381 if (!ErrorFound && !SC &&
12382 isOpenMPSimdDirective(DSAStack->getParentDirective())) {
12383 // OpenMP [2.8.1,simd Construct, Restrictions]
12384 // An ordered construct with the simd clause is the only OpenMP construct
12385 // that can appear in the simd region.
12386 Diag(Loc: StartLoc, DiagID: diag::err_omp_prohibited_region_simd)
12387 << (getLangOpts().OpenMP >= 50 ? 1 : 0);
12388 ErrorFound = true;
12389 } else if ((DependFound || DoacrossFound) && (TC || SC)) {
12390 SourceLocation Loc =
12391 DependFound ? DependFound->getBeginLoc() : DoacrossFound->getBeginLoc();
12392 Diag(Loc, DiagID: diag::err_omp_depend_clause_thread_simd)
12393 << getOpenMPClauseNameForDiag(C: DependFound ? OMPC_depend : OMPC_doacross)
12394 << getOpenMPClauseNameForDiag(C: TC ? TC->getClauseKind()
12395 : SC->getClauseKind());
12396 ErrorFound = true;
12397 } else if ((DependFound || DoacrossFound) &&
12398 !DSAStack->getParentOrderedRegionParam().first) {
12399 SourceLocation Loc =
12400 DependFound ? DependFound->getBeginLoc() : DoacrossFound->getBeginLoc();
12401 Diag(Loc, DiagID: diag::err_omp_ordered_directive_without_param)
12402 << getOpenMPClauseNameForDiag(C: DependFound ? OMPC_depend
12403 : OMPC_doacross);
12404 ErrorFound = true;
12405 } else if (TC || Clauses.empty()) {
12406 if (const Expr *Param = DSAStack->getParentOrderedRegionParam().first) {
12407 SourceLocation ErrLoc = TC ? TC->getBeginLoc() : StartLoc;
12408 Diag(Loc: ErrLoc, DiagID: diag::err_omp_ordered_directive_with_param)
12409 << (TC != nullptr);
12410 Diag(Loc: Param->getBeginLoc(), DiagID: diag::note_omp_ordered_param) << 1;
12411 ErrorFound = true;
12412 }
12413 }
12414 if ((!AStmt && !DependFound && !DoacrossFound) || ErrorFound)
12415 return StmtError();
12416
12417 // OpenMP 5.0, 2.17.9, ordered Construct, Restrictions.
12418 // During execution of an iteration of a worksharing-loop or a loop nest
12419 // within a worksharing-loop, simd, or worksharing-loop SIMD region, a thread
12420 // must not execute more than one ordered region corresponding to an ordered
12421 // construct without a depend clause.
12422 if (!DependFound && !DoacrossFound) {
12423 if (DSAStack->doesParentHasOrderedDirective()) {
12424 Diag(Loc: StartLoc, DiagID: diag::err_omp_several_directives_in_region) << "ordered";
12425 Diag(DSAStack->getParentOrderedDirectiveLoc(),
12426 DiagID: diag::note_omp_previous_directive)
12427 << "ordered";
12428 return StmtError();
12429 }
12430 DSAStack->setParentHasOrderedDirective(StartLoc);
12431 }
12432
12433 if (AStmt) {
12434 assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
12435
12436 SemaRef.setFunctionHasBranchProtectedScope();
12437 }
12438
12439 if (!AStmt)
12440 return OMPOrderedStandaloneDirective::Create(C: getASTContext(), StartLoc,
12441 EndLoc, Clauses);
12442 return OMPOrderedBlockAssocDirective::Create(C: getASTContext(), StartLoc,
12443 EndLoc, Clauses, AssociatedStmt: AStmt);
12444}
12445
12446namespace {
12447/// Helper class for checking expression in 'omp atomic [update]'
12448/// construct.
12449class OpenMPAtomicUpdateChecker {
12450 /// Error results for atomic update expressions.
12451 enum ExprAnalysisErrorCode {
12452 /// A statement is not an expression statement.
12453 NotAnExpression,
12454 /// Expression is not builtin binary or unary operation.
12455 NotABinaryOrUnaryExpression,
12456 /// Unary operation is not post-/pre- increment/decrement operation.
12457 NotAnUnaryIncDecExpression,
12458 /// An expression is not of scalar type.
12459 NotAScalarType,
12460 /// A binary operation is not an assignment operation.
12461 NotAnAssignmentOp,
12462 /// RHS part of the binary operation is not a binary expression.
12463 NotABinaryExpression,
12464 /// RHS part is not additive/multiplicative/shift/bitwise binary
12465 /// expression.
12466 NotABinaryOperator,
12467 /// RHS binary operation does not have reference to the updated LHS
12468 /// part.
12469 NotAnUpdateExpression,
12470 /// An expression contains semantical error not related to
12471 /// 'omp atomic [update]'
12472 NotAValidExpression,
12473 /// No errors is found.
12474 NoError
12475 };
12476 /// Reference to Sema.
12477 Sema &SemaRef;
12478 /// A location for note diagnostics (when error is found).
12479 SourceLocation NoteLoc;
12480 /// 'x' lvalue part of the source atomic expression.
12481 Expr *X;
12482 /// 'expr' rvalue part of the source atomic expression.
12483 Expr *E;
12484 /// Helper expression of the form
12485 /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or
12486 /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
12487 Expr *UpdateExpr;
12488 /// Is 'x' a LHS in a RHS part of full update expression. It is
12489 /// important for non-associative operations.
12490 bool IsXLHSInRHSPart;
12491 BinaryOperatorKind Op;
12492 SourceLocation OpLoc;
12493 /// true if the source expression is a postfix unary operation, false
12494 /// if it is a prefix unary operation.
12495 bool IsPostfixUpdate;
12496
12497public:
12498 OpenMPAtomicUpdateChecker(Sema &SemaRef)
12499 : SemaRef(SemaRef), X(nullptr), E(nullptr), UpdateExpr(nullptr),
12500 IsXLHSInRHSPart(false), Op(BO_PtrMemD), IsPostfixUpdate(false) {}
12501 /// Check specified statement that it is suitable for 'atomic update'
12502 /// constructs and extract 'x', 'expr' and Operation from the original
12503 /// expression. If DiagId and NoteId == 0, then only check is performed
12504 /// without error notification.
12505 /// \param DiagId Diagnostic which should be emitted if error is found.
12506 /// \param NoteId Diagnostic note for the main error message.
12507 /// \return true if statement is not an update expression, false otherwise.
12508 bool checkStatement(Stmt *S, unsigned DiagId = 0, unsigned NoteId = 0);
12509 /// Return the 'x' lvalue part of the source atomic expression.
12510 Expr *getX() const { return X; }
12511 /// Return the 'expr' rvalue part of the source atomic expression.
12512 Expr *getExpr() const { return E; }
12513 /// Return the update expression used in calculation of the updated
12514 /// value. Always has form 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or
12515 /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'.
12516 Expr *getUpdateExpr() const { return UpdateExpr; }
12517 /// Return true if 'x' is LHS in RHS part of full update expression,
12518 /// false otherwise.
12519 bool isXLHSInRHSPart() const { return IsXLHSInRHSPart; }
12520
12521 /// true if the source expression is a postfix unary operation, false
12522 /// if it is a prefix unary operation.
12523 bool isPostfixUpdate() const { return IsPostfixUpdate; }
12524
12525private:
12526 bool checkBinaryOperation(BinaryOperator *AtomicBinOp, unsigned DiagId = 0,
12527 unsigned NoteId = 0);
12528};
12529
12530bool OpenMPAtomicUpdateChecker::checkBinaryOperation(
12531 BinaryOperator *AtomicBinOp, unsigned DiagId, unsigned NoteId) {
12532 ExprAnalysisErrorCode ErrorFound = NoError;
12533 SourceLocation ErrorLoc, NoteLoc;
12534 SourceRange ErrorRange, NoteRange;
12535 // Allowed constructs are:
12536 // x = x binop expr;
12537 // x = expr binop x;
12538 if (AtomicBinOp->getOpcode() == BO_Assign) {
12539 X = AtomicBinOp->getLHS();
12540 if (const auto *AtomicInnerBinOp = dyn_cast<BinaryOperator>(
12541 Val: AtomicBinOp->getRHS()->IgnoreParenImpCasts())) {
12542 if (AtomicInnerBinOp->isMultiplicativeOp() ||
12543 AtomicInnerBinOp->isAdditiveOp() || AtomicInnerBinOp->isShiftOp() ||
12544 AtomicInnerBinOp->isBitwiseOp()) {
12545 Op = AtomicInnerBinOp->getOpcode();
12546 OpLoc = AtomicInnerBinOp->getOperatorLoc();
12547 Expr *LHS = AtomicInnerBinOp->getLHS();
12548 Expr *RHS = AtomicInnerBinOp->getRHS();
12549 llvm::FoldingSetNodeID XId, LHSId, RHSId;
12550 X->IgnoreParenImpCasts()->Profile(ID&: XId, Context: SemaRef.getASTContext(),
12551 /*Canonical=*/true);
12552 LHS->IgnoreParenImpCasts()->Profile(ID&: LHSId, Context: SemaRef.getASTContext(),
12553 /*Canonical=*/true);
12554 RHS->IgnoreParenImpCasts()->Profile(ID&: RHSId, Context: SemaRef.getASTContext(),
12555 /*Canonical=*/true);
12556 if (XId == LHSId) {
12557 E = RHS;
12558 IsXLHSInRHSPart = true;
12559 } else if (XId == RHSId) {
12560 E = LHS;
12561 IsXLHSInRHSPart = false;
12562 } else {
12563 ErrorLoc = AtomicInnerBinOp->getExprLoc();
12564 ErrorRange = AtomicInnerBinOp->getSourceRange();
12565 NoteLoc = X->getExprLoc();
12566 NoteRange = X->getSourceRange();
12567 ErrorFound = NotAnUpdateExpression;
12568 }
12569 } else {
12570 ErrorLoc = AtomicInnerBinOp->getExprLoc();
12571 ErrorRange = AtomicInnerBinOp->getSourceRange();
12572 NoteLoc = AtomicInnerBinOp->getOperatorLoc();
12573 NoteRange = SourceRange(NoteLoc, NoteLoc);
12574 ErrorFound = NotABinaryOperator;
12575 }
12576 } else {
12577 NoteLoc = ErrorLoc = AtomicBinOp->getRHS()->getExprLoc();
12578 NoteRange = ErrorRange = AtomicBinOp->getRHS()->getSourceRange();
12579 ErrorFound = NotABinaryExpression;
12580 }
12581 } else {
12582 ErrorLoc = AtomicBinOp->getExprLoc();
12583 ErrorRange = AtomicBinOp->getSourceRange();
12584 NoteLoc = AtomicBinOp->getOperatorLoc();
12585 NoteRange = SourceRange(NoteLoc, NoteLoc);
12586 ErrorFound = NotAnAssignmentOp;
12587 }
12588 if (ErrorFound != NoError && DiagId != 0 && NoteId != 0) {
12589 SemaRef.Diag(Loc: ErrorLoc, DiagID: DiagId) << ErrorRange;
12590 SemaRef.Diag(Loc: NoteLoc, DiagID: NoteId) << ErrorFound << NoteRange;
12591 return true;
12592 }
12593 if (SemaRef.CurContext->isDependentContext())
12594 E = X = UpdateExpr = nullptr;
12595 return ErrorFound != NoError;
12596}
12597
12598bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, unsigned DiagId,
12599 unsigned NoteId) {
12600 ExprAnalysisErrorCode ErrorFound = NoError;
12601 SourceLocation ErrorLoc, NoteLoc;
12602 SourceRange ErrorRange, NoteRange;
12603 // Allowed constructs are:
12604 // x++;
12605 // x--;
12606 // ++x;
12607 // --x;
12608 // x binop= expr;
12609 // x = x binop expr;
12610 // x = expr binop x;
12611 if (auto *AtomicBody = dyn_cast<Expr>(Val: S)) {
12612 AtomicBody = AtomicBody->IgnoreParenImpCasts();
12613 if (AtomicBody->getType()->isScalarType() ||
12614 AtomicBody->isInstantiationDependent()) {
12615 if (const auto *AtomicCompAssignOp = dyn_cast<CompoundAssignOperator>(
12616 Val: AtomicBody->IgnoreParenImpCasts())) {
12617 // Check for Compound Assignment Operation
12618 Op = BinaryOperator::getOpForCompoundAssignment(
12619 Opc: AtomicCompAssignOp->getOpcode());
12620 OpLoc = AtomicCompAssignOp->getOperatorLoc();
12621 E = AtomicCompAssignOp->getRHS();
12622 X = AtomicCompAssignOp->getLHS()->IgnoreParens();
12623 IsXLHSInRHSPart = true;
12624 } else if (auto *AtomicBinOp = dyn_cast<BinaryOperator>(
12625 Val: AtomicBody->IgnoreParenImpCasts())) {
12626 // Check for Binary Operation
12627 if (checkBinaryOperation(AtomicBinOp, DiagId, NoteId))
12628 return true;
12629 } else if (const auto *AtomicUnaryOp = dyn_cast<UnaryOperator>(
12630 Val: AtomicBody->IgnoreParenImpCasts())) {
12631 // Check for Unary Operation
12632 if (AtomicUnaryOp->isIncrementDecrementOp()) {
12633 IsPostfixUpdate = AtomicUnaryOp->isPostfix();
12634 Op = AtomicUnaryOp->isIncrementOp() ? BO_Add : BO_Sub;
12635 OpLoc = AtomicUnaryOp->getOperatorLoc();
12636 X = AtomicUnaryOp->getSubExpr()->IgnoreParens();
12637 E = SemaRef.ActOnIntegerConstant(Loc: OpLoc, /*uint64_t Val=*/Val: 1).get();
12638 IsXLHSInRHSPart = true;
12639 } else {
12640 ErrorFound = NotAnUnaryIncDecExpression;
12641 ErrorLoc = AtomicUnaryOp->getExprLoc();
12642 ErrorRange = AtomicUnaryOp->getSourceRange();
12643 NoteLoc = AtomicUnaryOp->getOperatorLoc();
12644 NoteRange = SourceRange(NoteLoc, NoteLoc);
12645 }
12646 } else if (!AtomicBody->isInstantiationDependent()) {
12647 ErrorFound = NotABinaryOrUnaryExpression;
12648 NoteLoc = ErrorLoc = AtomicBody->getExprLoc();
12649 NoteRange = ErrorRange = AtomicBody->getSourceRange();
12650 } else if (AtomicBody->containsErrors()) {
12651 ErrorFound = NotAValidExpression;
12652 NoteLoc = ErrorLoc = AtomicBody->getExprLoc();
12653 NoteRange = ErrorRange = AtomicBody->getSourceRange();
12654 }
12655 } else {
12656 ErrorFound = NotAScalarType;
12657 NoteLoc = ErrorLoc = AtomicBody->getBeginLoc();
12658 NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc);
12659 }
12660 } else {
12661 ErrorFound = NotAnExpression;
12662 NoteLoc = ErrorLoc = S->getBeginLoc();
12663 NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc);
12664 }
12665 if (ErrorFound != NoError && DiagId != 0 && NoteId != 0) {
12666 SemaRef.Diag(Loc: ErrorLoc, DiagID: DiagId) << ErrorRange;
12667 SemaRef.Diag(Loc: NoteLoc, DiagID: NoteId) << ErrorFound << NoteRange;
12668 return true;
12669 }
12670 if (SemaRef.CurContext->isDependentContext())
12671 E = X = UpdateExpr = nullptr;
12672 if (ErrorFound == NoError && E && X) {
12673 // Build an update expression of form 'OpaqueValueExpr(x) binop
12674 // OpaqueValueExpr(expr)' or 'OpaqueValueExpr(expr) binop
12675 // OpaqueValueExpr(x)' and then cast it to the type of the 'x' expression.
12676 auto *OVEX = new (SemaRef.getASTContext())
12677 OpaqueValueExpr(X->getExprLoc(), X->getType(), VK_PRValue);
12678 auto *OVEExpr = new (SemaRef.getASTContext())
12679 OpaqueValueExpr(E->getExprLoc(), E->getType(), VK_PRValue);
12680 ExprResult Update =
12681 SemaRef.CreateBuiltinBinOp(OpLoc, Opc: Op, LHSExpr: IsXLHSInRHSPart ? OVEX : OVEExpr,
12682 RHSExpr: IsXLHSInRHSPart ? OVEExpr : OVEX);
12683 if (Update.isInvalid())
12684 return true;
12685 Update = SemaRef.PerformImplicitConversion(From: Update.get(), ToType: X->getType(),
12686 Action: AssignmentAction::Casting);
12687 if (Update.isInvalid())
12688 return true;
12689 UpdateExpr = Update.get();
12690 }
12691 return ErrorFound != NoError;
12692}
12693
12694/// Get the node id of the fixed point of an expression \a S.
12695llvm::FoldingSetNodeID getNodeId(ASTContext &Context, const Expr *S) {
12696 llvm::FoldingSetNodeID Id;
12697 S->IgnoreParenImpCasts()->Profile(ID&: Id, Context, Canonical: true);
12698 return Id;
12699}
12700
12701/// Check if two expressions are same.
12702bool checkIfTwoExprsAreSame(ASTContext &Context, const Expr *LHS,
12703 const Expr *RHS) {
12704 return getNodeId(Context, S: LHS) == getNodeId(Context, S: RHS);
12705}
12706
12707class OpenMPAtomicCompareChecker {
12708public:
12709 /// All kinds of errors that can occur in `atomic compare`
12710 enum ErrorTy {
12711 /// Empty compound statement.
12712 NoStmt = 0,
12713 /// More than one statement in a compound statement.
12714 MoreThanOneStmt,
12715 /// Not an assignment binary operator.
12716 NotAnAssignment,
12717 /// Not a conditional operator.
12718 NotCondOp,
12719 /// Wrong false expr. According to the spec, 'x' should be at the false
12720 /// expression of a conditional expression.
12721 WrongFalseExpr,
12722 /// The condition of a conditional expression is not a binary operator.
12723 NotABinaryOp,
12724 /// Invalid binary operator (not <, >, or ==).
12725 InvalidBinaryOp,
12726 /// Invalid comparison (not x == e, e == x, x ordop expr, or expr ordop x).
12727 InvalidComparison,
12728 /// X is not a lvalue.
12729 XNotLValue,
12730 /// Not a scalar.
12731 NotScalar,
12732 /// Not an integer.
12733 NotInteger,
12734 /// 'else' statement is not expected.
12735 UnexpectedElse,
12736 /// Not an equality operator.
12737 NotEQ,
12738 /// Invalid assignment (not v == x).
12739 InvalidAssignment,
12740 /// Not if statement
12741 NotIfStmt,
12742 /// More than two statements in a compound statement.
12743 MoreThanTwoStmts,
12744 /// Not a compound statement.
12745 NotCompoundStmt,
12746 /// No else statement.
12747 NoElse,
12748 /// Not 'if (r)'.
12749 InvalidCondition,
12750 /// No error.
12751 NoError,
12752 };
12753
12754 struct ErrorInfoTy {
12755 ErrorTy Error;
12756 SourceLocation ErrorLoc;
12757 SourceRange ErrorRange;
12758 SourceLocation NoteLoc;
12759 SourceRange NoteRange;
12760 };
12761
12762 OpenMPAtomicCompareChecker(Sema &S) : ContextRef(S.getASTContext()) {}
12763
12764 /// Check if statement \a S is valid for <tt>atomic compare</tt>.
12765 bool checkStmt(Stmt *S, ErrorInfoTy &ErrorInfo);
12766
12767 Expr *getX() const { return X; }
12768 Expr *getE() const { return E; }
12769 Expr *getD() const { return D; }
12770 Expr *getCond() const { return C; }
12771 bool isXBinopExpr() const { return IsXBinopExpr; }
12772
12773protected:
12774 /// Reference to ASTContext
12775 ASTContext &ContextRef;
12776 /// 'x' lvalue part of the source atomic expression.
12777 Expr *X = nullptr;
12778 /// 'expr' or 'e' rvalue part of the source atomic expression.
12779 Expr *E = nullptr;
12780 /// 'd' rvalue part of the source atomic expression.
12781 Expr *D = nullptr;
12782 /// 'cond' part of the source atomic expression. It is in one of the following
12783 /// forms:
12784 /// expr ordop x
12785 /// x ordop expr
12786 /// x == e
12787 /// e == x
12788 Expr *C = nullptr;
12789 /// True if the cond expr is in the form of 'x ordop expr'.
12790 bool IsXBinopExpr = true;
12791
12792 /// Check if it is a valid conditional update statement (cond-update-stmt).
12793 bool checkCondUpdateStmt(IfStmt *S, ErrorInfoTy &ErrorInfo);
12794
12795 /// Check if it is a valid conditional expression statement (cond-expr-stmt).
12796 bool checkCondExprStmt(Stmt *S, ErrorInfoTy &ErrorInfo);
12797
12798 /// Check if all captured values have right type.
12799 bool checkType(ErrorInfoTy &ErrorInfo) const;
12800
12801 static bool CheckValue(const Expr *E, ErrorInfoTy &ErrorInfo,
12802 bool ShouldBeLValue, bool ShouldBeInteger = false) {
12803 if (E->isInstantiationDependent())
12804 return true;
12805
12806 if (ShouldBeLValue && !E->isLValue()) {
12807 ErrorInfo.Error = ErrorTy::XNotLValue;
12808 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
12809 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
12810 return false;
12811 }
12812
12813 QualType QTy = E->getType();
12814 if (!QTy->isScalarType()) {
12815 ErrorInfo.Error = ErrorTy::NotScalar;
12816 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
12817 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
12818 return false;
12819 }
12820 if (ShouldBeInteger && !QTy->isIntegerType()) {
12821 ErrorInfo.Error = ErrorTy::NotInteger;
12822 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
12823 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
12824 return false;
12825 }
12826
12827 return true;
12828 }
12829};
12830
12831bool OpenMPAtomicCompareChecker::checkCondUpdateStmt(IfStmt *S,
12832 ErrorInfoTy &ErrorInfo) {
12833 auto *Then = S->getThen();
12834 if (auto *CS = dyn_cast<CompoundStmt>(Val: Then)) {
12835 if (CS->body_empty()) {
12836 ErrorInfo.Error = ErrorTy::NoStmt;
12837 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
12838 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange();
12839 return false;
12840 }
12841 if (CS->size() > 1) {
12842 ErrorInfo.Error = ErrorTy::MoreThanOneStmt;
12843 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
12844 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getSourceRange();
12845 return false;
12846 }
12847 Then = CS->body_front();
12848 }
12849
12850 auto *BO = dyn_cast<BinaryOperator>(Val: Then);
12851 if (!BO) {
12852 ErrorInfo.Error = ErrorTy::NotAnAssignment;
12853 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Then->getBeginLoc();
12854 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Then->getSourceRange();
12855 return false;
12856 }
12857 if (BO->getOpcode() != BO_Assign) {
12858 ErrorInfo.Error = ErrorTy::NotAnAssignment;
12859 ErrorInfo.ErrorLoc = BO->getExprLoc();
12860 ErrorInfo.NoteLoc = BO->getOperatorLoc();
12861 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange();
12862 return false;
12863 }
12864
12865 X = BO->getLHS();
12866
12867 auto *Cond = dyn_cast<BinaryOperator>(Val: S->getCond());
12868 auto *Call = dyn_cast<CXXOperatorCallExpr>(Val: S->getCond());
12869 Expr *LHS = nullptr;
12870 Expr *RHS = nullptr;
12871 if (Cond) {
12872 LHS = Cond->getLHS();
12873 RHS = Cond->getRHS();
12874 } else if (Call) {
12875 LHS = Call->getArg(Arg: 0);
12876 RHS = Call->getArg(Arg: 1);
12877 } else {
12878 ErrorInfo.Error = ErrorTy::NotABinaryOp;
12879 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getCond()->getExprLoc();
12880 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getCond()->getSourceRange();
12881 return false;
12882 }
12883
12884 if ((Cond && Cond->getOpcode() == BO_EQ) ||
12885 (Call && Call->getOperator() == OverloadedOperatorKind::OO_EqualEqual)) {
12886 C = S->getCond();
12887 D = BO->getRHS();
12888 if (checkIfTwoExprsAreSame(Context&: ContextRef, LHS: X, RHS: LHS)) {
12889 E = RHS;
12890 } else if (checkIfTwoExprsAreSame(Context&: ContextRef, LHS: X, RHS)) {
12891 E = LHS;
12892 } else {
12893 ErrorInfo.Error = ErrorTy::InvalidComparison;
12894 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getCond()->getExprLoc();
12895 ErrorInfo.ErrorRange = ErrorInfo.NoteRange =
12896 S->getCond()->getSourceRange();
12897 return false;
12898 }
12899 } else if ((Cond &&
12900 (Cond->getOpcode() == BO_LT || Cond->getOpcode() == BO_GT)) ||
12901 (Call &&
12902 (Call->getOperator() == OverloadedOperatorKind::OO_Less ||
12903 Call->getOperator() == OverloadedOperatorKind::OO_Greater))) {
12904 E = BO->getRHS();
12905 if (checkIfTwoExprsAreSame(Context&: ContextRef, LHS: X, RHS: LHS) &&
12906 checkIfTwoExprsAreSame(Context&: ContextRef, LHS: E, RHS)) {
12907 C = S->getCond();
12908 } else if (checkIfTwoExprsAreSame(Context&: ContextRef, LHS: E, RHS: LHS) &&
12909 checkIfTwoExprsAreSame(Context&: ContextRef, LHS: X, RHS)) {
12910 C = S->getCond();
12911 IsXBinopExpr = false;
12912 } else {
12913 ErrorInfo.Error = ErrorTy::InvalidComparison;
12914 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getCond()->getExprLoc();
12915 ErrorInfo.ErrorRange = ErrorInfo.NoteRange =
12916 S->getCond()->getSourceRange();
12917 return false;
12918 }
12919 } else {
12920 ErrorInfo.Error = ErrorTy::InvalidBinaryOp;
12921 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getCond()->getExprLoc();
12922 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getCond()->getSourceRange();
12923 return false;
12924 }
12925
12926 if (S->getElse()) {
12927 ErrorInfo.Error = ErrorTy::UnexpectedElse;
12928 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getElse()->getBeginLoc();
12929 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getElse()->getSourceRange();
12930 return false;
12931 }
12932
12933 return true;
12934}
12935
12936bool OpenMPAtomicCompareChecker::checkCondExprStmt(Stmt *S,
12937 ErrorInfoTy &ErrorInfo) {
12938 auto *BO = dyn_cast<BinaryOperator>(Val: S);
12939 if (!BO) {
12940 ErrorInfo.Error = ErrorTy::NotAnAssignment;
12941 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getBeginLoc();
12942 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getSourceRange();
12943 return false;
12944 }
12945 if (BO->getOpcode() != BO_Assign) {
12946 ErrorInfo.Error = ErrorTy::NotAnAssignment;
12947 ErrorInfo.ErrorLoc = BO->getExprLoc();
12948 ErrorInfo.NoteLoc = BO->getOperatorLoc();
12949 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange();
12950 return false;
12951 }
12952
12953 X = BO->getLHS();
12954
12955 auto *CO = dyn_cast<ConditionalOperator>(Val: BO->getRHS()->IgnoreParenImpCasts());
12956 if (!CO) {
12957 ErrorInfo.Error = ErrorTy::NotCondOp;
12958 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = BO->getRHS()->getExprLoc();
12959 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getRHS()->getSourceRange();
12960 return false;
12961 }
12962
12963 if (!checkIfTwoExprsAreSame(Context&: ContextRef, LHS: X, RHS: CO->getFalseExpr())) {
12964 ErrorInfo.Error = ErrorTy::WrongFalseExpr;
12965 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CO->getFalseExpr()->getExprLoc();
12966 ErrorInfo.ErrorRange = ErrorInfo.NoteRange =
12967 CO->getFalseExpr()->getSourceRange();
12968 return false;
12969 }
12970
12971 auto *Cond = dyn_cast<BinaryOperator>(Val: CO->getCond());
12972 auto *Call = dyn_cast<CXXOperatorCallExpr>(Val: CO->getCond());
12973 Expr *LHS = nullptr;
12974 Expr *RHS = nullptr;
12975 if (Cond) {
12976 LHS = Cond->getLHS();
12977 RHS = Cond->getRHS();
12978 } else if (Call) {
12979 LHS = Call->getArg(Arg: 0);
12980 RHS = Call->getArg(Arg: 1);
12981 } else {
12982 ErrorInfo.Error = ErrorTy::NotABinaryOp;
12983 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CO->getCond()->getExprLoc();
12984 ErrorInfo.ErrorRange = ErrorInfo.NoteRange =
12985 CO->getCond()->getSourceRange();
12986 return false;
12987 }
12988
12989 if ((Cond && Cond->getOpcode() == BO_EQ) ||
12990 (Call && Call->getOperator() == OverloadedOperatorKind::OO_EqualEqual)) {
12991 C = CO->getCond();
12992 D = CO->getTrueExpr();
12993 if (checkIfTwoExprsAreSame(Context&: ContextRef, LHS: X, RHS: LHS)) {
12994 E = RHS;
12995 } else if (checkIfTwoExprsAreSame(Context&: ContextRef, LHS: X, RHS)) {
12996 E = LHS;
12997 } else {
12998 ErrorInfo.Error = ErrorTy::InvalidComparison;
12999 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CO->getCond()->getExprLoc();
13000 ErrorInfo.ErrorRange = ErrorInfo.NoteRange =
13001 CO->getCond()->getSourceRange();
13002 return false;
13003 }
13004 } else if ((Cond &&
13005 (Cond->getOpcode() == BO_LT || Cond->getOpcode() == BO_GT)) ||
13006 (Call &&
13007 (Call->getOperator() == OverloadedOperatorKind::OO_Less ||
13008 Call->getOperator() == OverloadedOperatorKind::OO_Greater))) {
13009
13010 E = CO->getTrueExpr();
13011 if (checkIfTwoExprsAreSame(Context&: ContextRef, LHS: X, RHS: LHS) &&
13012 checkIfTwoExprsAreSame(Context&: ContextRef, LHS: E, RHS)) {
13013 C = CO->getCond();
13014 } else if (checkIfTwoExprsAreSame(Context&: ContextRef, LHS: E, RHS: LHS) &&
13015 checkIfTwoExprsAreSame(Context&: ContextRef, LHS: X, RHS)) {
13016 C = CO->getCond();
13017 IsXBinopExpr = false;
13018 } else {
13019 ErrorInfo.Error = ErrorTy::InvalidComparison;
13020 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CO->getCond()->getExprLoc();
13021 ErrorInfo.ErrorRange = ErrorInfo.NoteRange =
13022 CO->getCond()->getSourceRange();
13023 return false;
13024 }
13025 } else {
13026 ErrorInfo.Error = ErrorTy::InvalidBinaryOp;
13027 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CO->getCond()->getExprLoc();
13028 ErrorInfo.ErrorRange = ErrorInfo.NoteRange =
13029 CO->getCond()->getSourceRange();
13030 return false;
13031 }
13032
13033 return true;
13034}
13035
13036bool OpenMPAtomicCompareChecker::checkType(ErrorInfoTy &ErrorInfo) const {
13037 // 'x' and 'e' cannot be nullptr
13038 assert(X && E && "X and E cannot be nullptr");
13039
13040 if (!CheckValue(E: X, ErrorInfo, ShouldBeLValue: true))
13041 return false;
13042
13043 if (!CheckValue(E, ErrorInfo, ShouldBeLValue: false))
13044 return false;
13045
13046 if (D && !CheckValue(E: D, ErrorInfo, ShouldBeLValue: false))
13047 return false;
13048
13049 return true;
13050}
13051
13052bool OpenMPAtomicCompareChecker::checkStmt(
13053 Stmt *S, OpenMPAtomicCompareChecker::ErrorInfoTy &ErrorInfo) {
13054 auto *CS = dyn_cast<CompoundStmt>(Val: S);
13055 if (CS) {
13056 if (CS->body_empty()) {
13057 ErrorInfo.Error = ErrorTy::NoStmt;
13058 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
13059 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange();
13060 return false;
13061 }
13062
13063 if (CS->size() != 1) {
13064 ErrorInfo.Error = ErrorTy::MoreThanOneStmt;
13065 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
13066 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange();
13067 return false;
13068 }
13069 S = CS->body_front();
13070 }
13071
13072 auto Res = false;
13073
13074 if (auto *IS = dyn_cast<IfStmt>(Val: S)) {
13075 // Check if the statement is in one of the following forms
13076 // (cond-update-stmt):
13077 // if (expr ordop x) { x = expr; }
13078 // if (x ordop expr) { x = expr; }
13079 // if (x == e) { x = d; }
13080 Res = checkCondUpdateStmt(S: IS, ErrorInfo);
13081 } else {
13082 // Check if the statement is in one of the following forms (cond-expr-stmt):
13083 // x = expr ordop x ? expr : x;
13084 // x = x ordop expr ? expr : x;
13085 // x = x == e ? d : x;
13086 Res = checkCondExprStmt(S, ErrorInfo);
13087 }
13088
13089 if (!Res)
13090 return false;
13091
13092 return checkType(ErrorInfo);
13093}
13094
13095class OpenMPAtomicCompareCaptureChecker final
13096 : public OpenMPAtomicCompareChecker {
13097public:
13098 OpenMPAtomicCompareCaptureChecker(Sema &S) : OpenMPAtomicCompareChecker(S) {}
13099
13100 Expr *getV() const { return V; }
13101 Expr *getR() const { return R; }
13102 bool isFailOnly() const { return IsFailOnly; }
13103 bool isPostfixUpdate() const { return IsPostfixUpdate; }
13104
13105 /// Check if statement \a S is valid for <tt>atomic compare capture</tt>.
13106 bool checkStmt(Stmt *S, ErrorInfoTy &ErrorInfo);
13107
13108private:
13109 bool checkType(ErrorInfoTy &ErrorInfo);
13110
13111 // NOTE: Form 3, 4, 5 in the following comments mean the 3rd, 4th, and 5th
13112 // form of 'conditional-update-capture-atomic' structured block on the v5.2
13113 // spec p.p. 82:
13114 // (1) { v = x; cond-update-stmt }
13115 // (2) { cond-update-stmt v = x; }
13116 // (3) if(x == e) { x = d; } else { v = x; }
13117 // (4) { r = x == e; if(r) { x = d; } }
13118 // (5) { r = x == e; if(r) { x = d; } else { v = x; } }
13119
13120 /// Check if it is valid 'if(x == e) { x = d; } else { v = x; }' (form 3)
13121 bool checkForm3(IfStmt *S, ErrorInfoTy &ErrorInfo);
13122
13123 /// Check if it is valid '{ r = x == e; if(r) { x = d; } }',
13124 /// or '{ r = x == e; if(r) { x = d; } else { v = x; } }' (form 4 and 5)
13125 bool checkForm45(Stmt *S, ErrorInfoTy &ErrorInfo);
13126
13127 /// 'v' lvalue part of the source atomic expression.
13128 Expr *V = nullptr;
13129 /// 'r' lvalue part of the source atomic expression.
13130 Expr *R = nullptr;
13131 /// If 'v' is only updated when the comparison fails.
13132 bool IsFailOnly = false;
13133 /// If original value of 'x' must be stored in 'v', not an updated one.
13134 bool IsPostfixUpdate = false;
13135};
13136
13137bool OpenMPAtomicCompareCaptureChecker::checkType(ErrorInfoTy &ErrorInfo) {
13138 if (!OpenMPAtomicCompareChecker::checkType(ErrorInfo))
13139 return false;
13140
13141 if (V && !CheckValue(E: V, ErrorInfo, ShouldBeLValue: true))
13142 return false;
13143
13144 if (R && !CheckValue(E: R, ErrorInfo, ShouldBeLValue: true, ShouldBeInteger: true))
13145 return false;
13146
13147 return true;
13148}
13149
13150bool OpenMPAtomicCompareCaptureChecker::checkForm3(IfStmt *S,
13151 ErrorInfoTy &ErrorInfo) {
13152 IsFailOnly = true;
13153
13154 auto *Then = S->getThen();
13155 if (auto *CS = dyn_cast<CompoundStmt>(Val: Then)) {
13156 if (CS->body_empty()) {
13157 ErrorInfo.Error = ErrorTy::NoStmt;
13158 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
13159 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange();
13160 return false;
13161 }
13162 if (CS->size() > 1) {
13163 ErrorInfo.Error = ErrorTy::MoreThanOneStmt;
13164 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
13165 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange();
13166 return false;
13167 }
13168 Then = CS->body_front();
13169 }
13170
13171 auto *BO = dyn_cast<BinaryOperator>(Val: Then);
13172 if (!BO) {
13173 ErrorInfo.Error = ErrorTy::NotAnAssignment;
13174 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Then->getBeginLoc();
13175 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Then->getSourceRange();
13176 return false;
13177 }
13178 if (BO->getOpcode() != BO_Assign) {
13179 ErrorInfo.Error = ErrorTy::NotAnAssignment;
13180 ErrorInfo.ErrorLoc = BO->getExprLoc();
13181 ErrorInfo.NoteLoc = BO->getOperatorLoc();
13182 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange();
13183 return false;
13184 }
13185
13186 X = BO->getLHS();
13187 D = BO->getRHS();
13188
13189 auto *Cond = dyn_cast<BinaryOperator>(Val: S->getCond());
13190 auto *Call = dyn_cast<CXXOperatorCallExpr>(Val: S->getCond());
13191 Expr *LHS = nullptr;
13192 Expr *RHS = nullptr;
13193 if (Cond) {
13194 LHS = Cond->getLHS();
13195 RHS = Cond->getRHS();
13196 } else if (Call) {
13197 LHS = Call->getArg(Arg: 0);
13198 RHS = Call->getArg(Arg: 1);
13199 } else {
13200 ErrorInfo.Error = ErrorTy::NotABinaryOp;
13201 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getCond()->getExprLoc();
13202 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getCond()->getSourceRange();
13203 return false;
13204 }
13205 if ((Cond && Cond->getOpcode() != BO_EQ) ||
13206 (Call && Call->getOperator() != OverloadedOperatorKind::OO_EqualEqual)) {
13207 ErrorInfo.Error = ErrorTy::NotEQ;
13208 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getCond()->getExprLoc();
13209 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getCond()->getSourceRange();
13210 return false;
13211 }
13212
13213 if (checkIfTwoExprsAreSame(Context&: ContextRef, LHS: X, RHS: LHS)) {
13214 E = RHS;
13215 } else if (checkIfTwoExprsAreSame(Context&: ContextRef, LHS: X, RHS)) {
13216 E = LHS;
13217 } else {
13218 ErrorInfo.Error = ErrorTy::InvalidComparison;
13219 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getCond()->getExprLoc();
13220 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getCond()->getSourceRange();
13221 return false;
13222 }
13223
13224 C = S->getCond();
13225
13226 if (!S->getElse()) {
13227 ErrorInfo.Error = ErrorTy::NoElse;
13228 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getBeginLoc();
13229 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getSourceRange();
13230 return false;
13231 }
13232
13233 auto *Else = S->getElse();
13234 if (auto *CS = dyn_cast<CompoundStmt>(Val: Else)) {
13235 if (CS->body_empty()) {
13236 ErrorInfo.Error = ErrorTy::NoStmt;
13237 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
13238 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange();
13239 return false;
13240 }
13241 if (CS->size() > 1) {
13242 ErrorInfo.Error = ErrorTy::MoreThanOneStmt;
13243 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
13244 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getSourceRange();
13245 return false;
13246 }
13247 Else = CS->body_front();
13248 }
13249
13250 auto *ElseBO = dyn_cast<BinaryOperator>(Val: Else);
13251 if (!ElseBO) {
13252 ErrorInfo.Error = ErrorTy::NotAnAssignment;
13253 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Else->getBeginLoc();
13254 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Else->getSourceRange();
13255 return false;
13256 }
13257 if (ElseBO->getOpcode() != BO_Assign) {
13258 ErrorInfo.Error = ErrorTy::NotAnAssignment;
13259 ErrorInfo.ErrorLoc = ElseBO->getExprLoc();
13260 ErrorInfo.NoteLoc = ElseBO->getOperatorLoc();
13261 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ElseBO->getSourceRange();
13262 return false;
13263 }
13264
13265 if (!checkIfTwoExprsAreSame(Context&: ContextRef, LHS: X, RHS: ElseBO->getRHS())) {
13266 ErrorInfo.Error = ErrorTy::InvalidAssignment;
13267 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = ElseBO->getRHS()->getExprLoc();
13268 ErrorInfo.ErrorRange = ErrorInfo.NoteRange =
13269 ElseBO->getRHS()->getSourceRange();
13270 return false;
13271 }
13272
13273 V = ElseBO->getLHS();
13274
13275 return checkType(ErrorInfo);
13276}
13277
13278bool OpenMPAtomicCompareCaptureChecker::checkForm45(Stmt *S,
13279 ErrorInfoTy &ErrorInfo) {
13280 // We don't check here as they should be already done before call this
13281 // function.
13282 auto *CS = cast<CompoundStmt>(Val: S);
13283 assert(CS->size() == 2 && "CompoundStmt size is not expected");
13284 auto *S1 = cast<BinaryOperator>(Val: CS->body_front());
13285 auto *S2 = cast<IfStmt>(Val: CS->body_back());
13286 assert(S1->getOpcode() == BO_Assign && "unexpected binary operator");
13287
13288 if (!checkIfTwoExprsAreSame(Context&: ContextRef, LHS: S1->getLHS(), RHS: S2->getCond())) {
13289 ErrorInfo.Error = ErrorTy::InvalidCondition;
13290 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S2->getCond()->getExprLoc();
13291 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S1->getLHS()->getSourceRange();
13292 return false;
13293 }
13294
13295 R = S1->getLHS();
13296
13297 auto *Then = S2->getThen();
13298 if (auto *ThenCS = dyn_cast<CompoundStmt>(Val: Then)) {
13299 if (ThenCS->body_empty()) {
13300 ErrorInfo.Error = ErrorTy::NoStmt;
13301 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = ThenCS->getBeginLoc();
13302 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ThenCS->getSourceRange();
13303 return false;
13304 }
13305 if (ThenCS->size() > 1) {
13306 ErrorInfo.Error = ErrorTy::MoreThanOneStmt;
13307 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = ThenCS->getBeginLoc();
13308 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ThenCS->getSourceRange();
13309 return false;
13310 }
13311 Then = ThenCS->body_front();
13312 }
13313
13314 auto *ThenBO = dyn_cast<BinaryOperator>(Val: Then);
13315 if (!ThenBO) {
13316 ErrorInfo.Error = ErrorTy::NotAnAssignment;
13317 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S2->getBeginLoc();
13318 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S2->getSourceRange();
13319 return false;
13320 }
13321 if (ThenBO->getOpcode() != BO_Assign) {
13322 ErrorInfo.Error = ErrorTy::NotAnAssignment;
13323 ErrorInfo.ErrorLoc = ThenBO->getExprLoc();
13324 ErrorInfo.NoteLoc = ThenBO->getOperatorLoc();
13325 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ThenBO->getSourceRange();
13326 return false;
13327 }
13328
13329 X = ThenBO->getLHS();
13330 D = ThenBO->getRHS();
13331
13332 auto *BO = cast<BinaryOperator>(Val: S1->getRHS()->IgnoreImpCasts());
13333 if (BO->getOpcode() != BO_EQ) {
13334 ErrorInfo.Error = ErrorTy::NotEQ;
13335 ErrorInfo.ErrorLoc = BO->getExprLoc();
13336 ErrorInfo.NoteLoc = BO->getOperatorLoc();
13337 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange();
13338 return false;
13339 }
13340
13341 C = BO;
13342
13343 if (checkIfTwoExprsAreSame(Context&: ContextRef, LHS: X, RHS: BO->getLHS())) {
13344 E = BO->getRHS();
13345 } else if (checkIfTwoExprsAreSame(Context&: ContextRef, LHS: X, RHS: BO->getRHS())) {
13346 E = BO->getLHS();
13347 } else {
13348 ErrorInfo.Error = ErrorTy::InvalidComparison;
13349 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = BO->getExprLoc();
13350 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange();
13351 return false;
13352 }
13353
13354 if (S2->getElse()) {
13355 IsFailOnly = true;
13356
13357 auto *Else = S2->getElse();
13358 if (auto *ElseCS = dyn_cast<CompoundStmt>(Val: Else)) {
13359 if (ElseCS->body_empty()) {
13360 ErrorInfo.Error = ErrorTy::NoStmt;
13361 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = ElseCS->getBeginLoc();
13362 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ElseCS->getSourceRange();
13363 return false;
13364 }
13365 if (ElseCS->size() > 1) {
13366 ErrorInfo.Error = ErrorTy::MoreThanOneStmt;
13367 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = ElseCS->getBeginLoc();
13368 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ElseCS->getSourceRange();
13369 return false;
13370 }
13371 Else = ElseCS->body_front();
13372 }
13373
13374 auto *ElseBO = dyn_cast<BinaryOperator>(Val: Else);
13375 if (!ElseBO) {
13376 ErrorInfo.Error = ErrorTy::NotAnAssignment;
13377 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Else->getBeginLoc();
13378 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Else->getSourceRange();
13379 return false;
13380 }
13381 if (ElseBO->getOpcode() != BO_Assign) {
13382 ErrorInfo.Error = ErrorTy::NotAnAssignment;
13383 ErrorInfo.ErrorLoc = ElseBO->getExprLoc();
13384 ErrorInfo.NoteLoc = ElseBO->getOperatorLoc();
13385 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ElseBO->getSourceRange();
13386 return false;
13387 }
13388 if (!checkIfTwoExprsAreSame(Context&: ContextRef, LHS: X, RHS: ElseBO->getRHS())) {
13389 ErrorInfo.Error = ErrorTy::InvalidAssignment;
13390 ErrorInfo.ErrorLoc = ElseBO->getRHS()->getExprLoc();
13391 ErrorInfo.NoteLoc = X->getExprLoc();
13392 ErrorInfo.ErrorRange = ElseBO->getRHS()->getSourceRange();
13393 ErrorInfo.NoteRange = X->getSourceRange();
13394 return false;
13395 }
13396
13397 V = ElseBO->getLHS();
13398 }
13399
13400 return checkType(ErrorInfo);
13401}
13402
13403bool OpenMPAtomicCompareCaptureChecker::checkStmt(Stmt *S,
13404 ErrorInfoTy &ErrorInfo) {
13405 // if(x == e) { x = d; } else { v = x; }
13406 if (auto *IS = dyn_cast<IfStmt>(Val: S))
13407 return checkForm3(S: IS, ErrorInfo);
13408
13409 auto *CS = dyn_cast<CompoundStmt>(Val: S);
13410 if (!CS) {
13411 ErrorInfo.Error = ErrorTy::NotCompoundStmt;
13412 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getBeginLoc();
13413 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getSourceRange();
13414 return false;
13415 }
13416 if (CS->body_empty()) {
13417 ErrorInfo.Error = ErrorTy::NoStmt;
13418 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
13419 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange();
13420 return false;
13421 }
13422
13423 // { if(x == e) { x = d; } else { v = x; } }
13424 if (CS->size() == 1) {
13425 auto *IS = dyn_cast<IfStmt>(Val: CS->body_front());
13426 if (!IS) {
13427 ErrorInfo.Error = ErrorTy::NotIfStmt;
13428 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->body_front()->getBeginLoc();
13429 ErrorInfo.ErrorRange = ErrorInfo.NoteRange =
13430 CS->body_front()->getSourceRange();
13431 return false;
13432 }
13433
13434 return checkForm3(S: IS, ErrorInfo);
13435 } else if (CS->size() == 2) {
13436 auto *S1 = CS->body_front();
13437 auto *S2 = CS->body_back();
13438
13439 Stmt *UpdateStmt = nullptr;
13440 Stmt *CondUpdateStmt = nullptr;
13441 Stmt *CondExprStmt = nullptr;
13442
13443 if (auto *BO = dyn_cast<BinaryOperator>(Val: S1)) {
13444 // It could be one of the following cases:
13445 // { v = x; cond-update-stmt }
13446 // { v = x; cond-expr-stmt }
13447 // { cond-expr-stmt; v = x; }
13448 // form 45
13449 if (isa<BinaryOperator>(Val: BO->getRHS()->IgnoreImpCasts()) ||
13450 isa<ConditionalOperator>(Val: BO->getRHS()->IgnoreImpCasts())) {
13451 // check if form 45
13452 if (isa<IfStmt>(Val: S2))
13453 return checkForm45(S: CS, ErrorInfo);
13454 // { cond-expr-stmt; v = x; }
13455 CondExprStmt = S1;
13456 UpdateStmt = S2;
13457 } else {
13458 IsPostfixUpdate = true;
13459 UpdateStmt = S1;
13460 if (isa<IfStmt>(Val: S2)) {
13461 // { v = x; cond-update-stmt }
13462 CondUpdateStmt = S2;
13463 } else {
13464 // { v = x; cond-expr-stmt }
13465 CondExprStmt = S2;
13466 }
13467 }
13468 } else {
13469 // { cond-update-stmt v = x; }
13470 UpdateStmt = S2;
13471 CondUpdateStmt = S1;
13472 }
13473
13474 auto CheckCondUpdateStmt = [this, &ErrorInfo](Stmt *CUS) {
13475 auto *IS = dyn_cast<IfStmt>(Val: CUS);
13476 if (!IS) {
13477 ErrorInfo.Error = ErrorTy::NotIfStmt;
13478 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CUS->getBeginLoc();
13479 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CUS->getSourceRange();
13480 return false;
13481 }
13482
13483 return checkCondUpdateStmt(S: IS, ErrorInfo);
13484 };
13485
13486 // CheckUpdateStmt has to be called *after* CheckCondUpdateStmt.
13487 auto CheckUpdateStmt = [this, &ErrorInfo](Stmt *US) {
13488 auto *BO = dyn_cast<BinaryOperator>(Val: US);
13489 if (!BO) {
13490 ErrorInfo.Error = ErrorTy::NotAnAssignment;
13491 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = US->getBeginLoc();
13492 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = US->getSourceRange();
13493 return false;
13494 }
13495 if (BO->getOpcode() != BO_Assign) {
13496 ErrorInfo.Error = ErrorTy::NotAnAssignment;
13497 ErrorInfo.ErrorLoc = BO->getExprLoc();
13498 ErrorInfo.NoteLoc = BO->getOperatorLoc();
13499 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange();
13500 return false;
13501 }
13502 if (!checkIfTwoExprsAreSame(Context&: ContextRef, LHS: this->X, RHS: BO->getRHS())) {
13503 ErrorInfo.Error = ErrorTy::InvalidAssignment;
13504 ErrorInfo.ErrorLoc = BO->getRHS()->getExprLoc();
13505 ErrorInfo.NoteLoc = this->X->getExprLoc();
13506 ErrorInfo.ErrorRange = BO->getRHS()->getSourceRange();
13507 ErrorInfo.NoteRange = this->X->getSourceRange();
13508 return false;
13509 }
13510
13511 this->V = BO->getLHS();
13512
13513 return true;
13514 };
13515
13516 if (CondUpdateStmt && !CheckCondUpdateStmt(CondUpdateStmt))
13517 return false;
13518 if (CondExprStmt && !checkCondExprStmt(S: CondExprStmt, ErrorInfo))
13519 return false;
13520 if (!CheckUpdateStmt(UpdateStmt))
13521 return false;
13522 } else {
13523 ErrorInfo.Error = ErrorTy::MoreThanTwoStmts;
13524 ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
13525 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange();
13526 return false;
13527 }
13528
13529 return checkType(ErrorInfo);
13530}
13531} // namespace
13532
13533StmtResult SemaOpenMP::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
13534 Stmt *AStmt,
13535 SourceLocation StartLoc,
13536 SourceLocation EndLoc) {
13537 ASTContext &Context = getASTContext();
13538 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
13539 // Register location of the first atomic directive.
13540 DSAStack->addAtomicDirectiveLoc(Loc: StartLoc);
13541 if (!AStmt)
13542 return StmtError();
13543
13544 // 1.2.2 OpenMP Language Terminology
13545 // Structured block - An executable statement with a single entry at the
13546 // top and a single exit at the bottom.
13547 // The point of exit cannot be a branch out of the structured block.
13548 // longjmp() and throw() must not violate the entry/exit criteria.
13549 OpenMPClauseKind AtomicKind = OMPC_unknown;
13550 SourceLocation AtomicKindLoc;
13551 OpenMPClauseKind MemOrderKind = OMPC_unknown;
13552 SourceLocation MemOrderLoc;
13553 bool MutexClauseEncountered = false;
13554 llvm::SmallSet<OpenMPClauseKind, 2> EncounteredAtomicKinds;
13555 for (const OMPClause *C : Clauses) {
13556 switch (C->getClauseKind()) {
13557 case OMPC_read:
13558 case OMPC_write:
13559 case OMPC_update:
13560 MutexClauseEncountered = true;
13561 [[fallthrough]];
13562 case OMPC_capture:
13563 case OMPC_compare: {
13564 if (AtomicKind != OMPC_unknown && MutexClauseEncountered) {
13565 Diag(Loc: C->getBeginLoc(), DiagID: diag::err_omp_atomic_several_clauses)
13566 << SourceRange(C->getBeginLoc(), C->getEndLoc());
13567 Diag(Loc: AtomicKindLoc, DiagID: diag::note_omp_previous_mem_order_clause)
13568 << getOpenMPClauseNameForDiag(C: AtomicKind);
13569 } else {
13570 AtomicKind = C->getClauseKind();
13571 AtomicKindLoc = C->getBeginLoc();
13572 if (!EncounteredAtomicKinds.insert(V: C->getClauseKind()).second) {
13573 Diag(Loc: C->getBeginLoc(), DiagID: diag::err_omp_atomic_several_clauses)
13574 << SourceRange(C->getBeginLoc(), C->getEndLoc());
13575 Diag(Loc: AtomicKindLoc, DiagID: diag::note_omp_previous_mem_order_clause)
13576 << getOpenMPClauseNameForDiag(C: AtomicKind);
13577 }
13578 }
13579 break;
13580 }
13581 case OMPC_weak:
13582 case OMPC_fail: {
13583 if (!EncounteredAtomicKinds.contains(V: OMPC_compare)) {
13584 Diag(Loc: C->getBeginLoc(), DiagID: diag::err_omp_atomic_no_compare)
13585 << getOpenMPClauseNameForDiag(C: C->getClauseKind())
13586 << SourceRange(C->getBeginLoc(), C->getEndLoc());
13587 return StmtError();
13588 }
13589 break;
13590 }
13591 case OMPC_seq_cst:
13592 case OMPC_acq_rel:
13593 case OMPC_acquire:
13594 case OMPC_release:
13595 case OMPC_relaxed: {
13596 if (MemOrderKind != OMPC_unknown) {
13597 Diag(Loc: C->getBeginLoc(), DiagID: diag::err_omp_several_mem_order_clauses)
13598 << getOpenMPDirectiveName(D: OMPD_atomic, V: OMPVersion) << 0
13599 << SourceRange(C->getBeginLoc(), C->getEndLoc());
13600 Diag(Loc: MemOrderLoc, DiagID: diag::note_omp_previous_mem_order_clause)
13601 << getOpenMPClauseNameForDiag(C: MemOrderKind);
13602 } else {
13603 MemOrderKind = C->getClauseKind();
13604 MemOrderLoc = C->getBeginLoc();
13605 }
13606 break;
13607 }
13608 // The following clauses are allowed, but we don't need to do anything here.
13609 case OMPC_hint:
13610 break;
13611 default:
13612 llvm_unreachable("unknown clause is encountered");
13613 }
13614 }
13615 bool IsCompareCapture = false;
13616 if (EncounteredAtomicKinds.contains(V: OMPC_compare) &&
13617 EncounteredAtomicKinds.contains(V: OMPC_capture)) {
13618 IsCompareCapture = true;
13619 AtomicKind = OMPC_compare;
13620 }
13621 // OpenMP 5.0, 2.17.7 atomic Construct, Restrictions
13622 // If atomic-clause is read then memory-order-clause must not be acq_rel or
13623 // release.
13624 // If atomic-clause is write then memory-order-clause must not be acq_rel or
13625 // acquire.
13626 // If atomic-clause is update or not present then memory-order-clause must not
13627 // be acq_rel or acquire.
13628 if ((AtomicKind == OMPC_read &&
13629 (MemOrderKind == OMPC_acq_rel || MemOrderKind == OMPC_release)) ||
13630 ((AtomicKind == OMPC_write || AtomicKind == OMPC_update ||
13631 AtomicKind == OMPC_unknown) &&
13632 (MemOrderKind == OMPC_acq_rel || MemOrderKind == OMPC_acquire))) {
13633 SourceLocation Loc = AtomicKindLoc;
13634 if (AtomicKind == OMPC_unknown)
13635 Loc = StartLoc;
13636 Diag(Loc, DiagID: diag::err_omp_atomic_incompatible_mem_order_clause)
13637 << getOpenMPClauseNameForDiag(C: AtomicKind)
13638 << (AtomicKind == OMPC_unknown ? 1 : 0)
13639 << getOpenMPClauseNameForDiag(C: MemOrderKind);
13640 Diag(Loc: MemOrderLoc, DiagID: diag::note_omp_previous_mem_order_clause)
13641 << getOpenMPClauseNameForDiag(C: MemOrderKind);
13642 }
13643
13644 Stmt *Body = AStmt;
13645 if (auto *EWC = dyn_cast<ExprWithCleanups>(Val: Body))
13646 Body = EWC->getSubExpr();
13647
13648 Expr *X = nullptr;
13649 Expr *V = nullptr;
13650 Expr *E = nullptr;
13651 Expr *UE = nullptr;
13652 Expr *D = nullptr;
13653 Expr *CE = nullptr;
13654 Expr *R = nullptr;
13655 bool IsXLHSInRHSPart = false;
13656 bool IsPostfixUpdate = false;
13657 bool IsFailOnly = false;
13658 // OpenMP [2.12.6, atomic Construct]
13659 // In the next expressions:
13660 // * x and v (as applicable) are both l-value expressions with scalar type.
13661 // * During the execution of an atomic region, multiple syntactic
13662 // occurrences of x must designate the same storage location.
13663 // * Neither of v and expr (as applicable) may access the storage location
13664 // designated by x.
13665 // * Neither of x and expr (as applicable) may access the storage location
13666 // designated by v.
13667 // * expr is an expression with scalar type.
13668 // * binop is one of +, *, -, /, &, ^, |, <<, or >>.
13669 // * binop, binop=, ++, and -- are not overloaded operators.
13670 // * The expression x binop expr must be numerically equivalent to x binop
13671 // (expr). This requirement is satisfied if the operators in expr have
13672 // precedence greater than binop, or by using parentheses around expr or
13673 // subexpressions of expr.
13674 // * The expression expr binop x must be numerically equivalent to (expr)
13675 // binop x. This requirement is satisfied if the operators in expr have
13676 // precedence equal to or greater than binop, or by using parentheses around
13677 // expr or subexpressions of expr.
13678 // * For forms that allow multiple occurrences of x, the number of times
13679 // that x is evaluated is unspecified.
13680 if (AtomicKind == OMPC_read) {
13681 enum {
13682 NotAnExpression,
13683 NotAnAssignmentOp,
13684 NotAScalarType,
13685 NotAnLValue,
13686 NoError
13687 } ErrorFound = NoError;
13688 SourceLocation ErrorLoc, NoteLoc;
13689 SourceRange ErrorRange, NoteRange;
13690 // If clause is read:
13691 // v = x;
13692 if (const auto *AtomicBody = dyn_cast<Expr>(Val: Body)) {
13693 const auto *AtomicBinOp =
13694 dyn_cast<BinaryOperator>(Val: AtomicBody->IgnoreParenImpCasts());
13695 if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) {
13696 X = AtomicBinOp->getRHS()->IgnoreParenImpCasts();
13697 V = AtomicBinOp->getLHS()->IgnoreParenImpCasts();
13698 if ((X->isInstantiationDependent() || X->getType()->isScalarType()) &&
13699 (V->isInstantiationDependent() || V->getType()->isScalarType())) {
13700 if (!X->isLValue() || !V->isLValue()) {
13701 const Expr *NotLValueExpr = X->isLValue() ? V : X;
13702 ErrorFound = NotAnLValue;
13703 ErrorLoc = AtomicBinOp->getExprLoc();
13704 ErrorRange = AtomicBinOp->getSourceRange();
13705 NoteLoc = NotLValueExpr->getExprLoc();
13706 NoteRange = NotLValueExpr->getSourceRange();
13707 }
13708 } else if (!X->isInstantiationDependent() ||
13709 !V->isInstantiationDependent()) {
13710 const Expr *NotScalarExpr =
13711 (X->isInstantiationDependent() || X->getType()->isScalarType())
13712 ? V
13713 : X;
13714 ErrorFound = NotAScalarType;
13715 ErrorLoc = AtomicBinOp->getExprLoc();
13716 ErrorRange = AtomicBinOp->getSourceRange();
13717 NoteLoc = NotScalarExpr->getExprLoc();
13718 NoteRange = NotScalarExpr->getSourceRange();
13719 }
13720 } else if (!AtomicBody->isInstantiationDependent()) {
13721 ErrorFound = NotAnAssignmentOp;
13722 ErrorLoc = AtomicBody->getExprLoc();
13723 ErrorRange = AtomicBody->getSourceRange();
13724 NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc()
13725 : AtomicBody->getExprLoc();
13726 NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange()
13727 : AtomicBody->getSourceRange();
13728 }
13729 } else {
13730 ErrorFound = NotAnExpression;
13731 NoteLoc = ErrorLoc = Body->getBeginLoc();
13732 NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc);
13733 }
13734 if (ErrorFound != NoError) {
13735 Diag(Loc: ErrorLoc, DiagID: diag::err_omp_atomic_read_not_expression_statement)
13736 << ErrorRange;
13737 Diag(Loc: NoteLoc, DiagID: diag::note_omp_atomic_read_write)
13738 << ErrorFound << NoteRange;
13739 return StmtError();
13740 }
13741 if (SemaRef.CurContext->isDependentContext())
13742 V = X = nullptr;
13743 } else if (AtomicKind == OMPC_write) {
13744 enum {
13745 NotAnExpression,
13746 NotAnAssignmentOp,
13747 NotAScalarType,
13748 NotAnLValue,
13749 NoError
13750 } ErrorFound = NoError;
13751 SourceLocation ErrorLoc, NoteLoc;
13752 SourceRange ErrorRange, NoteRange;
13753 // If clause is write:
13754 // x = expr;
13755 if (const auto *AtomicBody = dyn_cast<Expr>(Val: Body)) {
13756 const auto *AtomicBinOp =
13757 dyn_cast<BinaryOperator>(Val: AtomicBody->IgnoreParenImpCasts());
13758 if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) {
13759 X = AtomicBinOp->getLHS();
13760 E = AtomicBinOp->getRHS();
13761 if ((X->isInstantiationDependent() || X->getType()->isScalarType()) &&
13762 (E->isInstantiationDependent() || E->getType()->isScalarType())) {
13763 if (!X->isLValue()) {
13764 ErrorFound = NotAnLValue;
13765 ErrorLoc = AtomicBinOp->getExprLoc();
13766 ErrorRange = AtomicBinOp->getSourceRange();
13767 NoteLoc = X->getExprLoc();
13768 NoteRange = X->getSourceRange();
13769 }
13770 } else if (!X->isInstantiationDependent() ||
13771 !E->isInstantiationDependent()) {
13772 const Expr *NotScalarExpr =
13773 (X->isInstantiationDependent() || X->getType()->isScalarType())
13774 ? E
13775 : X;
13776 ErrorFound = NotAScalarType;
13777 ErrorLoc = AtomicBinOp->getExprLoc();
13778 ErrorRange = AtomicBinOp->getSourceRange();
13779 NoteLoc = NotScalarExpr->getExprLoc();
13780 NoteRange = NotScalarExpr->getSourceRange();
13781 }
13782 } else if (!AtomicBody->isInstantiationDependent()) {
13783 ErrorFound = NotAnAssignmentOp;
13784 ErrorLoc = AtomicBody->getExprLoc();
13785 ErrorRange = AtomicBody->getSourceRange();
13786 NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc()
13787 : AtomicBody->getExprLoc();
13788 NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange()
13789 : AtomicBody->getSourceRange();
13790 }
13791 } else {
13792 ErrorFound = NotAnExpression;
13793 NoteLoc = ErrorLoc = Body->getBeginLoc();
13794 NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc);
13795 }
13796 if (ErrorFound != NoError) {
13797 Diag(Loc: ErrorLoc, DiagID: diag::err_omp_atomic_write_not_expression_statement)
13798 << ErrorRange;
13799 Diag(Loc: NoteLoc, DiagID: diag::note_omp_atomic_read_write)
13800 << ErrorFound << NoteRange;
13801 return StmtError();
13802 }
13803 if (SemaRef.CurContext->isDependentContext())
13804 E = X = nullptr;
13805 } else if (AtomicKind == OMPC_update || AtomicKind == OMPC_unknown) {
13806 // If clause is update:
13807 // x++;
13808 // x--;
13809 // ++x;
13810 // --x;
13811 // x binop= expr;
13812 // x = x binop expr;
13813 // x = expr binop x;
13814 OpenMPAtomicUpdateChecker Checker(SemaRef);
13815 if (Checker.checkStatement(
13816 S: Body,
13817 DiagId: (AtomicKind == OMPC_update)
13818 ? diag::err_omp_atomic_update_not_expression_statement
13819 : diag::err_omp_atomic_not_expression_statement,
13820 NoteId: diag::note_omp_atomic_update))
13821 return StmtError();
13822 if (!SemaRef.CurContext->isDependentContext()) {
13823 E = Checker.getExpr();
13824 X = Checker.getX();
13825 UE = Checker.getUpdateExpr();
13826 IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
13827 }
13828 } else if (AtomicKind == OMPC_capture) {
13829 enum {
13830 NotAnAssignmentOp,
13831 NotACompoundStatement,
13832 NotTwoSubstatements,
13833 NotASpecificExpression,
13834 NoError
13835 } ErrorFound = NoError;
13836 SourceLocation ErrorLoc, NoteLoc;
13837 SourceRange ErrorRange, NoteRange;
13838 if (const auto *AtomicBody = dyn_cast<Expr>(Val: Body)) {
13839 // If clause is a capture:
13840 // v = x++;
13841 // v = x--;
13842 // v = ++x;
13843 // v = --x;
13844 // v = x binop= expr;
13845 // v = x = x binop expr;
13846 // v = x = expr binop x;
13847 const auto *AtomicBinOp =
13848 dyn_cast<BinaryOperator>(Val: AtomicBody->IgnoreParenImpCasts());
13849 if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) {
13850 V = AtomicBinOp->getLHS();
13851 Body = AtomicBinOp->getRHS()->IgnoreParenImpCasts();
13852 OpenMPAtomicUpdateChecker Checker(SemaRef);
13853 if (Checker.checkStatement(
13854 S: Body, DiagId: diag::err_omp_atomic_capture_not_expression_statement,
13855 NoteId: diag::note_omp_atomic_update))
13856 return StmtError();
13857 E = Checker.getExpr();
13858 X = Checker.getX();
13859 UE = Checker.getUpdateExpr();
13860 IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
13861 IsPostfixUpdate = Checker.isPostfixUpdate();
13862 } else if (!AtomicBody->isInstantiationDependent()) {
13863 ErrorLoc = AtomicBody->getExprLoc();
13864 ErrorRange = AtomicBody->getSourceRange();
13865 NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc()
13866 : AtomicBody->getExprLoc();
13867 NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange()
13868 : AtomicBody->getSourceRange();
13869 ErrorFound = NotAnAssignmentOp;
13870 }
13871 if (ErrorFound != NoError) {
13872 Diag(Loc: ErrorLoc, DiagID: diag::err_omp_atomic_capture_not_expression_statement)
13873 << ErrorRange;
13874 Diag(Loc: NoteLoc, DiagID: diag::note_omp_atomic_capture) << ErrorFound << NoteRange;
13875 return StmtError();
13876 }
13877 if (SemaRef.CurContext->isDependentContext())
13878 UE = V = E = X = nullptr;
13879 } else {
13880 // If clause is a capture:
13881 // { v = x; x = expr; }
13882 // { v = x; x++; }
13883 // { v = x; x--; }
13884 // { v = x; ++x; }
13885 // { v = x; --x; }
13886 // { v = x; x binop= expr; }
13887 // { v = x; x = x binop expr; }
13888 // { v = x; x = expr binop x; }
13889 // { x++; v = x; }
13890 // { x--; v = x; }
13891 // { ++x; v = x; }
13892 // { --x; v = x; }
13893 // { x binop= expr; v = x; }
13894 // { x = x binop expr; v = x; }
13895 // { x = expr binop x; v = x; }
13896 if (auto *CS = dyn_cast<CompoundStmt>(Val: Body)) {
13897 // Check that this is { expr1; expr2; }
13898 if (CS->size() == 2) {
13899 Stmt *First = CS->body_front();
13900 Stmt *Second = CS->body_back();
13901 if (auto *EWC = dyn_cast<ExprWithCleanups>(Val: First))
13902 First = EWC->getSubExpr()->IgnoreParenImpCasts();
13903 if (auto *EWC = dyn_cast<ExprWithCleanups>(Val: Second))
13904 Second = EWC->getSubExpr()->IgnoreParenImpCasts();
13905 // Need to find what subexpression is 'v' and what is 'x'.
13906 OpenMPAtomicUpdateChecker Checker(SemaRef);
13907 bool IsUpdateExprFound = !Checker.checkStatement(S: Second);
13908 BinaryOperator *BinOp = nullptr;
13909 if (IsUpdateExprFound) {
13910 BinOp = dyn_cast<BinaryOperator>(Val: First);
13911 IsUpdateExprFound = BinOp && BinOp->getOpcode() == BO_Assign;
13912 }
13913 if (IsUpdateExprFound && !SemaRef.CurContext->isDependentContext()) {
13914 // { v = x; x++; }
13915 // { v = x; x--; }
13916 // { v = x; ++x; }
13917 // { v = x; --x; }
13918 // { v = x; x binop= expr; }
13919 // { v = x; x = x binop expr; }
13920 // { v = x; x = expr binop x; }
13921 // Check that the first expression has form v = x.
13922 Expr *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts();
13923 llvm::FoldingSetNodeID XId, PossibleXId;
13924 Checker.getX()->Profile(ID&: XId, Context, /*Canonical=*/true);
13925 PossibleX->Profile(ID&: PossibleXId, Context, /*Canonical=*/true);
13926 IsUpdateExprFound = XId == PossibleXId;
13927 if (IsUpdateExprFound) {
13928 V = BinOp->getLHS();
13929 X = Checker.getX();
13930 E = Checker.getExpr();
13931 UE = Checker.getUpdateExpr();
13932 IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
13933 IsPostfixUpdate = true;
13934 }
13935 }
13936 if (!IsUpdateExprFound) {
13937 IsUpdateExprFound = !Checker.checkStatement(S: First);
13938 BinOp = nullptr;
13939 if (IsUpdateExprFound) {
13940 BinOp = dyn_cast<BinaryOperator>(Val: Second);
13941 IsUpdateExprFound = BinOp && BinOp->getOpcode() == BO_Assign;
13942 }
13943 if (IsUpdateExprFound &&
13944 !SemaRef.CurContext->isDependentContext()) {
13945 // { x++; v = x; }
13946 // { x--; v = x; }
13947 // { ++x; v = x; }
13948 // { --x; v = x; }
13949 // { x binop= expr; v = x; }
13950 // { x = x binop expr; v = x; }
13951 // { x = expr binop x; v = x; }
13952 // Check that the second expression has form v = x.
13953 Expr *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts();
13954 llvm::FoldingSetNodeID XId, PossibleXId;
13955 Checker.getX()->Profile(ID&: XId, Context, /*Canonical=*/true);
13956 PossibleX->Profile(ID&: PossibleXId, Context, /*Canonical=*/true);
13957 IsUpdateExprFound = XId == PossibleXId;
13958 if (IsUpdateExprFound) {
13959 V = BinOp->getLHS();
13960 X = Checker.getX();
13961 E = Checker.getExpr();
13962 UE = Checker.getUpdateExpr();
13963 IsXLHSInRHSPart = Checker.isXLHSInRHSPart();
13964 IsPostfixUpdate = false;
13965 }
13966 }
13967 }
13968 if (!IsUpdateExprFound) {
13969 // { v = x; x = expr; }
13970 auto *FirstExpr = dyn_cast<Expr>(Val: First);
13971 auto *SecondExpr = dyn_cast<Expr>(Val: Second);
13972 if (!FirstExpr || !SecondExpr ||
13973 !(FirstExpr->isInstantiationDependent() ||
13974 SecondExpr->isInstantiationDependent())) {
13975 auto *FirstBinOp = dyn_cast<BinaryOperator>(Val: First);
13976 if (!FirstBinOp || FirstBinOp->getOpcode() != BO_Assign) {
13977 ErrorFound = NotAnAssignmentOp;
13978 NoteLoc = ErrorLoc = FirstBinOp ? FirstBinOp->getOperatorLoc()
13979 : First->getBeginLoc();
13980 NoteRange = ErrorRange = FirstBinOp
13981 ? FirstBinOp->getSourceRange()
13982 : SourceRange(ErrorLoc, ErrorLoc);
13983 } else {
13984 auto *SecondBinOp = dyn_cast<BinaryOperator>(Val: Second);
13985 if (!SecondBinOp || SecondBinOp->getOpcode() != BO_Assign) {
13986 ErrorFound = NotAnAssignmentOp;
13987 NoteLoc = ErrorLoc = SecondBinOp
13988 ? SecondBinOp->getOperatorLoc()
13989 : Second->getBeginLoc();
13990 NoteRange = ErrorRange =
13991 SecondBinOp ? SecondBinOp->getSourceRange()
13992 : SourceRange(ErrorLoc, ErrorLoc);
13993 } else {
13994 Expr *PossibleXRHSInFirst =
13995 FirstBinOp->getRHS()->IgnoreParenImpCasts();
13996 Expr *PossibleXLHSInSecond =
13997 SecondBinOp->getLHS()->IgnoreParenImpCasts();
13998 llvm::FoldingSetNodeID X1Id, X2Id;
13999 PossibleXRHSInFirst->Profile(ID&: X1Id, Context,
14000 /*Canonical=*/true);
14001 PossibleXLHSInSecond->Profile(ID&: X2Id, Context,
14002 /*Canonical=*/true);
14003 IsUpdateExprFound = X1Id == X2Id;
14004 if (IsUpdateExprFound) {
14005 V = FirstBinOp->getLHS();
14006 X = SecondBinOp->getLHS();
14007 E = SecondBinOp->getRHS();
14008 UE = nullptr;
14009 IsXLHSInRHSPart = false;
14010 IsPostfixUpdate = true;
14011 } else {
14012 ErrorFound = NotASpecificExpression;
14013 ErrorLoc = FirstBinOp->getExprLoc();
14014 ErrorRange = FirstBinOp->getSourceRange();
14015 NoteLoc = SecondBinOp->getLHS()->getExprLoc();
14016 NoteRange = SecondBinOp->getRHS()->getSourceRange();
14017 }
14018 }
14019 }
14020 }
14021 }
14022 } else {
14023 NoteLoc = ErrorLoc = Body->getBeginLoc();
14024 NoteRange = ErrorRange =
14025 SourceRange(Body->getBeginLoc(), Body->getBeginLoc());
14026 ErrorFound = NotTwoSubstatements;
14027 }
14028 } else {
14029 NoteLoc = ErrorLoc = Body->getBeginLoc();
14030 NoteRange = ErrorRange =
14031 SourceRange(Body->getBeginLoc(), Body->getBeginLoc());
14032 ErrorFound = NotACompoundStatement;
14033 }
14034 }
14035 if (ErrorFound != NoError) {
14036 Diag(Loc: ErrorLoc, DiagID: diag::err_omp_atomic_capture_not_compound_statement)
14037 << ErrorRange;
14038 Diag(Loc: NoteLoc, DiagID: diag::note_omp_atomic_capture) << ErrorFound << NoteRange;
14039 return StmtError();
14040 }
14041 if (SemaRef.CurContext->isDependentContext())
14042 UE = V = E = X = nullptr;
14043 } else if (AtomicKind == OMPC_compare) {
14044 if (IsCompareCapture) {
14045 OpenMPAtomicCompareCaptureChecker::ErrorInfoTy ErrorInfo;
14046 OpenMPAtomicCompareCaptureChecker Checker(SemaRef);
14047 if (!Checker.checkStmt(S: Body, ErrorInfo)) {
14048 Diag(Loc: ErrorInfo.ErrorLoc, DiagID: diag::err_omp_atomic_compare_capture)
14049 << ErrorInfo.ErrorRange;
14050 Diag(Loc: ErrorInfo.NoteLoc, DiagID: diag::note_omp_atomic_compare)
14051 << ErrorInfo.Error << ErrorInfo.NoteRange;
14052 return StmtError();
14053 }
14054 X = Checker.getX();
14055 E = Checker.getE();
14056 D = Checker.getD();
14057 CE = Checker.getCond();
14058 V = Checker.getV();
14059 R = Checker.getR();
14060 // We reuse IsXLHSInRHSPart to tell if it is in the form 'x ordop expr'.
14061 IsXLHSInRHSPart = Checker.isXBinopExpr();
14062 IsFailOnly = Checker.isFailOnly();
14063 IsPostfixUpdate = Checker.isPostfixUpdate();
14064 } else {
14065 OpenMPAtomicCompareChecker::ErrorInfoTy ErrorInfo;
14066 OpenMPAtomicCompareChecker Checker(SemaRef);
14067 if (!Checker.checkStmt(S: Body, ErrorInfo)) {
14068 Diag(Loc: ErrorInfo.ErrorLoc, DiagID: diag::err_omp_atomic_compare)
14069 << ErrorInfo.ErrorRange;
14070 Diag(Loc: ErrorInfo.NoteLoc, DiagID: diag::note_omp_atomic_compare)
14071 << ErrorInfo.Error << ErrorInfo.NoteRange;
14072 return StmtError();
14073 }
14074 X = Checker.getX();
14075 E = Checker.getE();
14076 D = Checker.getD();
14077 CE = Checker.getCond();
14078 // The weak clause may only appear if the resulting atomic operation is
14079 // an atomic conditional update for which the comparison tests for
14080 // equality. It was not possible to do this check in
14081 // OpenMPAtomicCompareChecker::checkStmt() as the check for OMPC_weak
14082 // could not be performed (Clauses are not available).
14083 auto *It = find_if(Range&: Clauses, P: [](OMPClause *C) {
14084 return C->getClauseKind() == llvm::omp::Clause::OMPC_weak;
14085 });
14086 if (It != Clauses.end()) {
14087 auto *Cond = dyn_cast<BinaryOperator>(Val: CE);
14088 if (Cond->getOpcode() != BO_EQ) {
14089 ErrorInfo.Error = Checker.ErrorTy::NotAnAssignment;
14090 ErrorInfo.ErrorLoc = Cond->getExprLoc();
14091 ErrorInfo.NoteLoc = Cond->getOperatorLoc();
14092 ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange();
14093
14094 Diag(Loc: ErrorInfo.ErrorLoc, DiagID: diag::err_omp_atomic_weak_no_equality)
14095 << ErrorInfo.ErrorRange;
14096 return StmtError();
14097 }
14098 }
14099 // We reuse IsXLHSInRHSPart to tell if it is in the form 'x ordop expr'.
14100 IsXLHSInRHSPart = Checker.isXBinopExpr();
14101 }
14102 }
14103
14104 SemaRef.setFunctionHasBranchProtectedScope();
14105
14106 return OMPAtomicDirective::Create(
14107 C: Context, StartLoc, EndLoc, Clauses, AssociatedStmt: AStmt,
14108 Exprs: {.X: X, .V: V, .R: R, .E: E, .UE: UE, .D: D, .Cond: CE, .IsXLHSInRHSPart: IsXLHSInRHSPart, .IsPostfixUpdate: IsPostfixUpdate, .IsFailOnly: IsFailOnly});
14109}
14110
14111StmtResult SemaOpenMP::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses,
14112 Stmt *AStmt,
14113 SourceLocation StartLoc,
14114 SourceLocation EndLoc) {
14115 if (!AStmt)
14116 return StmtError();
14117
14118 if (validateMultidimClauses(SemaRef&: *this, Clauses))
14119 return StmtError();
14120
14121 // Check for conflicting capture kinds on structured bindings.
14122 if (checkClausesForDecompositionConflicts(SemaRef, DKind: OMPD_target, Clauses))
14123 return StmtError();
14124
14125 if (checkOriginalVarMappedButOnlyBindingsUsed(SemaRef, Clauses, Body: AStmt))
14126 return StmtError();
14127
14128 CapturedStmt *CS = setBranchProtectedScope(SemaRef, DKind: OMPD_target, AStmt);
14129
14130 // OpenMP [2.16, Nesting of Regions]
14131 // If specified, a teams construct must be contained within a target
14132 // construct. That target construct must contain no statements or directives
14133 // outside of the teams construct.
14134 if (DSAStack->hasInnerTeamsRegion()) {
14135 const Stmt *S = CS->IgnoreContainers(/*IgnoreCaptured=*/true);
14136 bool OMPTeamsFound = true;
14137 if (const auto *CS = dyn_cast<CompoundStmt>(Val: S)) {
14138 auto I = CS->body_begin();
14139 while (I != CS->body_end()) {
14140 const auto *OED = dyn_cast<OMPExecutableDirective>(Val: *I);
14141 bool IsTeams = OED && isOpenMPTeamsDirective(DKind: OED->getDirectiveKind());
14142 if (!IsTeams || I != CS->body_begin()) {
14143 OMPTeamsFound = false;
14144 if (IsTeams && I != CS->body_begin()) {
14145 // This is the two teams case. Since the InnerTeamsRegionLoc will
14146 // point to this second one reset the iterator to the other teams.
14147 --I;
14148 }
14149 break;
14150 }
14151 ++I;
14152 }
14153 assert(I != CS->body_end() && "Not found statement");
14154 S = *I;
14155 } else {
14156 const auto *OED = dyn_cast<OMPExecutableDirective>(Val: S);
14157 OMPTeamsFound = OED && isOpenMPTeamsDirective(DKind: OED->getDirectiveKind());
14158 }
14159 if (!OMPTeamsFound) {
14160 Diag(Loc: StartLoc, DiagID: diag::err_omp_target_contains_not_only_teams);
14161 Diag(DSAStack->getInnerTeamsRegionLoc(),
14162 DiagID: diag::note_omp_nested_teams_construct_here);
14163 Diag(Loc: S->getBeginLoc(), DiagID: diag::note_omp_nested_statement_here)
14164 << isa<OMPExecutableDirective>(Val: S);
14165 return StmtError();
14166 }
14167 }
14168
14169 return OMPTargetDirective::Create(C: getASTContext(), StartLoc, EndLoc, Clauses,
14170 AssociatedStmt: AStmt);
14171}
14172
14173StmtResult SemaOpenMP::ActOnOpenMPTargetParallelDirective(
14174 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14175 SourceLocation EndLoc) {
14176 if (!AStmt)
14177 return StmtError();
14178
14179 if (validateMultidimClauses(SemaRef&: *this, Clauses))
14180 return StmtError();
14181
14182 // Check for conflicting capture kinds on structured bindings.
14183 if (checkClausesForDecompositionConflicts(SemaRef, DKind: OMPD_target_parallel,
14184 Clauses))
14185 return StmtError();
14186
14187 if (checkOriginalVarMappedButOnlyBindingsUsed(SemaRef, Clauses, Body: AStmt))
14188 return StmtError();
14189
14190 setBranchProtectedScope(SemaRef, DKind: OMPD_target_parallel, AStmt);
14191
14192 return OMPTargetParallelDirective::Create(
14193 C: getASTContext(), StartLoc, EndLoc, Clauses, AssociatedStmt: AStmt,
14194 DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
14195}
14196
14197StmtResult SemaOpenMP::ActOnOpenMPTargetParallelForDirective(
14198 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14199 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14200 if (!AStmt)
14201 return StmtError();
14202
14203 if (validateMultidimClauses(SemaRef&: *this, Clauses))
14204 return StmtError();
14205
14206 if (checkClausesForDecompositionConflicts(SemaRef, DKind: OMPD_target_parallel_for,
14207 Clauses))
14208 return StmtError();
14209
14210 if (checkOriginalVarMappedButOnlyBindingsUsed(SemaRef, Clauses, Body: AStmt))
14211 return StmtError();
14212
14213 CapturedStmt *CS =
14214 setBranchProtectedScope(SemaRef, DKind: OMPD_target_parallel_for, AStmt);
14215
14216 OMPLoopBasedDirective::HelperExprs B;
14217 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
14218 // define the nested loops number.
14219 unsigned NestedLoopCount =
14220 checkOpenMPLoop(DKind: OMPD_target_parallel_for, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
14221 OrderedLoopCountExpr: getOrderedNumberExpr(Clauses), AStmt: CS, SemaRef, DSA&: *DSAStack,
14222 VarsWithImplicitDSA, Built&: B);
14223 if (NestedLoopCount == 0)
14224 return StmtError();
14225
14226 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
14227 return StmtError();
14228
14229 return OMPTargetParallelForDirective::Create(
14230 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B,
14231 DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
14232}
14233
14234/// Check for existence of a map clause in the list of clauses.
14235static bool hasClauses(ArrayRef<OMPClause *> Clauses,
14236 const OpenMPClauseKind K) {
14237 return llvm::any_of(
14238 Range&: Clauses, P: [K](const OMPClause *C) { return C->getClauseKind() == K; });
14239}
14240
14241template <typename... Params>
14242static bool hasClauses(ArrayRef<OMPClause *> Clauses, const OpenMPClauseKind K,
14243 const Params... ClauseTypes) {
14244 return hasClauses(Clauses, K) || hasClauses(Clauses, ClauseTypes...);
14245}
14246
14247/// Check if the variables in the mapping clause are externally visible.
14248static bool isClauseMappable(ArrayRef<OMPClause *> Clauses) {
14249 for (const OMPClause *C : Clauses) {
14250 if (auto *TC = dyn_cast<OMPToClause>(Val: C))
14251 return llvm::all_of(Range: TC->all_decls(), P: [](ValueDecl *VD) {
14252 return !VD || !VD->hasAttr<OMPDeclareTargetDeclAttr>() ||
14253 (VD->isExternallyVisible() &&
14254 VD->getVisibility() != HiddenVisibility);
14255 });
14256 else if (auto *FC = dyn_cast<OMPFromClause>(Val: C))
14257 return llvm::all_of(Range: FC->all_decls(), P: [](ValueDecl *VD) {
14258 return !VD || !VD->hasAttr<OMPDeclareTargetDeclAttr>() ||
14259 (VD->isExternallyVisible() &&
14260 VD->getVisibility() != HiddenVisibility);
14261 });
14262 }
14263
14264 return true;
14265}
14266
14267StmtResult
14268SemaOpenMP::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses,
14269 Stmt *AStmt, SourceLocation StartLoc,
14270 SourceLocation EndLoc) {
14271 if (!AStmt)
14272 return StmtError();
14273
14274 assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
14275
14276 // OpenMP [2.12.2, target data Construct, Restrictions]
14277 // At least one map, use_device_addr or use_device_ptr clause must appear on
14278 // the directive.
14279 if (!hasClauses(Clauses, K: OMPC_map, ClauseTypes: OMPC_use_device_ptr) &&
14280 (getLangOpts().OpenMP < 50 ||
14281 !hasClauses(Clauses, K: OMPC_use_device_addr))) {
14282 StringRef Expected;
14283 if (getLangOpts().OpenMP < 50)
14284 Expected = "'map' or 'use_device_ptr'";
14285 else
14286 Expected = "'map', 'use_device_ptr', or 'use_device_addr'";
14287 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
14288 Diag(Loc: StartLoc, DiagID: diag::err_omp_no_clause_for_directive)
14289 << Expected << getOpenMPDirectiveName(D: OMPD_target_data, V: OMPVersion);
14290 return StmtError();
14291 }
14292
14293 SemaRef.setFunctionHasBranchProtectedScope();
14294
14295 return OMPTargetDataDirective::Create(C: getASTContext(), StartLoc, EndLoc,
14296 Clauses, AssociatedStmt: AStmt);
14297}
14298
14299StmtResult SemaOpenMP::ActOnOpenMPTargetEnterDataDirective(
14300 ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc,
14301 SourceLocation EndLoc, Stmt *AStmt) {
14302 if (!AStmt)
14303 return StmtError();
14304
14305 setBranchProtectedScope(SemaRef, DKind: OMPD_target_enter_data, AStmt);
14306
14307 // OpenMP [2.10.2, Restrictions, p. 99]
14308 // At least one map clause must appear on the directive.
14309 if (!hasClauses(Clauses, K: OMPC_map)) {
14310 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
14311 Diag(Loc: StartLoc, DiagID: diag::err_omp_no_clause_for_directive)
14312 << "'map'"
14313 << getOpenMPDirectiveName(D: OMPD_target_enter_data, V: OMPVersion);
14314 return StmtError();
14315 }
14316
14317 return OMPTargetEnterDataDirective::Create(C: getASTContext(), StartLoc, EndLoc,
14318 Clauses, AssociatedStmt: AStmt);
14319}
14320
14321StmtResult SemaOpenMP::ActOnOpenMPTargetExitDataDirective(
14322 ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc,
14323 SourceLocation EndLoc, Stmt *AStmt) {
14324 if (!AStmt)
14325 return StmtError();
14326
14327 setBranchProtectedScope(SemaRef, DKind: OMPD_target_exit_data, AStmt);
14328
14329 // OpenMP [2.10.3, Restrictions, p. 102]
14330 // At least one map clause must appear on the directive.
14331 if (!hasClauses(Clauses, K: OMPC_map)) {
14332 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
14333 Diag(Loc: StartLoc, DiagID: diag::err_omp_no_clause_for_directive)
14334 << "'map'" << getOpenMPDirectiveName(D: OMPD_target_exit_data, V: OMPVersion);
14335 return StmtError();
14336 }
14337
14338 return OMPTargetExitDataDirective::Create(C: getASTContext(), StartLoc, EndLoc,
14339 Clauses, AssociatedStmt: AStmt);
14340}
14341
14342StmtResult SemaOpenMP::ActOnOpenMPTargetUpdateDirective(
14343 ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc,
14344 SourceLocation EndLoc, Stmt *AStmt) {
14345 if (!AStmt)
14346 return StmtError();
14347
14348 setBranchProtectedScope(SemaRef, DKind: OMPD_target_update, AStmt);
14349
14350 if (!hasClauses(Clauses, K: OMPC_to, ClauseTypes: OMPC_from)) {
14351 Diag(Loc: StartLoc, DiagID: diag::err_omp_at_least_one_motion_clause_required);
14352 return StmtError();
14353 }
14354
14355 if (!isClauseMappable(Clauses)) {
14356 Diag(Loc: StartLoc, DiagID: diag::err_omp_cannot_update_with_internal_linkage);
14357 return StmtError();
14358 }
14359
14360 return OMPTargetUpdateDirective::Create(C: getASTContext(), StartLoc, EndLoc,
14361 Clauses, AssociatedStmt: AStmt);
14362}
14363
14364StmtResult SemaOpenMP::ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses,
14365 Stmt *AStmt,
14366 SourceLocation StartLoc,
14367 SourceLocation EndLoc) {
14368 if (!AStmt)
14369 return StmtError();
14370
14371 if (validateMultidimClauses(SemaRef&: *this, Clauses))
14372 return StmtError();
14373
14374 if (checkClausesForDecompositionConflicts(SemaRef, DKind: OMPD_teams, Clauses))
14375 return StmtError();
14376
14377 // Report affected OpenMP target offloading behavior when in HIP lang-mode.
14378 if (getLangOpts().HIP && (DSAStack->getParentDirective() == OMPD_target))
14379 Diag(Loc: StartLoc, DiagID: diag::warn_hip_omp_target_directives);
14380
14381 setBranchProtectedScope(SemaRef, DKind: OMPD_teams, AStmt);
14382
14383 DSAStack->setParentTeamsRegionLoc(StartLoc);
14384
14385 return OMPTeamsDirective::Create(C: getASTContext(), StartLoc, EndLoc, Clauses,
14386 AssociatedStmt: AStmt);
14387}
14388
14389StmtResult SemaOpenMP::ActOnOpenMPCancellationPointDirective(
14390 SourceLocation StartLoc, SourceLocation EndLoc,
14391 OpenMPDirectiveKind CancelRegion) {
14392 if (DSAStack->isParentNowaitRegion()) {
14393 Diag(Loc: StartLoc, DiagID: diag::err_omp_parent_cancel_region_nowait) << 0;
14394 return StmtError();
14395 }
14396 if (DSAStack->isParentOrderedRegion()) {
14397 Diag(Loc: StartLoc, DiagID: diag::err_omp_parent_cancel_region_ordered) << 0;
14398 return StmtError();
14399 }
14400 return OMPCancellationPointDirective::Create(C: getASTContext(), StartLoc,
14401 EndLoc, CancelRegion);
14402}
14403
14404StmtResult SemaOpenMP::ActOnOpenMPCancelDirective(
14405 ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc,
14406 SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion) {
14407 if (DSAStack->isParentNowaitRegion()) {
14408 Diag(Loc: StartLoc, DiagID: diag::err_omp_parent_cancel_region_nowait) << 1;
14409 return StmtError();
14410 }
14411 if (DSAStack->isParentOrderedRegion()) {
14412 Diag(Loc: StartLoc, DiagID: diag::err_omp_parent_cancel_region_ordered) << 1;
14413 return StmtError();
14414 }
14415 DSAStack->setParentCancelRegion(/*Cancel=*/true);
14416 return OMPCancelDirective::Create(C: getASTContext(), StartLoc, EndLoc, Clauses,
14417 CancelRegion);
14418}
14419
14420static bool checkReductionClauseWithNogroup(Sema &S,
14421 ArrayRef<OMPClause *> Clauses) {
14422 const OMPClause *ReductionClause = nullptr;
14423 const OMPClause *NogroupClause = nullptr;
14424 for (const OMPClause *C : Clauses) {
14425 if (C->getClauseKind() == OMPC_reduction) {
14426 ReductionClause = C;
14427 if (NogroupClause)
14428 break;
14429 continue;
14430 }
14431 if (C->getClauseKind() == OMPC_nogroup) {
14432 NogroupClause = C;
14433 if (ReductionClause)
14434 break;
14435 continue;
14436 }
14437 }
14438 if (ReductionClause && NogroupClause) {
14439 S.Diag(Loc: ReductionClause->getBeginLoc(), DiagID: diag::err_omp_reduction_with_nogroup)
14440 << SourceRange(NogroupClause->getBeginLoc(),
14441 NogroupClause->getEndLoc());
14442 return true;
14443 }
14444 return false;
14445}
14446
14447StmtResult SemaOpenMP::ActOnOpenMPTaskLoopDirective(
14448 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14449 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14450 if (!AStmt)
14451 return StmtError();
14452
14453 assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
14454 OMPLoopBasedDirective::HelperExprs B;
14455 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
14456 // define the nested loops number.
14457 unsigned NestedLoopCount =
14458 checkOpenMPLoop(DKind: OMPD_taskloop, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
14459 /*OrderedLoopCountExpr=*/nullptr, AStmt, SemaRef,
14460 DSA&: *DSAStack, VarsWithImplicitDSA, Built&: B);
14461 if (NestedLoopCount == 0)
14462 return StmtError();
14463
14464 assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) &&
14465 "omp for loop exprs were not built");
14466
14467 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14468 // The grainsize clause and num_tasks clause are mutually exclusive and may
14469 // not appear on the same taskloop directive.
14470 if (checkMutuallyExclusiveClauses(S&: SemaRef, Clauses,
14471 MutuallyExclusiveClauses: {OMPC_grainsize, OMPC_num_tasks}))
14472 return StmtError();
14473 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14474 // If a reduction clause is present on the taskloop directive, the nogroup
14475 // clause must not be specified.
14476 if (checkReductionClauseWithNogroup(S&: SemaRef, Clauses))
14477 return StmtError();
14478
14479 SemaRef.setFunctionHasBranchProtectedScope();
14480 return OMPTaskLoopDirective::Create(C: getASTContext(), StartLoc, EndLoc,
14481 CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B,
14482 DSAStack->isCancelRegion());
14483}
14484
14485StmtResult SemaOpenMP::ActOnOpenMPTaskLoopSimdDirective(
14486 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14487 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14488 if (!AStmt)
14489 return StmtError();
14490
14491 CapturedStmt *CS =
14492 setBranchProtectedScope(SemaRef, DKind: OMPD_taskloop_simd, AStmt);
14493
14494 assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
14495 OMPLoopBasedDirective::HelperExprs B;
14496 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
14497 // define the nested loops number.
14498 unsigned NestedLoopCount =
14499 checkOpenMPLoop(DKind: OMPD_taskloop_simd, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
14500 /*OrderedLoopCountExpr=*/nullptr, AStmt: CS, SemaRef, DSA&: *DSAStack,
14501 VarsWithImplicitDSA, Built&: B);
14502 if (NestedLoopCount == 0)
14503 return StmtError();
14504
14505 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
14506 return StmtError();
14507
14508 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14509 // The grainsize clause and num_tasks clause are mutually exclusive and may
14510 // not appear on the same taskloop directive.
14511 if (checkMutuallyExclusiveClauses(S&: SemaRef, Clauses,
14512 MutuallyExclusiveClauses: {OMPC_grainsize, OMPC_num_tasks}))
14513 return StmtError();
14514 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14515 // If a reduction clause is present on the taskloop directive, the nogroup
14516 // clause must not be specified.
14517 if (checkReductionClauseWithNogroup(S&: SemaRef, Clauses))
14518 return StmtError();
14519 if (checkSimdlenSafelenSpecified(S&: SemaRef, Clauses))
14520 return StmtError();
14521
14522 return OMPTaskLoopSimdDirective::Create(C: getASTContext(), StartLoc, EndLoc,
14523 CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
14524}
14525
14526StmtResult SemaOpenMP::ActOnOpenMPMasterTaskLoopDirective(
14527 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14528 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14529 if (!AStmt)
14530 return StmtError();
14531
14532 assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
14533 OMPLoopBasedDirective::HelperExprs B;
14534 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
14535 // define the nested loops number.
14536 unsigned NestedLoopCount =
14537 checkOpenMPLoop(DKind: OMPD_master_taskloop, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
14538 /*OrderedLoopCountExpr=*/nullptr, AStmt, SemaRef,
14539 DSA&: *DSAStack, VarsWithImplicitDSA, Built&: B);
14540 if (NestedLoopCount == 0)
14541 return StmtError();
14542
14543 assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) &&
14544 "omp for loop exprs were not built");
14545
14546 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14547 // The grainsize clause and num_tasks clause are mutually exclusive and may
14548 // not appear on the same taskloop directive.
14549 if (checkMutuallyExclusiveClauses(S&: SemaRef, Clauses,
14550 MutuallyExclusiveClauses: {OMPC_grainsize, OMPC_num_tasks}))
14551 return StmtError();
14552 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14553 // If a reduction clause is present on the taskloop directive, the nogroup
14554 // clause must not be specified.
14555 if (checkReductionClauseWithNogroup(S&: SemaRef, Clauses))
14556 return StmtError();
14557
14558 SemaRef.setFunctionHasBranchProtectedScope();
14559 return OMPMasterTaskLoopDirective::Create(C: getASTContext(), StartLoc, EndLoc,
14560 CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B,
14561 DSAStack->isCancelRegion());
14562}
14563
14564StmtResult SemaOpenMP::ActOnOpenMPMaskedTaskLoopDirective(
14565 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14566 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14567 if (!AStmt)
14568 return StmtError();
14569
14570 assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
14571 OMPLoopBasedDirective::HelperExprs B;
14572 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
14573 // define the nested loops number.
14574 unsigned NestedLoopCount =
14575 checkOpenMPLoop(DKind: OMPD_masked_taskloop, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
14576 /*OrderedLoopCountExpr=*/nullptr, AStmt, SemaRef,
14577 DSA&: *DSAStack, VarsWithImplicitDSA, Built&: B);
14578 if (NestedLoopCount == 0)
14579 return StmtError();
14580
14581 assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) &&
14582 "omp for loop exprs were not built");
14583
14584 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14585 // The grainsize clause and num_tasks clause are mutually exclusive and may
14586 // not appear on the same taskloop directive.
14587 if (checkMutuallyExclusiveClauses(S&: SemaRef, Clauses,
14588 MutuallyExclusiveClauses: {OMPC_grainsize, OMPC_num_tasks}))
14589 return StmtError();
14590 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14591 // If a reduction clause is present on the taskloop directive, the nogroup
14592 // clause must not be specified.
14593 if (checkReductionClauseWithNogroup(S&: SemaRef, Clauses))
14594 return StmtError();
14595
14596 SemaRef.setFunctionHasBranchProtectedScope();
14597 return OMPMaskedTaskLoopDirective::Create(C: getASTContext(), StartLoc, EndLoc,
14598 CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B,
14599 DSAStack->isCancelRegion());
14600}
14601
14602StmtResult SemaOpenMP::ActOnOpenMPMasterTaskLoopSimdDirective(
14603 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14604 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14605 if (!AStmt)
14606 return StmtError();
14607
14608 CapturedStmt *CS =
14609 setBranchProtectedScope(SemaRef, DKind: OMPD_master_taskloop_simd, AStmt);
14610
14611 assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
14612 OMPLoopBasedDirective::HelperExprs B;
14613 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
14614 // define the nested loops number.
14615 unsigned NestedLoopCount =
14616 checkOpenMPLoop(DKind: OMPD_master_taskloop_simd, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
14617 /*OrderedLoopCountExpr=*/nullptr, AStmt: CS, SemaRef, DSA&: *DSAStack,
14618 VarsWithImplicitDSA, Built&: B);
14619 if (NestedLoopCount == 0)
14620 return StmtError();
14621
14622 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
14623 return StmtError();
14624
14625 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14626 // The grainsize clause and num_tasks clause are mutually exclusive and may
14627 // not appear on the same taskloop directive.
14628 if (checkMutuallyExclusiveClauses(S&: SemaRef, Clauses,
14629 MutuallyExclusiveClauses: {OMPC_grainsize, OMPC_num_tasks}))
14630 return StmtError();
14631 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14632 // If a reduction clause is present on the taskloop directive, the nogroup
14633 // clause must not be specified.
14634 if (checkReductionClauseWithNogroup(S&: SemaRef, Clauses))
14635 return StmtError();
14636 if (checkSimdlenSafelenSpecified(S&: SemaRef, Clauses))
14637 return StmtError();
14638
14639 return OMPMasterTaskLoopSimdDirective::Create(
14640 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
14641}
14642
14643StmtResult SemaOpenMP::ActOnOpenMPMaskedTaskLoopSimdDirective(
14644 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14645 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14646 if (!AStmt)
14647 return StmtError();
14648
14649 CapturedStmt *CS =
14650 setBranchProtectedScope(SemaRef, DKind: OMPD_masked_taskloop_simd, AStmt);
14651
14652 assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
14653 OMPLoopBasedDirective::HelperExprs B;
14654 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
14655 // define the nested loops number.
14656 unsigned NestedLoopCount =
14657 checkOpenMPLoop(DKind: OMPD_masked_taskloop_simd, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
14658 /*OrderedLoopCountExpr=*/nullptr, AStmt: CS, SemaRef, DSA&: *DSAStack,
14659 VarsWithImplicitDSA, Built&: B);
14660 if (NestedLoopCount == 0)
14661 return StmtError();
14662
14663 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
14664 return StmtError();
14665
14666 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14667 // The grainsize clause and num_tasks clause are mutually exclusive and may
14668 // not appear on the same taskloop directive.
14669 if (checkMutuallyExclusiveClauses(S&: SemaRef, Clauses,
14670 MutuallyExclusiveClauses: {OMPC_grainsize, OMPC_num_tasks}))
14671 return StmtError();
14672 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14673 // If a reduction clause is present on the taskloop directive, the nogroup
14674 // clause must not be specified.
14675 if (checkReductionClauseWithNogroup(S&: SemaRef, Clauses))
14676 return StmtError();
14677 if (checkSimdlenSafelenSpecified(S&: SemaRef, Clauses))
14678 return StmtError();
14679
14680 return OMPMaskedTaskLoopSimdDirective::Create(
14681 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
14682}
14683
14684StmtResult SemaOpenMP::ActOnOpenMPParallelMasterTaskLoopDirective(
14685 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14686 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14687 if (!AStmt)
14688 return StmtError();
14689
14690 CapturedStmt *CS =
14691 setBranchProtectedScope(SemaRef, DKind: OMPD_parallel_master_taskloop, AStmt);
14692
14693 OMPLoopBasedDirective::HelperExprs B;
14694 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
14695 // define the nested loops number.
14696 unsigned NestedLoopCount = checkOpenMPLoop(
14697 DKind: OMPD_parallel_master_taskloop, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
14698 /*OrderedLoopCountExpr=*/nullptr, AStmt: CS, SemaRef, DSA&: *DSAStack,
14699 VarsWithImplicitDSA, Built&: B);
14700 if (NestedLoopCount == 0)
14701 return StmtError();
14702
14703 assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) &&
14704 "omp for loop exprs were not built");
14705
14706 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14707 // The grainsize clause and num_tasks clause are mutually exclusive and may
14708 // not appear on the same taskloop directive.
14709 if (checkMutuallyExclusiveClauses(S&: SemaRef, Clauses,
14710 MutuallyExclusiveClauses: {OMPC_grainsize, OMPC_num_tasks}))
14711 return StmtError();
14712 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14713 // If a reduction clause is present on the taskloop directive, the nogroup
14714 // clause must not be specified.
14715 if (checkReductionClauseWithNogroup(S&: SemaRef, Clauses))
14716 return StmtError();
14717
14718 return OMPParallelMasterTaskLoopDirective::Create(
14719 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B,
14720 DSAStack->isCancelRegion());
14721}
14722
14723StmtResult SemaOpenMP::ActOnOpenMPParallelMaskedTaskLoopDirective(
14724 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14725 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14726 if (!AStmt)
14727 return StmtError();
14728
14729 CapturedStmt *CS =
14730 setBranchProtectedScope(SemaRef, DKind: OMPD_parallel_masked_taskloop, AStmt);
14731
14732 OMPLoopBasedDirective::HelperExprs B;
14733 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
14734 // define the nested loops number.
14735 unsigned NestedLoopCount = checkOpenMPLoop(
14736 DKind: OMPD_parallel_masked_taskloop, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
14737 /*OrderedLoopCountExpr=*/nullptr, AStmt: CS, SemaRef, DSA&: *DSAStack,
14738 VarsWithImplicitDSA, Built&: B);
14739 if (NestedLoopCount == 0)
14740 return StmtError();
14741
14742 assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) &&
14743 "omp for loop exprs were not built");
14744
14745 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14746 // The grainsize clause and num_tasks clause are mutually exclusive and may
14747 // not appear on the same taskloop directive.
14748 if (checkMutuallyExclusiveClauses(S&: SemaRef, Clauses,
14749 MutuallyExclusiveClauses: {OMPC_grainsize, OMPC_num_tasks}))
14750 return StmtError();
14751 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14752 // If a reduction clause is present on the taskloop directive, the nogroup
14753 // clause must not be specified.
14754 if (checkReductionClauseWithNogroup(S&: SemaRef, Clauses))
14755 return StmtError();
14756
14757 return OMPParallelMaskedTaskLoopDirective::Create(
14758 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B,
14759 DSAStack->isCancelRegion());
14760}
14761
14762StmtResult SemaOpenMP::ActOnOpenMPParallelMasterTaskLoopSimdDirective(
14763 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14764 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14765 if (!AStmt)
14766 return StmtError();
14767
14768 CapturedStmt *CS = setBranchProtectedScope(
14769 SemaRef, DKind: OMPD_parallel_master_taskloop_simd, AStmt);
14770
14771 OMPLoopBasedDirective::HelperExprs B;
14772 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
14773 // define the nested loops number.
14774 unsigned NestedLoopCount = checkOpenMPLoop(
14775 DKind: OMPD_parallel_master_taskloop_simd, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
14776 /*OrderedLoopCountExpr=*/nullptr, AStmt: CS, SemaRef, DSA&: *DSAStack,
14777 VarsWithImplicitDSA, Built&: B);
14778 if (NestedLoopCount == 0)
14779 return StmtError();
14780
14781 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
14782 return StmtError();
14783
14784 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14785 // The grainsize clause and num_tasks clause are mutually exclusive and may
14786 // not appear on the same taskloop directive.
14787 if (checkMutuallyExclusiveClauses(S&: SemaRef, Clauses,
14788 MutuallyExclusiveClauses: {OMPC_grainsize, OMPC_num_tasks}))
14789 return StmtError();
14790 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14791 // If a reduction clause is present on the taskloop directive, the nogroup
14792 // clause must not be specified.
14793 if (checkReductionClauseWithNogroup(S&: SemaRef, Clauses))
14794 return StmtError();
14795 if (checkSimdlenSafelenSpecified(S&: SemaRef, Clauses))
14796 return StmtError();
14797
14798 return OMPParallelMasterTaskLoopSimdDirective::Create(
14799 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
14800}
14801
14802StmtResult SemaOpenMP::ActOnOpenMPParallelMaskedTaskLoopSimdDirective(
14803 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14804 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14805 if (!AStmt)
14806 return StmtError();
14807
14808 CapturedStmt *CS = setBranchProtectedScope(
14809 SemaRef, DKind: OMPD_parallel_masked_taskloop_simd, AStmt);
14810
14811 OMPLoopBasedDirective::HelperExprs B;
14812 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
14813 // define the nested loops number.
14814 unsigned NestedLoopCount = checkOpenMPLoop(
14815 DKind: OMPD_parallel_masked_taskloop_simd, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
14816 /*OrderedLoopCountExpr=*/nullptr, AStmt: CS, SemaRef, DSA&: *DSAStack,
14817 VarsWithImplicitDSA, Built&: B);
14818 if (NestedLoopCount == 0)
14819 return StmtError();
14820
14821 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
14822 return StmtError();
14823
14824 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14825 // The grainsize clause and num_tasks clause are mutually exclusive and may
14826 // not appear on the same taskloop directive.
14827 if (checkMutuallyExclusiveClauses(S&: SemaRef, Clauses,
14828 MutuallyExclusiveClauses: {OMPC_grainsize, OMPC_num_tasks}))
14829 return StmtError();
14830 // OpenMP, [2.9.2 taskloop Construct, Restrictions]
14831 // If a reduction clause is present on the taskloop directive, the nogroup
14832 // clause must not be specified.
14833 if (checkReductionClauseWithNogroup(S&: SemaRef, Clauses))
14834 return StmtError();
14835 if (checkSimdlenSafelenSpecified(S&: SemaRef, Clauses))
14836 return StmtError();
14837
14838 return OMPParallelMaskedTaskLoopSimdDirective::Create(
14839 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
14840}
14841
14842StmtResult SemaOpenMP::ActOnOpenMPDistributeDirective(
14843 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14844 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14845 if (!AStmt)
14846 return StmtError();
14847
14848 assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
14849 OMPLoopBasedDirective::HelperExprs B;
14850 // In presence of clause 'collapse' with number of loops, it will
14851 // define the nested loops number.
14852 unsigned NestedLoopCount =
14853 checkOpenMPLoop(DKind: OMPD_distribute, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
14854 OrderedLoopCountExpr: nullptr /*ordered not a clause on distribute*/, AStmt,
14855 SemaRef, DSA&: *DSAStack, VarsWithImplicitDSA, Built&: B);
14856 if (NestedLoopCount == 0)
14857 return StmtError();
14858
14859 assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) &&
14860 "omp for loop exprs were not built");
14861
14862 SemaRef.setFunctionHasBranchProtectedScope();
14863 auto *DistributeDirective = OMPDistributeDirective::Create(
14864 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
14865 return DistributeDirective;
14866}
14867
14868StmtResult SemaOpenMP::ActOnOpenMPDistributeParallelForDirective(
14869 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14870 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14871 if (!AStmt)
14872 return StmtError();
14873
14874 CapturedStmt *CS =
14875 setBranchProtectedScope(SemaRef, DKind: OMPD_distribute_parallel_for, AStmt);
14876
14877 OMPLoopBasedDirective::HelperExprs B;
14878 // In presence of clause 'collapse' with number of loops, it will
14879 // define the nested loops number.
14880 unsigned NestedLoopCount = checkOpenMPLoop(
14881 DKind: OMPD_distribute_parallel_for, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
14882 OrderedLoopCountExpr: nullptr /*ordered not a clause on distribute*/, AStmt: CS, SemaRef, DSA&: *DSAStack,
14883 VarsWithImplicitDSA, Built&: B);
14884 if (NestedLoopCount == 0)
14885 return StmtError();
14886
14887 assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) &&
14888 "omp for loop exprs were not built");
14889
14890 return OMPDistributeParallelForDirective::Create(
14891 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B,
14892 DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
14893}
14894
14895StmtResult SemaOpenMP::ActOnOpenMPDistributeParallelForSimdDirective(
14896 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14897 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14898 if (!AStmt)
14899 return StmtError();
14900
14901 CapturedStmt *CS = setBranchProtectedScope(
14902 SemaRef, DKind: OMPD_distribute_parallel_for_simd, AStmt);
14903
14904 OMPLoopBasedDirective::HelperExprs B;
14905 // In presence of clause 'collapse' with number of loops, it will
14906 // define the nested loops number.
14907 unsigned NestedLoopCount = checkOpenMPLoop(
14908 DKind: OMPD_distribute_parallel_for_simd, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
14909 OrderedLoopCountExpr: nullptr /*ordered not a clause on distribute*/, AStmt: CS, SemaRef, DSA&: *DSAStack,
14910 VarsWithImplicitDSA, Built&: B);
14911 if (NestedLoopCount == 0)
14912 return StmtError();
14913
14914 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
14915 return StmtError();
14916
14917 if (checkSimdlenSafelenSpecified(S&: SemaRef, Clauses))
14918 return StmtError();
14919
14920 return OMPDistributeParallelForSimdDirective::Create(
14921 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
14922}
14923
14924StmtResult SemaOpenMP::ActOnOpenMPDistributeSimdDirective(
14925 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14926 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14927 if (!AStmt)
14928 return StmtError();
14929
14930 CapturedStmt *CS =
14931 setBranchProtectedScope(SemaRef, DKind: OMPD_distribute_simd, AStmt);
14932
14933 OMPLoopBasedDirective::HelperExprs B;
14934 // In presence of clause 'collapse' with number of loops, it will
14935 // define the nested loops number.
14936 unsigned NestedLoopCount =
14937 checkOpenMPLoop(DKind: OMPD_distribute_simd, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
14938 OrderedLoopCountExpr: nullptr /*ordered not a clause on distribute*/, AStmt: CS,
14939 SemaRef, DSA&: *DSAStack, VarsWithImplicitDSA, Built&: B);
14940 if (NestedLoopCount == 0)
14941 return StmtError();
14942
14943 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
14944 return StmtError();
14945
14946 if (checkSimdlenSafelenSpecified(S&: SemaRef, Clauses))
14947 return StmtError();
14948
14949 return OMPDistributeSimdDirective::Create(C: getASTContext(), StartLoc, EndLoc,
14950 CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
14951}
14952
14953StmtResult SemaOpenMP::ActOnOpenMPTargetParallelForSimdDirective(
14954 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14955 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14956 if (!AStmt)
14957 return StmtError();
14958
14959 if (validateMultidimClauses(SemaRef&: *this, Clauses))
14960 return StmtError();
14961
14962 if (checkClausesForDecompositionConflicts(
14963 SemaRef, DKind: OMPD_target_parallel_for_simd, Clauses))
14964 return StmtError();
14965
14966 if (checkOriginalVarMappedButOnlyBindingsUsed(SemaRef, Clauses, Body: AStmt))
14967 return StmtError();
14968
14969 CapturedStmt *CS =
14970 setBranchProtectedScope(SemaRef, DKind: OMPD_target_parallel_for_simd, AStmt);
14971
14972 OMPLoopBasedDirective::HelperExprs B;
14973 // In presence of clause 'collapse' or 'ordered' with number of loops, it will
14974 // define the nested loops number.
14975 unsigned NestedLoopCount = checkOpenMPLoop(
14976 DKind: OMPD_target_parallel_for_simd, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
14977 OrderedLoopCountExpr: getOrderedNumberExpr(Clauses), AStmt: CS, SemaRef, DSA&: *DSAStack,
14978 VarsWithImplicitDSA, Built&: B);
14979 if (NestedLoopCount == 0)
14980 return StmtError();
14981
14982 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
14983 return StmtError();
14984
14985 if (checkSimdlenSafelenSpecified(S&: SemaRef, Clauses))
14986 return StmtError();
14987
14988 return OMPTargetParallelForSimdDirective::Create(
14989 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
14990}
14991
14992StmtResult SemaOpenMP::ActOnOpenMPTargetSimdDirective(
14993 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
14994 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
14995 if (!AStmt)
14996 return StmtError();
14997
14998 if (validateMultidimClauses(SemaRef&: *this, Clauses))
14999 return StmtError();
15000
15001 if (checkClausesForDecompositionConflicts(SemaRef, DKind: OMPD_target_simd, Clauses))
15002 return StmtError();
15003
15004 if (checkOriginalVarMappedButOnlyBindingsUsed(SemaRef, Clauses, Body: AStmt))
15005 return StmtError();
15006
15007 CapturedStmt *CS = setBranchProtectedScope(SemaRef, DKind: OMPD_target_simd, AStmt);
15008
15009 OMPLoopBasedDirective::HelperExprs B;
15010 // In presence of clause 'collapse' with number of loops, it will define the
15011 // nested loops number.
15012 unsigned NestedLoopCount =
15013 checkOpenMPLoop(DKind: OMPD_target_simd, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
15014 OrderedLoopCountExpr: getOrderedNumberExpr(Clauses), AStmt: CS, SemaRef, DSA&: *DSAStack,
15015 VarsWithImplicitDSA, Built&: B);
15016 if (NestedLoopCount == 0)
15017 return StmtError();
15018
15019 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
15020 return StmtError();
15021
15022 if (checkSimdlenSafelenSpecified(S&: SemaRef, Clauses))
15023 return StmtError();
15024
15025 return OMPTargetSimdDirective::Create(C: getASTContext(), StartLoc, EndLoc,
15026 CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
15027}
15028
15029StmtResult SemaOpenMP::ActOnOpenMPTeamsDistributeDirective(
15030 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
15031 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
15032 if (!AStmt)
15033 return StmtError();
15034
15035 if (validateMultidimClauses(SemaRef&: *this, Clauses))
15036 return StmtError();
15037
15038 if (checkClausesForDecompositionConflicts(SemaRef, DKind: OMPD_teams_distribute,
15039 Clauses))
15040 return StmtError();
15041
15042 CapturedStmt *CS =
15043 setBranchProtectedScope(SemaRef, DKind: OMPD_teams_distribute, AStmt);
15044
15045 OMPLoopBasedDirective::HelperExprs B;
15046 // In presence of clause 'collapse' with number of loops, it will
15047 // define the nested loops number.
15048 unsigned NestedLoopCount =
15049 checkOpenMPLoop(DKind: OMPD_teams_distribute, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
15050 OrderedLoopCountExpr: nullptr /*ordered not a clause on distribute*/, AStmt: CS,
15051 SemaRef, DSA&: *DSAStack, VarsWithImplicitDSA, Built&: B);
15052 if (NestedLoopCount == 0)
15053 return StmtError();
15054
15055 assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) &&
15056 "omp teams distribute loop exprs were not built");
15057
15058 DSAStack->setParentTeamsRegionLoc(StartLoc);
15059
15060 return OMPTeamsDistributeDirective::Create(
15061 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
15062}
15063
15064StmtResult SemaOpenMP::ActOnOpenMPTeamsDistributeSimdDirective(
15065 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
15066 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
15067 if (!AStmt)
15068 return StmtError();
15069
15070 if (validateMultidimClauses(SemaRef&: *this, Clauses))
15071 return StmtError();
15072 if (checkClausesForDecompositionConflicts(SemaRef, DKind: OMPD_teams_distribute_simd,
15073 Clauses))
15074 return StmtError();
15075
15076 CapturedStmt *CS =
15077 setBranchProtectedScope(SemaRef, DKind: OMPD_teams_distribute_simd, AStmt);
15078
15079 OMPLoopBasedDirective::HelperExprs B;
15080 // In presence of clause 'collapse' with number of loops, it will
15081 // define the nested loops number.
15082 unsigned NestedLoopCount = checkOpenMPLoop(
15083 DKind: OMPD_teams_distribute_simd, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
15084 OrderedLoopCountExpr: nullptr /*ordered not a clause on distribute*/, AStmt: CS, SemaRef, DSA&: *DSAStack,
15085 VarsWithImplicitDSA, Built&: B);
15086 if (NestedLoopCount == 0)
15087 return StmtError();
15088
15089 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
15090 return StmtError();
15091
15092 if (checkSimdlenSafelenSpecified(S&: SemaRef, Clauses))
15093 return StmtError();
15094
15095 DSAStack->setParentTeamsRegionLoc(StartLoc);
15096
15097 return OMPTeamsDistributeSimdDirective::Create(
15098 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
15099}
15100
15101StmtResult SemaOpenMP::ActOnOpenMPTeamsDistributeParallelForSimdDirective(
15102 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
15103 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
15104 if (!AStmt)
15105 return StmtError();
15106
15107 if (validateMultidimClauses(SemaRef&: *this, Clauses))
15108 return StmtError();
15109
15110 if (checkClausesForDecompositionConflicts(
15111 SemaRef, DKind: OMPD_teams_distribute_parallel_for_simd, Clauses))
15112 return StmtError();
15113
15114 CapturedStmt *CS = setBranchProtectedScope(
15115 SemaRef, DKind: OMPD_teams_distribute_parallel_for_simd, AStmt);
15116
15117 OMPLoopBasedDirective::HelperExprs B;
15118 // In presence of clause 'collapse' with number of loops, it will
15119 // define the nested loops number.
15120 unsigned NestedLoopCount = checkOpenMPLoop(
15121 DKind: OMPD_teams_distribute_parallel_for_simd, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
15122 OrderedLoopCountExpr: nullptr /*ordered not a clause on distribute*/, AStmt: CS, SemaRef, DSA&: *DSAStack,
15123 VarsWithImplicitDSA, Built&: B);
15124 if (NestedLoopCount == 0)
15125 return StmtError();
15126
15127 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
15128 return StmtError();
15129
15130 if (checkSimdlenSafelenSpecified(S&: SemaRef, Clauses))
15131 return StmtError();
15132
15133 DSAStack->setParentTeamsRegionLoc(StartLoc);
15134
15135 return OMPTeamsDistributeParallelForSimdDirective::Create(
15136 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
15137}
15138
15139StmtResult SemaOpenMP::ActOnOpenMPTeamsDistributeParallelForDirective(
15140 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
15141 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
15142 if (!AStmt)
15143 return StmtError();
15144
15145 if (validateMultidimClauses(SemaRef&: *this, Clauses))
15146 return StmtError();
15147
15148 if (checkClausesForDecompositionConflicts(
15149 SemaRef, DKind: OMPD_teams_distribute_parallel_for, Clauses))
15150 return StmtError();
15151
15152 CapturedStmt *CS = setBranchProtectedScope(
15153 SemaRef, DKind: OMPD_teams_distribute_parallel_for, AStmt);
15154
15155 OMPLoopBasedDirective::HelperExprs B;
15156 // In presence of clause 'collapse' with number of loops, it will
15157 // define the nested loops number.
15158 unsigned NestedLoopCount = checkOpenMPLoop(
15159 DKind: OMPD_teams_distribute_parallel_for, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
15160 OrderedLoopCountExpr: nullptr /*ordered not a clause on distribute*/, AStmt: CS, SemaRef, DSA&: *DSAStack,
15161 VarsWithImplicitDSA, Built&: B);
15162
15163 if (NestedLoopCount == 0)
15164 return StmtError();
15165
15166 assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) &&
15167 "omp for loop exprs were not built");
15168
15169 DSAStack->setParentTeamsRegionLoc(StartLoc);
15170
15171 return OMPTeamsDistributeParallelForDirective::Create(
15172 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B,
15173 DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
15174}
15175
15176StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDirective(
15177 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
15178 SourceLocation EndLoc) {
15179 if (!AStmt)
15180 return StmtError();
15181
15182 if (checkClausesForDecompositionConflicts(SemaRef, DKind: OMPD_target_teams,
15183 Clauses))
15184 return StmtError();
15185
15186 if (checkOriginalVarMappedButOnlyBindingsUsed(SemaRef, Clauses, Body: AStmt))
15187 return StmtError();
15188
15189 setBranchProtectedScope(SemaRef, DKind: OMPD_target_teams, AStmt);
15190
15191 if (validateMultidimClauses(SemaRef&: *this, Clauses, /*MayHaveBareClause=*/true))
15192 return StmtError();
15193
15194 return OMPTargetTeamsDirective::Create(C: getASTContext(), StartLoc, EndLoc,
15195 Clauses, AssociatedStmt: AStmt);
15196}
15197
15198StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeDirective(
15199 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
15200 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
15201 if (!AStmt)
15202 return StmtError();
15203
15204 if (validateMultidimClauses(SemaRef&: *this, Clauses))
15205 return StmtError();
15206
15207 if (checkClausesForDecompositionConflicts(
15208 SemaRef, DKind: OMPD_target_teams_distribute, Clauses))
15209 return StmtError();
15210
15211 if (checkOriginalVarMappedButOnlyBindingsUsed(SemaRef, Clauses, Body: AStmt))
15212 return StmtError();
15213
15214 CapturedStmt *CS =
15215 setBranchProtectedScope(SemaRef, DKind: OMPD_target_teams_distribute, AStmt);
15216
15217 OMPLoopBasedDirective::HelperExprs B;
15218 // In presence of clause 'collapse' with number of loops, it will
15219 // define the nested loops number.
15220 unsigned NestedLoopCount = checkOpenMPLoop(
15221 DKind: OMPD_target_teams_distribute, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
15222 OrderedLoopCountExpr: nullptr /*ordered not a clause on distribute*/, AStmt: CS, SemaRef, DSA&: *DSAStack,
15223 VarsWithImplicitDSA, Built&: B);
15224 if (NestedLoopCount == 0)
15225 return StmtError();
15226
15227 assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) &&
15228 "omp target teams distribute loop exprs were not built");
15229
15230 return OMPTargetTeamsDistributeDirective::Create(
15231 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
15232}
15233
15234StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeParallelForDirective(
15235 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
15236 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
15237 if (!AStmt)
15238 return StmtError();
15239
15240 if (validateMultidimClauses(SemaRef&: *this, Clauses))
15241 return StmtError();
15242
15243 if (checkClausesForDecompositionConflicts(
15244 SemaRef, DKind: OMPD_target_teams_distribute_parallel_for, Clauses))
15245 return StmtError();
15246
15247 if (checkOriginalVarMappedButOnlyBindingsUsed(SemaRef, Clauses, Body: AStmt))
15248 return StmtError();
15249
15250 CapturedStmt *CS = setBranchProtectedScope(
15251 SemaRef, DKind: OMPD_target_teams_distribute_parallel_for, AStmt);
15252
15253 OMPLoopBasedDirective::HelperExprs B;
15254 // In presence of clause 'collapse' with number of loops, it will
15255 // define the nested loops number.
15256 unsigned NestedLoopCount = checkOpenMPLoop(
15257 DKind: OMPD_target_teams_distribute_parallel_for, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
15258 OrderedLoopCountExpr: nullptr /*ordered not a clause on distribute*/, AStmt: CS, SemaRef, DSA&: *DSAStack,
15259 VarsWithImplicitDSA, Built&: B);
15260 if (NestedLoopCount == 0)
15261 return StmtError();
15262
15263 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
15264 return StmtError();
15265
15266 return OMPTargetTeamsDistributeParallelForDirective::Create(
15267 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B,
15268 DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
15269}
15270
15271StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective(
15272 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
15273 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
15274 if (!AStmt)
15275 return StmtError();
15276
15277 if (validateMultidimClauses(SemaRef&: *this, Clauses))
15278 return StmtError();
15279
15280 if (checkClausesForDecompositionConflicts(
15281 SemaRef, DKind: OMPD_target_teams_distribute_parallel_for_simd, Clauses))
15282 return StmtError();
15283
15284 if (checkOriginalVarMappedButOnlyBindingsUsed(SemaRef, Clauses, Body: AStmt))
15285 return StmtError();
15286
15287 CapturedStmt *CS = setBranchProtectedScope(
15288 SemaRef, DKind: OMPD_target_teams_distribute_parallel_for_simd, AStmt);
15289
15290 OMPLoopBasedDirective::HelperExprs B;
15291 // In presence of clause 'collapse' with number of loops, it will
15292 // define the nested loops number.
15293 unsigned NestedLoopCount =
15294 checkOpenMPLoop(DKind: OMPD_target_teams_distribute_parallel_for_simd,
15295 CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
15296 OrderedLoopCountExpr: nullptr /*ordered not a clause on distribute*/, AStmt: CS,
15297 SemaRef, DSA&: *DSAStack, VarsWithImplicitDSA, Built&: B);
15298 if (NestedLoopCount == 0)
15299 return StmtError();
15300
15301 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
15302 return StmtError();
15303
15304 if (checkSimdlenSafelenSpecified(S&: SemaRef, Clauses))
15305 return StmtError();
15306
15307 return OMPTargetTeamsDistributeParallelForSimdDirective::Create(
15308 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
15309}
15310
15311StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeSimdDirective(
15312 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
15313 SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
15314 if (!AStmt)
15315 return StmtError();
15316
15317 if (validateMultidimClauses(SemaRef&: *this, Clauses))
15318 return StmtError();
15319
15320 if (checkClausesForDecompositionConflicts(
15321 SemaRef, DKind: OMPD_target_teams_distribute_simd, Clauses))
15322 return StmtError();
15323
15324 if (checkOriginalVarMappedButOnlyBindingsUsed(SemaRef, Clauses, Body: AStmt))
15325 return StmtError();
15326
15327 CapturedStmt *CS = setBranchProtectedScope(
15328 SemaRef, DKind: OMPD_target_teams_distribute_simd, AStmt);
15329
15330 OMPLoopBasedDirective::HelperExprs B;
15331 // In presence of clause 'collapse' with number of loops, it will
15332 // define the nested loops number.
15333 unsigned NestedLoopCount = checkOpenMPLoop(
15334 DKind: OMPD_target_teams_distribute_simd, CollapseLoopCountExpr: getCollapseNumberExpr(Clauses),
15335 OrderedLoopCountExpr: nullptr /*ordered not a clause on distribute*/, AStmt: CS, SemaRef, DSA&: *DSAStack,
15336 VarsWithImplicitDSA, Built&: B);
15337 if (NestedLoopCount == 0)
15338 return StmtError();
15339
15340 if (finishLinearClauses(SemaRef, Clauses, B, DSAStack))
15341 return StmtError();
15342
15343 if (checkSimdlenSafelenSpecified(S&: SemaRef, Clauses))
15344 return StmtError();
15345
15346 return OMPTargetTeamsDistributeSimdDirective::Create(
15347 C: getASTContext(), StartLoc, EndLoc, CollapsedNum: NestedLoopCount, Clauses, AssociatedStmt: AStmt, Exprs: B);
15348}
15349
15350/// Updates OriginalInits by checking Transform against loop transformation
15351/// directives and appending their pre-inits if a match is found.
15352static void updatePreInits(OMPLoopTransformationDirective *Transform,
15353 SmallVectorImpl<Stmt *> &PreInits) {
15354 Stmt *Dir = Transform->getDirective();
15355 switch (Dir->getStmtClass()) {
15356#define STMT(CLASS, PARENT)
15357#define ABSTRACT_STMT(CLASS)
15358#define COMMON_OMP_LOOP_TRANSFORMATION(CLASS, PARENT) \
15359 case Stmt::CLASS##Class: \
15360 appendFlattenedStmtList(PreInits, \
15361 static_cast<const CLASS *>(Dir)->getPreInits()); \
15362 break;
15363#define OMPCANONICALLOOPNESTTRANSFORMATIONDIRECTIVE(CLASS, PARENT) \
15364 COMMON_OMP_LOOP_TRANSFORMATION(CLASS, PARENT)
15365#define OMPCANONICALLOOPSEQUENCETRANSFORMATIONDIRECTIVE(CLASS, PARENT) \
15366 COMMON_OMP_LOOP_TRANSFORMATION(CLASS, PARENT)
15367#include "clang/AST/StmtNodes.inc"
15368#undef COMMON_OMP_LOOP_TRANSFORMATION
15369 default:
15370 llvm_unreachable("Not a loop transformation");
15371 }
15372}
15373
15374bool SemaOpenMP::checkTransformableLoopNest(
15375 OpenMPDirectiveKind Kind, Stmt *AStmt, int NumLoops,
15376 SmallVectorImpl<OMPLoopBasedDirective::HelperExprs> &LoopHelpers,
15377 Stmt *&Body, SmallVectorImpl<SmallVector<Stmt *>> &OriginalInits) {
15378 OriginalInits.emplace_back();
15379 // Only tile and stripe re-emit the statements before the nested loop in a
15380 // nested transformation's generated loop (see appendStmtsBeforeNestedLoop);
15381 // other constructs would silently drop them.
15382 bool RelaxNestForPeeledTransformation =
15383 Kind == OMPD_tile || Kind == OMPD_stripe;
15384 bool Result = OMPLoopBasedDirective::doForAllLoops(
15385 CurStmt: AStmt->IgnoreContainers(), /*TryImperfectlyNestedLoops=*/false, NumLoops,
15386 Callback: [this, &LoopHelpers, &Body, &OriginalInits,
15387 Kind](unsigned Cnt, Stmt *CurStmt, Stmt *HintWrapper) {
15388 // The start of this loop is a floor set in the enclosing tile's body.
15389 // Loop analysis reads a start only once, so the nest would repeat the
15390 // first tile. Reject instead of emitting wrong loops.
15391 if (HintWrapper) {
15392 SemaRef.Diag(Loc: CurStmt->getBeginLoc(),
15393 DiagID: diag::err_omp_collapse_stacked_tile)
15394 << /*LoopTransform=*/1;
15395 return true;
15396 }
15397 VarsWithInheritedDSAType TmpDSA;
15398 unsigned SingleNumLoops =
15399 checkOpenMPLoop(DKind: Kind, CollapseLoopCountExpr: nullptr, OrderedLoopCountExpr: nullptr, AStmt: CurStmt, SemaRef, DSA&: *DSAStack,
15400 VarsWithImplicitDSA&: TmpDSA, Built&: LoopHelpers[Cnt]);
15401 if (SingleNumLoops == 0)
15402 return true;
15403 assert(SingleNumLoops == 1 && "Expect single loop iteration space");
15404 if (auto *For = dyn_cast<ForStmt>(Val: CurStmt)) {
15405 OriginalInits.back().push_back(Elt: For->getInit());
15406 Body = For->getBody();
15407 } else {
15408 assert(isa<CXXForRangeStmt>(CurStmt) &&
15409 "Expected canonical for or range-based for loops.");
15410 auto *CXXFor = cast<CXXForRangeStmt>(Val: CurStmt);
15411 OriginalInits.back().push_back(Elt: CXXFor->getBeginStmt());
15412 Body = CXXFor->getBody();
15413 }
15414 OriginalInits.emplace_back();
15415 return false;
15416 },
15417 OnTransformationCallback: [&OriginalInits](OMPLoopTransformationDirective *Transform) {
15418 updatePreInits(Transform, PreInits&: OriginalInits.back());
15419 },
15420 RelaxNestForPeeledTransformation);
15421 assert(OriginalInits.back().empty() && "No preinit after innermost loop");
15422 OriginalInits.pop_back();
15423 return Result;
15424}
15425
15426/// Counts the total number of OpenMP canonical nested loops, including the
15427/// outermost loop (the original loop). PRECONDITION of this visitor is that it
15428/// must be invoked from the original loop to be analyzed. The traversal stops
15429/// for Decl's and Expr's given that they may contain inner loops that must not
15430/// be counted.
15431///
15432/// Example AST structure for the code:
15433///
15434/// int main() {
15435/// #pragma omp fuse
15436/// {
15437/// for (int i = 0; i < 100; i++) { <-- Outer loop
15438/// []() {
15439/// for(int j = 0; j < 100; j++) {} <-- NOT A LOOP (1)
15440/// };
15441/// for(int j = 0; j < 5; ++j) {} <-- Inner loop
15442/// }
15443/// for (int r = 0; i < 100; i++) { <-- Outer loop
15444/// struct LocalClass {
15445/// void bar() {
15446/// for(int j = 0; j < 100; j++) {} <-- NOT A LOOP (2)
15447/// }
15448/// };
15449/// for(int k = 0; k < 10; ++k) {} <-- Inner loop
15450/// {x = 5; for(k = 0; k < 10; ++k) x += k; x}; <-- NOT A LOOP (3)
15451/// }
15452/// }
15453/// }
15454/// (1) because in a different function (here: a lambda)
15455/// (2) because in a different function (here: class method)
15456/// (3) because considered to be intervening-code of non-perfectly nested loop
15457/// Result: Loop 'i' contains 2 loops, Loop 'r' also contains 2 loops.
15458class NestedLoopCounterVisitor final : public DynamicRecursiveASTVisitor {
15459private:
15460 unsigned NestedLoopCount = 0;
15461
15462public:
15463 explicit NestedLoopCounterVisitor() = default;
15464
15465 unsigned getNestedLoopCount() const { return NestedLoopCount; }
15466
15467 bool VisitForStmt(ForStmt *FS) override {
15468 ++NestedLoopCount;
15469 return true;
15470 }
15471
15472 bool VisitCXXForRangeStmt(CXXForRangeStmt *FRS) override {
15473 ++NestedLoopCount;
15474 return true;
15475 }
15476
15477 bool TraverseStmt(Stmt *S) override {
15478 if (!S)
15479 return true;
15480
15481 // Skip traversal of all expressions, including special cases like
15482 // LambdaExpr, StmtExpr, BlockExpr, and RequiresExpr. These expressions
15483 // may contain inner statements (and even loops), but they are not part
15484 // of the syntactic body of the surrounding loop structure.
15485 // Therefore must not be counted.
15486 if (isa<Expr>(Val: S))
15487 return true;
15488
15489 // Only recurse into CompoundStmt (block {}) and loop bodies.
15490 if (isa<CompoundStmt, ForStmt, CXXForRangeStmt>(Val: S)) {
15491 return DynamicRecursiveASTVisitor::TraverseStmt(S);
15492 }
15493
15494 // Stop traversal of the rest of statements, that break perfect
15495 // loop nesting, such as control flow (IfStmt, SwitchStmt...).
15496 return true;
15497 }
15498
15499 bool TraverseDecl(Decl *D) override {
15500 // Stop in the case of finding a declaration, it is not important
15501 // in order to find nested loops (Possible CXXRecordDecl, RecordDecl,
15502 // FunctionDecl...).
15503 return true;
15504 }
15505};
15506
15507bool SemaOpenMP::analyzeLoopSequence(Stmt *LoopSeqStmt,
15508 LoopSequenceAnalysis &SeqAnalysis,
15509 ASTContext &Context,
15510 OpenMPDirectiveKind Kind) {
15511 VarsWithInheritedDSAType TmpDSA;
15512 // Helper Lambda to handle storing initialization and body statements for
15513 // both ForStmt and CXXForRangeStmt.
15514 auto StoreLoopStatements = [](LoopAnalysis &Analysis, Stmt *LoopStmt) {
15515 if (auto *For = dyn_cast<ForStmt>(Val: LoopStmt)) {
15516 Analysis.OriginalInits.push_back(Elt: For->getInit());
15517 Analysis.TheForStmt = For;
15518 } else {
15519 auto *CXXFor = cast<CXXForRangeStmt>(Val: LoopStmt);
15520 Analysis.OriginalInits.push_back(Elt: CXXFor->getBeginStmt());
15521 Analysis.TheForStmt = CXXFor;
15522 }
15523 };
15524
15525 // Helper lambda functions to encapsulate the processing of different
15526 // derivations of the canonical loop sequence grammar
15527 // Modularized code for handling loop generation and transformations.
15528 auto AnalyzeLoopGeneration = [&](Stmt *Child) {
15529 auto *LoopTransform = cast<OMPLoopTransformationDirective>(Val: Child);
15530 Stmt *TransformedStmt = LoopTransform->getTransformedStmt();
15531 unsigned NumGeneratedTopLevelLoops =
15532 LoopTransform->getNumGeneratedTopLevelLoops();
15533 // Handle the case where transformed statement is not available due to
15534 // dependent contexts
15535 if (!TransformedStmt) {
15536 if (NumGeneratedTopLevelLoops > 0) {
15537 SeqAnalysis.LoopSeqSize += NumGeneratedTopLevelLoops;
15538 return true;
15539 }
15540 // Unroll full (0 loops produced)
15541 Diag(Loc: Child->getBeginLoc(), DiagID: diag::err_omp_not_for)
15542 << 0 << getOpenMPDirectiveName(D: Kind);
15543 return false;
15544 }
15545 // Handle loop transformations with multiple loop nests
15546 // Unroll full
15547 if (!NumGeneratedTopLevelLoops) {
15548 Diag(Loc: Child->getBeginLoc(), DiagID: diag::err_omp_not_for)
15549 << 0 << getOpenMPDirectiveName(D: Kind);
15550 return false;
15551 }
15552 // Loop transformatons such as split or loopranged fuse
15553 if (NumGeneratedTopLevelLoops > 1) {
15554 // Get the preinits related to this loop sequence generating
15555 // loop transformation (i.e loopranged fuse, split...)
15556 // These preinits differ slightly from regular inits/pre-inits related
15557 // to single loop generating loop transformations (interchange, unroll)
15558 // given that they are not bounded to a particular loop nest
15559 // so they need to be treated independently
15560 updatePreInits(Transform: LoopTransform, PreInits&: SeqAnalysis.LoopSequencePreInits);
15561 return analyzeLoopSequence(LoopSeqStmt: TransformedStmt, SeqAnalysis, Context, Kind);
15562 }
15563 // Vast majority: (Tile, Unroll, Stripe, Reverse, Interchange, Fuse all)
15564 // Process the transformed loop statement
15565 LoopAnalysis &NewTransformedSingleLoop =
15566 SeqAnalysis.Loops.emplace_back(Args&: Child);
15567 unsigned IsCanonical = checkOpenMPLoop(
15568 DKind: Kind, CollapseLoopCountExpr: nullptr, OrderedLoopCountExpr: nullptr, AStmt: TransformedStmt, SemaRef, DSA&: *DSAStack, VarsWithImplicitDSA&: TmpDSA,
15569 Built&: NewTransformedSingleLoop.HelperExprs);
15570
15571 if (!IsCanonical)
15572 return false;
15573
15574 StoreLoopStatements(NewTransformedSingleLoop, TransformedStmt);
15575 updatePreInits(Transform: LoopTransform, PreInits&: NewTransformedSingleLoop.TransformsPreInits);
15576
15577 SeqAnalysis.LoopSeqSize++;
15578 return true;
15579 };
15580
15581 // Modularized code for handling regular canonical loops.
15582 auto AnalyzeRegularLoop = [&](Stmt *Child) {
15583 LoopAnalysis &NewRegularLoop = SeqAnalysis.Loops.emplace_back(Args&: Child);
15584 unsigned IsCanonical =
15585 checkOpenMPLoop(DKind: Kind, CollapseLoopCountExpr: nullptr, OrderedLoopCountExpr: nullptr, AStmt: Child, SemaRef, DSA&: *DSAStack,
15586 VarsWithImplicitDSA&: TmpDSA, Built&: NewRegularLoop.HelperExprs);
15587
15588 if (!IsCanonical)
15589 return false;
15590
15591 StoreLoopStatements(NewRegularLoop, Child);
15592 NestedLoopCounterVisitor NLCV;
15593 NLCV.TraverseStmt(S: Child);
15594 return true;
15595 };
15596
15597 // High level grammar validation.
15598 for (Stmt *Child : LoopSeqStmt->children()) {
15599 if (!Child)
15600 continue;
15601 // Skip over non-loop-sequence statements.
15602 if (!LoopSequenceAnalysis::isLoopSequenceDerivation(S: Child)) {
15603 Child = Child->IgnoreContainers();
15604 // Ignore empty compound statement.
15605 if (!Child)
15606 continue;
15607 // In the case of a nested loop sequence ignoring containers would not
15608 // be enough, a recurisve transversal of the loop sequence is required.
15609 if (isa<CompoundStmt>(Val: Child)) {
15610 if (!analyzeLoopSequence(LoopSeqStmt: Child, SeqAnalysis, Context, Kind))
15611 return false;
15612 // Already been treated, skip this children
15613 continue;
15614 }
15615 }
15616 // Regular loop sequence handling.
15617 if (LoopSequenceAnalysis::isLoopSequenceDerivation(S: Child)) {
15618 if (LoopAnalysis::isLoopTransformation(S: Child)) {
15619 if (!AnalyzeLoopGeneration(Child))
15620 return false;
15621 // AnalyzeLoopGeneration updates SeqAnalysis.LoopSeqSize accordingly.
15622 } else {
15623 if (!AnalyzeRegularLoop(Child))
15624 return false;
15625 SeqAnalysis.LoopSeqSize++;
15626 }
15627 } else {
15628 // Report error for invalid statement inside canonical loop sequence.
15629 Diag(Loc: Child->getBeginLoc(), DiagID: diag::err_omp_not_for)
15630 << 0 << getOpenMPDirectiveName(D: Kind);
15631 return false;
15632 }
15633 }
15634 return true;
15635}
15636
15637bool SemaOpenMP::checkTransformableLoopSequence(
15638 OpenMPDirectiveKind Kind, Stmt *AStmt, LoopSequenceAnalysis &SeqAnalysis,
15639 ASTContext &Context) {
15640 // Following OpenMP 6.0 API Specification, a Canonical Loop Sequence follows
15641 // the grammar:
15642 //
15643 // canonical-loop-sequence:
15644 // {
15645 // loop-sequence+
15646 // }
15647 // where loop-sequence can be any of the following:
15648 // 1. canonical-loop-sequence
15649 // 2. loop-nest
15650 // 3. loop-sequence-generating-construct (i.e OMPLoopTransformationDirective)
15651 //
15652 // To recognise and traverse this structure the helper function
15653 // analyzeLoopSequence serves as the recurisve entry point
15654 // and tries to match the input AST to the canonical loop sequence grammar
15655 // structure. This function will perform both a semantic and syntactical
15656 // analysis of the given statement according to OpenMP 6.0 definition of
15657 // the aforementioned canonical loop sequence.
15658
15659 // We expect an outer compound statement.
15660 if (!isa<CompoundStmt>(Val: AStmt)) {
15661 Diag(Loc: AStmt->getBeginLoc(), DiagID: diag::err_omp_not_a_loop_sequence)
15662 << getOpenMPDirectiveName(D: Kind);
15663 return false;
15664 }
15665
15666 // Recursive entry point to process the main loop sequence
15667 if (!analyzeLoopSequence(LoopSeqStmt: AStmt, SeqAnalysis, Context, Kind))
15668 return false;
15669
15670 // Diagnose an empty loop sequence.
15671 if (!SeqAnalysis.LoopSeqSize) {
15672 Diag(Loc: AStmt->getBeginLoc(), DiagID: diag::err_omp_empty_loop_sequence)
15673 << getOpenMPDirectiveName(D: Kind);
15674 return false;
15675 }
15676 return true;
15677}
15678
15679/// Add preinit statements that need to be propagated from the selected loop.
15680static void addLoopPreInits(ASTContext &Context,
15681 OMPLoopBasedDirective::HelperExprs &LoopHelper,
15682 Stmt *LoopStmt, ArrayRef<Stmt *> OriginalInit,
15683 SmallVectorImpl<Stmt *> &PreInits) {
15684
15685 // For range-based for-statements, ensure that their syntactic sugar is
15686 // executed by adding them as pre-init statements.
15687 if (auto *CXXRangeFor = dyn_cast<CXXForRangeStmt>(Val: LoopStmt)) {
15688 Stmt *RangeInit = CXXRangeFor->getInit();
15689 if (RangeInit)
15690 PreInits.push_back(Elt: RangeInit);
15691
15692 DeclStmt *RangeStmt = CXXRangeFor->getRangeStmt();
15693 PreInits.push_back(Elt: new (Context) DeclStmt(RangeStmt->getDeclGroup(),
15694 RangeStmt->getBeginLoc(),
15695 RangeStmt->getEndLoc()));
15696
15697 DeclStmt *RangeEnd = CXXRangeFor->getEndStmt();
15698 PreInits.push_back(Elt: new (Context) DeclStmt(RangeEnd->getDeclGroup(),
15699 RangeEnd->getBeginLoc(),
15700 RangeEnd->getEndLoc()));
15701 }
15702
15703 llvm::append_range(C&: PreInits, R&: OriginalInit);
15704
15705 // List of OMPCapturedExprDecl, for __begin, __end, and NumIterations
15706 if (auto *PI = cast_or_null<DeclStmt>(Val: LoopHelper.PreInits)) {
15707 PreInits.push_back(Elt: new (Context) DeclStmt(
15708 PI->getDeclGroup(), PI->getBeginLoc(), PI->getEndLoc()));
15709 }
15710
15711 // Gather declarations for the data members used as counters.
15712 for (Expr *CounterRef : LoopHelper.Counters) {
15713 auto *CounterDecl = cast<DeclRefExpr>(Val: CounterRef)->getDecl();
15714 if (isa<OMPCapturedExprDecl>(Val: CounterDecl))
15715 PreInits.push_back(Elt: new (Context) DeclStmt(
15716 DeclGroupRef(CounterDecl), SourceLocation(), SourceLocation()));
15717 }
15718}
15719
15720/// Collect the loop statements (ForStmt or CXXRangeForStmt) of the affected
15721/// loop of a construct.
15722static void collectLoopStmts(Stmt *AStmt, MutableArrayRef<Stmt *> LoopStmts,
15723 bool RelaxNestForPeeledTransformation = false) {
15724 size_t NumLoops = LoopStmts.size();
15725 OMPLoopBasedDirective::doForAllLoops(
15726 CurStmt: AStmt, /*TryImperfectlyNestedLoops=*/false, NumLoops,
15727 Callback: [LoopStmts](unsigned Cnt, Stmt *CurStmt) {
15728 assert(!LoopStmts[Cnt] && "Loop statement must not yet be assigned");
15729 LoopStmts[Cnt] = CurStmt;
15730 return false;
15731 },
15732 RelaxNestForPeeledTransformation);
15733 assert(!is_contained(LoopStmts, nullptr) &&
15734 "Expecting a loop statement for each affected loop");
15735}
15736
15737/// A non-innermost affected loop generated by a nested loop transformation
15738/// (e.g. `omp reverse`) computes the user counter in statements ahead of the
15739/// next loop. A construct that rebuilds the nest only keeps the innermost
15740/// body, so it must re-emit these statements in the matching loop.
15741static void appendStmtsBeforeNestedLoop(Stmt *LoopStmt,
15742 SmallVectorImpl<Stmt *> &BodyParts) {
15743 Stmt *Body = isa<ForStmt>(Val: LoopStmt)
15744 ? cast<ForStmt>(Val: LoopStmt)->getBody()
15745 : cast<CXXForRangeStmt>(Val: LoopStmt)->getBody();
15746 llvm::append_range(C&: BodyParts,
15747 R: OMPLoopBasedDirective::getStmtsBeforeNestedLoop(Body));
15748}
15749
15750/// Build and return a DeclRefExpr for the floor induction variable using the
15751/// SemaRef and the provided parameters.
15752static Expr *makeFloorIVRef(Sema &SemaRef, ArrayRef<VarDecl *> FloorIndVars,
15753 int I, QualType IVTy, DeclRefExpr *OrigCntVar) {
15754 return buildDeclRefExpr(S&: SemaRef, D: FloorIndVars[I], Ty: IVTy,
15755 Loc: OrigCntVar->getExprLoc());
15756}
15757
15758StmtResult SemaOpenMP::ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses,
15759 Stmt *AStmt,
15760 SourceLocation StartLoc,
15761 SourceLocation EndLoc) {
15762 ASTContext &Context = getASTContext();
15763 Scope *CurScope = SemaRef.getCurScope();
15764
15765 const auto *SizesClause =
15766 OMPExecutableDirective::getSingleClause<OMPSizesClause>(Clauses);
15767 if (!SizesClause ||
15768 llvm::any_of(Range: SizesClause->getSizesRefs(), P: [](Expr *E) { return !E; }))
15769 return StmtError();
15770 unsigned NumLoops = SizesClause->getNumSizes();
15771
15772 // Empty statement should only be possible if there already was an error.
15773 if (!AStmt)
15774 return StmtError();
15775
15776 // Verify and diagnose loop nest.
15777 SmallVector<OMPLoopBasedDirective::HelperExprs, 4> LoopHelpers(NumLoops);
15778 Stmt *Body = nullptr;
15779 SmallVector<SmallVector<Stmt *>, 4> OriginalInits;
15780 if (!checkTransformableLoopNest(Kind: OMPD_tile, AStmt, NumLoops, LoopHelpers, Body,
15781 OriginalInits))
15782 return StmtError();
15783
15784 // Delay tiling to when template is completely instantiated.
15785 if (SemaRef.CurContext->isDependentContext())
15786 return OMPTileDirective::Create(C: Context, StartLoc, EndLoc, Clauses,
15787 NumLoops, AssociatedStmt: AStmt, TransformedStmt: nullptr, PreInits: nullptr);
15788
15789 assert(LoopHelpers.size() == NumLoops &&
15790 "Expecting loop iteration space dimensionality to match number of "
15791 "affected loops");
15792 assert(OriginalInits.size() == NumLoops &&
15793 "Expecting loop iteration space dimensionality to match number of "
15794 "affected loops");
15795
15796 // Collect all affected loop statements.
15797 SmallVector<Stmt *> LoopStmts(NumLoops, nullptr);
15798 collectLoopStmts(AStmt, LoopStmts, /*RelaxNestForPeeledTransformation=*/true);
15799
15800 SmallVector<Stmt *, 4> PreInits;
15801 CaptureVars CopyTransformer(SemaRef);
15802
15803 // Create iteration variables for the generated loops.
15804 SmallVector<VarDecl *, 4> FloorIndVars;
15805 SmallVector<VarDecl *, 4> TileIndVars;
15806 FloorIndVars.resize(N: NumLoops);
15807 TileIndVars.resize(N: NumLoops);
15808 for (unsigned I = 0; I < NumLoops; ++I) {
15809 OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I];
15810
15811 assert(LoopHelper.Counters.size() == 1 &&
15812 "Expect single-dimensional loop iteration space");
15813 auto *OrigCntVar = cast<DeclRefExpr>(Val: LoopHelper.Counters.front());
15814 std::string OrigVarName = OrigCntVar->getNameInfo().getAsString();
15815 DeclRefExpr *IterVarRef = cast<DeclRefExpr>(Val: LoopHelper.IterationVarRef);
15816 QualType CntTy = IterVarRef->getType();
15817
15818 // Iteration variable for the floor (i.e. outer) loop.
15819 {
15820 std::string FloorCntName =
15821 (Twine(".floor_") + llvm::utostr(X: I) + ".iv." + OrigVarName).str();
15822 VarDecl *FloorCntDecl =
15823 buildVarDecl(SemaRef, Loc: {}, Type: CntTy, Name: FloorCntName, Attrs: nullptr, OrigRef: OrigCntVar);
15824 FloorIndVars[I] = FloorCntDecl;
15825 }
15826
15827 // Iteration variable for the tile (i.e. inner) loop.
15828 {
15829 std::string TileCntName =
15830 (Twine(".tile_") + llvm::utostr(X: I) + ".iv." + OrigVarName).str();
15831
15832 // Reuse the iteration variable created by checkOpenMPLoop. It is also
15833 // used by the expressions to derive the original iteration variable's
15834 // value from the logical iteration number.
15835 auto *TileCntDecl = cast<VarDecl>(Val: IterVarRef->getDecl());
15836 TileCntDecl->setDeclName(
15837 &SemaRef.PP.getIdentifierTable().get(Name: TileCntName));
15838 TileIndVars[I] = TileCntDecl;
15839 }
15840
15841 addLoopPreInits(Context, LoopHelper, LoopStmt: LoopStmts[I], OriginalInit: OriginalInits[I],
15842 PreInits);
15843 }
15844
15845 // Once the original iteration values are set, append the innermost body.
15846 Stmt *Inner = Body;
15847
15848 auto MakeDimTileSize = [&SemaRef = this->SemaRef, &CopyTransformer, &Context,
15849 SizesClause, CurScope](int I) -> Expr * {
15850 Expr *DimTileSizeExpr = SizesClause->getSizesRefs()[I];
15851
15852 if (DimTileSizeExpr->containsErrors())
15853 return nullptr;
15854
15855 if (isa<ConstantExpr>(Val: DimTileSizeExpr))
15856 return AssertSuccess(R: CopyTransformer.TransformExpr(E: DimTileSizeExpr));
15857
15858 // When the tile size is not a constant but a variable, it is possible to
15859 // pass non-positive numbers. For instance:
15860 // \code{c}
15861 // int a = 0;
15862 // #pragma omp tile sizes(a)
15863 // for (int i = 0; i < 42; ++i)
15864 // body(i);
15865 // \endcode
15866 // Although there is no meaningful interpretation of the tile size, the body
15867 // should still be executed 42 times to avoid surprises. To preserve the
15868 // invariant that every loop iteration is executed exactly once and not
15869 // cause an infinite loop, apply a minimum tile size of one.
15870 // Build expr:
15871 // \code{c}
15872 // (TS <= 0) ? 1 : TS
15873 // \endcode
15874 QualType DimTy = DimTileSizeExpr->getType();
15875 uint64_t DimWidth = Context.getTypeSize(T: DimTy);
15876 IntegerLiteral *Zero = IntegerLiteral::Create(
15877 C: Context, V: llvm::APInt::getZero(numBits: DimWidth), type: DimTy, l: {});
15878 IntegerLiteral *One =
15879 IntegerLiteral::Create(C: Context, V: llvm::APInt(DimWidth, 1), type: DimTy, l: {});
15880 Expr *Cond = AssertSuccess(R: SemaRef.BuildBinOp(
15881 S: CurScope, OpLoc: {}, Opc: BO_LE,
15882 LHSExpr: AssertSuccess(R: CopyTransformer.TransformExpr(E: DimTileSizeExpr)), RHSExpr: Zero));
15883 Expr *MinOne = new (Context) ConditionalOperator(
15884 Cond, {}, One, {},
15885 AssertSuccess(R: CopyTransformer.TransformExpr(E: DimTileSizeExpr)), DimTy,
15886 VK_PRValue, OK_Ordinary);
15887 return MinOne;
15888 };
15889
15890 // Create tile loops from the inside to the outside.
15891 //
15892 // Each intra-tile loop is emitted in its natural min-bounded form, which has
15893 // no per-iteration body predicate and vectorizes well when run directly:
15894 // for (.tile.iv = .floor.iv; .tile.iv < min(.floor.iv + T, N); ++.tile.iv)
15895 //
15896 // A loop-associated directive that *consumes* this loop (e.g. `collapse`)
15897 // instead needs a constant, floor-independent trip count to linearize the
15898 // nest, which the min() bound cannot give it. Rather than change the
15899 // emitted loop, we attach a droppable OMPInvariantPredicateBoundAttr hint
15900 // below carrying an equivalent rectangular reinterpretation:
15901 // RectCond : .tile.iv < .floor.iv + T -- rectangular bound, analyzed by
15902 // checkOpenMPIterationSpace in place of the stored condition
15903 // TileSize : T -- constant per-tile trip count
15904 // Predicate : .tile.iv < N -- remainder-tile overshoot,
15905 // applied as a body guard instead of shortening the trip count;
15906 // omitted when N is known to be a multiple of T, as there is
15907 // then no partial tile to guard against
15908 // Because the reinterpreted lower bound is still `.floor.iv`,
15909 // checkOpenMPIterationSpace sets IsNonRectangularLB on the matching floor
15910 // counter, so a collapsed `.tile.iv` re-reads the floor's current value
15911 // instead of a stale preheader snapshot. Collapsing through stacked tiles
15912 // (tile-of-tile) is not supported: the inner floor is not itself a collapsed
15913 // counter.
15914 for (int I = NumLoops - 1; I >= 0; --I) {
15915 OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I];
15916 Expr *NumIterations = LoopHelper.NumIterations;
15917 auto *OrigCntVar = cast<DeclRefExpr>(Val: LoopHelper.Counters[0]);
15918 QualType IVTy = NumIterations->getType();
15919 Stmt *LoopStmt = LoopStmts[I];
15920
15921 // Commonly used variables. One of the constraints of an AST is that every
15922 // node object must appear at most once, hence we define a lambda that
15923 // creates a new AST node at every use.
15924 auto MakeTileIVRef = [&SemaRef = this->SemaRef, &TileIndVars, I, IVTy,
15925 OrigCntVar]() {
15926 return buildDeclRefExpr(S&: SemaRef, D: TileIndVars[I], Ty: IVTy,
15927 Loc: OrigCntVar->getExprLoc());
15928 };
15929
15930 // For init-statement: auto .tile.iv = .floor.iv
15931 SemaRef.AddInitializerToDecl(
15932 dcl: TileIndVars[I],
15933 init: SemaRef
15934 .DefaultLvalueConversion(
15935 E: makeFloorIVRef(SemaRef, FloorIndVars, I, IVTy, OrigCntVar))
15936 .get(),
15937 /*DirectInit=*/false);
15938 Decl *CounterDecl = TileIndVars[I];
15939 StmtResult InitStmt = new (Context)
15940 DeclStmt(DeclGroupRef::Create(C&: Context, Decls: &CounterDecl, NumDecls: 1),
15941 OrigCntVar->getBeginLoc(), OrigCntVar->getEndLoc());
15942 if (!InitStmt.isUsable())
15943 return StmtError();
15944
15945 // For cond-expression:
15946 // .tile.iv < min(.floor.iv + DimTileSize, NumIterations)
15947 Expr *DimTileSize = MakeDimTileSize(I);
15948 if (!DimTileSize)
15949 return StmtError();
15950 ExprResult EndOfTile = SemaRef.BuildBinOp(
15951 S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_Add,
15952 LHSExpr: makeFloorIVRef(SemaRef, FloorIndVars, I, IVTy, OrigCntVar),
15953 RHSExpr: DimTileSize);
15954 if (!EndOfTile.isUsable())
15955 return StmtError();
15956 ExprResult IsPartialTile =
15957 SemaRef.BuildBinOp(S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_LT,
15958 LHSExpr: NumIterations, RHSExpr: EndOfTile.get());
15959 if (!IsPartialTile.isUsable())
15960 return StmtError();
15961 ExprResult MinTileAndIterSpace = SemaRef.ActOnConditionalOp(
15962 QuestionLoc: LoopHelper.Cond->getBeginLoc(), ColonLoc: LoopHelper.Cond->getEndLoc(),
15963 CondExpr: IsPartialTile.get(), LHSExpr: NumIterations, RHSExpr: EndOfTile.get());
15964 if (!MinTileAndIterSpace.isUsable())
15965 return StmtError();
15966 ExprResult CondExpr =
15967 SemaRef.BuildBinOp(S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_LT,
15968 LHSExpr: MakeTileIVRef(), RHSExpr: MinTileAndIterSpace.get());
15969 if (!CondExpr.isUsable())
15970 return StmtError();
15971
15972 // For incr-statement: ++.tile.iv
15973 ExprResult IncrStmt = SemaRef.BuildUnaryOp(
15974 S: CurScope, OpLoc: LoopHelper.Inc->getExprLoc(), Opc: UO_PreInc, Input: MakeTileIVRef());
15975 if (!IncrStmt.isUsable())
15976 return StmtError();
15977
15978 // Build OMPInvariantPredicateBoundAttr hint (RectCond, TileSize,
15979 // Predicate).
15980 Expr *RectDimTileSize = MakeDimTileSize(I);
15981 if (!RectDimTileSize)
15982 return StmtError();
15983 ExprResult RectEndOfTile = SemaRef.BuildBinOp(
15984 S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_Add,
15985 LHSExpr: makeFloorIVRef(SemaRef, FloorIndVars, I, IVTy, OrigCntVar),
15986 RHSExpr: RectDimTileSize);
15987 if (!RectEndOfTile.isUsable())
15988 return StmtError();
15989 ExprResult RectCond =
15990 SemaRef.BuildBinOp(S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_LT,
15991 LHSExpr: MakeTileIVRef(), RHSExpr: RectEndOfTile.get());
15992 Expr *TileSizeExpr = MakeDimTileSize(I);
15993 if (!TileSizeExpr)
15994 return StmtError();
15995 ExprResult TileSize = SemaRef.PerformImplicitConversion(
15996 From: TileSizeExpr, ToType: IVTy, Action: AssignmentAction::Converting,
15997 /*AllowExplicit=*/true);
15998 if (!RectCond.isUsable() || !TileSize.isUsable())
15999 return StmtError();
16000
16001 // The overshoot guard is only needed if the last tile can be partial. When
16002 // both the trip count and the tile size are known at compile time and the
16003 // former is a multiple of the latter, every tile is full, so leave the
16004 // predicate out. A dependent or run-time value makes
16005 // the evaluation fail, which keeps the guard.
16006 bool NoPartialTile = false;
16007 Expr::EvalResult TileSizeVal, NumIterationsVal;
16008 if (TileSizeExpr->EvaluateAsInt(Result&: TileSizeVal, Ctx: Context) &&
16009 NumIterations->EvaluateAsInt(Result&: NumIterationsVal, Ctx: Context)) {
16010 llvm::APSInt TS = TileSizeVal.Val.getInt();
16011 llvm::APSInt N = NumIterationsVal.Val.getInt();
16012 unsigned Width = std::max(a: TS.getBitWidth(), b: N.getBitWidth());
16013 TS = TS.extend(width: Width);
16014 N = N.extend(width: Width);
16015 NoPartialTile =
16016 TS.isStrictlyPositive() && N.isStrictlyPositive() && N.urem(RHS: TS) == 0;
16017 }
16018
16019 ExprResult Predicate;
16020 if (!NoPartialTile) {
16021 Predicate = SemaRef.BuildBinOp(S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(),
16022 Opc: BO_LT, LHSExpr: MakeTileIVRef(), RHSExpr: NumIterations);
16023 if (!Predicate.isUsable())
16024 return StmtError();
16025 }
16026
16027 // Statements to set the original iteration variable's value from the
16028 // logical iteration number.
16029 // Generated for loop is:
16030 // \code
16031 // Original_for_init;
16032 // for (auto .tile.iv = .floor.iv;
16033 // .tile.iv < min(.floor.iv + DimTileSize, NumIterations);
16034 // ++.tile.iv) {
16035 // Original_Body;
16036 // Original_counter_update;
16037 // }
16038 // \endcode
16039 // FIXME: If the innermost body is an loop itself, inserting these
16040 // statements stops it being recognized as a perfectly nested loop (e.g.
16041 // for applying tiling again). If this is the case, sink the expressions
16042 // further into the inner loop.
16043 SmallVector<Stmt *, 4> BodyParts;
16044 BodyParts.append(in_start: LoopHelper.Updates.begin(), in_end: LoopHelper.Updates.end());
16045 if (auto *SourceCXXFor = dyn_cast<CXXForRangeStmt>(Val: LoopStmt))
16046 BodyParts.push_back(Elt: SourceCXXFor->getLoopVarStmt());
16047 if (static_cast<unsigned>(I) + 1 < NumLoops)
16048 appendStmtsBeforeNestedLoop(LoopStmt, BodyParts);
16049 BodyParts.push_back(Elt: Inner);
16050 Inner = CompoundStmt::Create(C: Context, Stmts: BodyParts, FPFeatures: FPOptionsOverride(),
16051 LB: Inner->getBeginLoc(), RB: Inner->getEndLoc());
16052 Inner = new (Context)
16053 ForStmt(Context, InitStmt.get(), CondExpr.get(), nullptr,
16054 IncrStmt.get(), Inner, LoopHelper.Init->getBeginLoc(),
16055 LoopHelper.Init->getBeginLoc(), LoopHelper.Inc->getEndLoc());
16056
16057 // Attach the droppable reinterpretation attribute to the intra-tile loop.
16058 auto *Hint = OMPInvariantPredicateBoundAttr::CreateImplicit(
16059 Ctx&: Context, RectCond: RectCond.get(), TileSize: TileSize.get(),
16060 Predicate: Predicate.isUsable() ? Predicate.get() : nullptr,
16061 Range: Inner->getSourceRange());
16062 Inner =
16063 AttributedStmt::Create(C: Context, Loc: Inner->getBeginLoc(), Attrs: {Hint}, SubStmt: Inner);
16064 }
16065
16066 // Create floor loops from the inside to the outside.
16067 for (int I = NumLoops - 1; I >= 0; --I) {
16068 auto &LoopHelper = LoopHelpers[I];
16069 Expr *NumIterations = LoopHelper.NumIterations;
16070 DeclRefExpr *OrigCntVar = cast<DeclRefExpr>(Val: LoopHelper.Counters[0]);
16071 QualType IVTy = NumIterations->getType();
16072
16073 // For init-statement: auto .floor.iv = 0
16074 SemaRef.AddInitializerToDecl(
16075 dcl: FloorIndVars[I],
16076 init: SemaRef.ActOnIntegerConstant(Loc: LoopHelper.Init->getExprLoc(), Val: 0).get(),
16077 /*DirectInit=*/false);
16078 Decl *CounterDecl = FloorIndVars[I];
16079 StmtResult InitStmt = new (Context)
16080 DeclStmt(DeclGroupRef::Create(C&: Context, Decls: &CounterDecl, NumDecls: 1),
16081 OrigCntVar->getBeginLoc(), OrigCntVar->getEndLoc());
16082 if (!InitStmt.isUsable())
16083 return StmtError();
16084
16085 // For cond-expression: .floor.iv < NumIterations
16086 ExprResult CondExpr = SemaRef.BuildBinOp(
16087 S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_LT,
16088 LHSExpr: makeFloorIVRef(SemaRef, FloorIndVars, I, IVTy, OrigCntVar),
16089 RHSExpr: NumIterations);
16090 if (!CondExpr.isUsable())
16091 return StmtError();
16092
16093 // For incr-statement: .floor.iv += DimTileSize
16094 Expr *DimTileSize = MakeDimTileSize(I);
16095 if (!DimTileSize)
16096 return StmtError();
16097 ExprResult IncrStmt = SemaRef.BuildBinOp(
16098 S: CurScope, OpLoc: LoopHelper.Inc->getExprLoc(), Opc: BO_AddAssign,
16099 LHSExpr: makeFloorIVRef(SemaRef, FloorIndVars, I, IVTy, OrigCntVar),
16100 RHSExpr: DimTileSize);
16101 if (!IncrStmt.isUsable())
16102 return StmtError();
16103
16104 Inner = new (Context)
16105 ForStmt(Context, InitStmt.get(), CondExpr.get(), nullptr,
16106 IncrStmt.get(), Inner, LoopHelper.Init->getBeginLoc(),
16107 LoopHelper.Init->getBeginLoc(), LoopHelper.Inc->getEndLoc());
16108 }
16109
16110 return OMPTileDirective::Create(C: Context, StartLoc, EndLoc, Clauses, NumLoops,
16111 AssociatedStmt: AStmt, TransformedStmt: Inner,
16112 PreInits: buildPreInits(Context, PreInits));
16113}
16114
16115StmtResult SemaOpenMP::ActOnOpenMPStripeDirective(ArrayRef<OMPClause *> Clauses,
16116 Stmt *AStmt,
16117 SourceLocation StartLoc,
16118 SourceLocation EndLoc) {
16119 ASTContext &Context = getASTContext();
16120 Scope *CurScope = SemaRef.getCurScope();
16121
16122 const auto *SizesClause =
16123 OMPExecutableDirective::getSingleClause<OMPSizesClause>(Clauses);
16124 if (!SizesClause ||
16125 llvm::any_of(Range: SizesClause->getSizesRefs(), P: [](const Expr *SizeExpr) {
16126 return !SizeExpr || SizeExpr->containsErrors();
16127 }))
16128 return StmtError();
16129 unsigned NumLoops = SizesClause->getNumSizes();
16130
16131 // Empty statement should only be possible if there already was an error.
16132 if (!AStmt)
16133 return StmtError();
16134
16135 // Verify and diagnose loop nest.
16136 SmallVector<OMPLoopBasedDirective::HelperExprs, 4> LoopHelpers(NumLoops);
16137 Stmt *Body = nullptr;
16138 SmallVector<SmallVector<Stmt *>, 4> OriginalInits;
16139 if (!checkTransformableLoopNest(Kind: OMPD_stripe, AStmt, NumLoops, LoopHelpers,
16140 Body, OriginalInits))
16141 return StmtError();
16142
16143 // Delay striping to when template is completely instantiated.
16144 if (SemaRef.CurContext->isDependentContext())
16145 return OMPStripeDirective::Create(C: Context, StartLoc, EndLoc, Clauses,
16146 NumLoops, AssociatedStmt: AStmt, TransformedStmt: nullptr, PreInits: nullptr);
16147
16148 assert(LoopHelpers.size() == NumLoops &&
16149 "Expecting loop iteration space dimensionality to match number of "
16150 "affected loops");
16151 assert(OriginalInits.size() == NumLoops &&
16152 "Expecting loop iteration space dimensionality to match number of "
16153 "affected loops");
16154
16155 // Collect all affected loop statements.
16156 SmallVector<Stmt *> LoopStmts(NumLoops, nullptr);
16157 collectLoopStmts(AStmt, LoopStmts, /*RelaxNestForPeeledTransformation=*/true);
16158
16159 SmallVector<Stmt *, 4> PreInits;
16160 CaptureVars CopyTransformer(SemaRef);
16161
16162 // Create iteration variables for the generated loops.
16163 SmallVector<VarDecl *, 4> FloorIndVars;
16164 SmallVector<VarDecl *, 4> StripeIndVars;
16165 FloorIndVars.resize(N: NumLoops);
16166 StripeIndVars.resize(N: NumLoops);
16167 for (unsigned I : llvm::seq<unsigned>(Size: NumLoops)) {
16168 OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I];
16169
16170 assert(LoopHelper.Counters.size() == 1 &&
16171 "Expect single-dimensional loop iteration space");
16172 auto *OrigCntVar = cast<DeclRefExpr>(Val: LoopHelper.Counters.front());
16173 std::string OrigVarName = OrigCntVar->getNameInfo().getAsString();
16174 DeclRefExpr *IterVarRef = cast<DeclRefExpr>(Val: LoopHelper.IterationVarRef);
16175 QualType CntTy = IterVarRef->getType();
16176
16177 // Iteration variable for the stripe (i.e. outer) loop.
16178 {
16179 std::string FloorCntName =
16180 (Twine(".floor_") + llvm::utostr(X: I) + ".iv." + OrigVarName).str();
16181 VarDecl *FloorCntDecl =
16182 buildVarDecl(SemaRef, Loc: {}, Type: CntTy, Name: FloorCntName, Attrs: nullptr, OrigRef: OrigCntVar);
16183 FloorIndVars[I] = FloorCntDecl;
16184 }
16185
16186 // Iteration variable for the stripe (i.e. inner) loop.
16187 {
16188 std::string StripeCntName =
16189 (Twine(".stripe_") + llvm::utostr(X: I) + ".iv." + OrigVarName).str();
16190
16191 // Reuse the iteration variable created by checkOpenMPLoop. It is also
16192 // used by the expressions to derive the original iteration variable's
16193 // value from the logical iteration number.
16194 auto *StripeCntDecl = cast<VarDecl>(Val: IterVarRef->getDecl());
16195 StripeCntDecl->setDeclName(
16196 &SemaRef.PP.getIdentifierTable().get(Name: StripeCntName));
16197 StripeIndVars[I] = StripeCntDecl;
16198 }
16199
16200 addLoopPreInits(Context, LoopHelper, LoopStmt: LoopStmts[I], OriginalInit: OriginalInits[I],
16201 PreInits);
16202 }
16203
16204 // Once the original iteration values are set, append the innermost body.
16205 Stmt *Inner = Body;
16206
16207 auto MakeDimStripeSize = [&](int I) -> Expr * {
16208 Expr *DimStripeSizeExpr = SizesClause->getSizesRefs()[I];
16209 if (isa<ConstantExpr>(Val: DimStripeSizeExpr))
16210 return AssertSuccess(R: CopyTransformer.TransformExpr(E: DimStripeSizeExpr));
16211
16212 // When the stripe size is not a constant but a variable, it is possible to
16213 // pass non-positive numbers. For instance:
16214 // \code{c}
16215 // int a = 0;
16216 // #pragma omp stripe sizes(a)
16217 // for (int i = 0; i < 42; ++i)
16218 // body(i);
16219 // \endcode
16220 // Although there is no meaningful interpretation of the stripe size, the
16221 // body should still be executed 42 times to avoid surprises. To preserve
16222 // the invariant that every loop iteration is executed exactly once and not
16223 // cause an infinite loop, apply a minimum stripe size of one.
16224 // Build expr:
16225 // \code{c}
16226 // (TS <= 0) ? 1 : TS
16227 // \endcode
16228 QualType DimTy = DimStripeSizeExpr->getType();
16229 uint64_t DimWidth = Context.getTypeSize(T: DimTy);
16230 IntegerLiteral *Zero = IntegerLiteral::Create(
16231 C: Context, V: llvm::APInt::getZero(numBits: DimWidth), type: DimTy, l: {});
16232 IntegerLiteral *One =
16233 IntegerLiteral::Create(C: Context, V: llvm::APInt(DimWidth, 1), type: DimTy, l: {});
16234 Expr *Cond = AssertSuccess(R: SemaRef.BuildBinOp(
16235 S: CurScope, OpLoc: {}, Opc: BO_LE,
16236 LHSExpr: AssertSuccess(R: CopyTransformer.TransformExpr(E: DimStripeSizeExpr)), RHSExpr: Zero));
16237 Expr *MinOne = new (Context) ConditionalOperator(
16238 Cond, {}, One, {},
16239 AssertSuccess(R: CopyTransformer.TransformExpr(E: DimStripeSizeExpr)), DimTy,
16240 VK_PRValue, OK_Ordinary);
16241 return MinOne;
16242 };
16243
16244 // Create stripe loops from the inside to the outside.
16245 for (int I = NumLoops - 1; I >= 0; --I) {
16246 OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I];
16247 Expr *NumIterations = LoopHelper.NumIterations;
16248 auto *OrigCntVar = cast<DeclRefExpr>(Val: LoopHelper.Counters[0]);
16249 QualType IVTy = NumIterations->getType();
16250 Stmt *LoopStmt = LoopStmts[I];
16251
16252 // For init-statement: auto .stripe.iv = .floor.iv
16253 SemaRef.AddInitializerToDecl(
16254 dcl: StripeIndVars[I],
16255 init: SemaRef
16256 .DefaultLvalueConversion(
16257 E: makeFloorIVRef(SemaRef, FloorIndVars, I, IVTy, OrigCntVar))
16258 .get(),
16259 /*DirectInit=*/false);
16260 Decl *CounterDecl = StripeIndVars[I];
16261 StmtResult InitStmt = new (Context)
16262 DeclStmt(DeclGroupRef::Create(C&: Context, Decls: &CounterDecl, NumDecls: 1),
16263 OrigCntVar->getBeginLoc(), OrigCntVar->getEndLoc());
16264 if (!InitStmt.isUsable())
16265 return StmtError();
16266
16267 // For cond-expression:
16268 // .stripe.iv < min(.floor.iv + DimStripeSize, NumIterations)
16269 ExprResult EndOfStripe = SemaRef.BuildBinOp(
16270 S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_Add,
16271 LHSExpr: makeFloorIVRef(SemaRef, FloorIndVars, I, IVTy, OrigCntVar),
16272 RHSExpr: MakeDimStripeSize(I));
16273 if (!EndOfStripe.isUsable())
16274 return StmtError();
16275 ExprResult IsPartialStripe =
16276 SemaRef.BuildBinOp(S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_LT,
16277 LHSExpr: NumIterations, RHSExpr: EndOfStripe.get());
16278 if (!IsPartialStripe.isUsable())
16279 return StmtError();
16280 ExprResult MinStripeAndIterSpace = SemaRef.ActOnConditionalOp(
16281 QuestionLoc: LoopHelper.Cond->getBeginLoc(), ColonLoc: LoopHelper.Cond->getEndLoc(),
16282 CondExpr: IsPartialStripe.get(), LHSExpr: NumIterations, RHSExpr: EndOfStripe.get());
16283 if (!MinStripeAndIterSpace.isUsable())
16284 return StmtError();
16285 ExprResult CondExpr = SemaRef.BuildBinOp(
16286 S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_LT,
16287 LHSExpr: makeFloorIVRef(SemaRef, FloorIndVars: StripeIndVars, I, IVTy, OrigCntVar),
16288 RHSExpr: MinStripeAndIterSpace.get());
16289 if (!CondExpr.isUsable())
16290 return StmtError();
16291
16292 // For incr-statement: ++.stripe.iv
16293 ExprResult IncrStmt = SemaRef.BuildUnaryOp(
16294 S: CurScope, OpLoc: LoopHelper.Inc->getExprLoc(), Opc: UO_PreInc,
16295 Input: makeFloorIVRef(SemaRef, FloorIndVars: StripeIndVars, I, IVTy, OrigCntVar));
16296 if (!IncrStmt.isUsable())
16297 return StmtError();
16298
16299 // Statements to set the original iteration variable's value from the
16300 // logical iteration number.
16301 // Generated for loop is:
16302 // \code
16303 // Original_for_init;
16304 // for (auto .stripe.iv = .floor.iv;
16305 // .stripe.iv < min(.floor.iv + DimStripeSize, NumIterations);
16306 // ++.stripe.iv) {
16307 // Original_Body;
16308 // Original_counter_update;
16309 // }
16310 // \endcode
16311 // FIXME: If the innermost body is a loop itself, inserting these
16312 // statements stops it being recognized as a perfectly nested loop (e.g.
16313 // for applying another loop transformation). If this is the case, sink the
16314 // expressions further into the inner loop.
16315 SmallVector<Stmt *, 4> BodyParts;
16316 BodyParts.append(in_start: LoopHelper.Updates.begin(), in_end: LoopHelper.Updates.end());
16317 if (auto *SourceCXXFor = dyn_cast<CXXForRangeStmt>(Val: LoopStmt))
16318 BodyParts.push_back(Elt: SourceCXXFor->getLoopVarStmt());
16319 if (static_cast<unsigned>(I) + 1 < NumLoops)
16320 appendStmtsBeforeNestedLoop(LoopStmt, BodyParts);
16321 BodyParts.push_back(Elt: Inner);
16322 Inner = CompoundStmt::Create(C: Context, Stmts: BodyParts, FPFeatures: FPOptionsOverride(),
16323 LB: Inner->getBeginLoc(), RB: Inner->getEndLoc());
16324 Inner = new (Context)
16325 ForStmt(Context, InitStmt.get(), CondExpr.get(), nullptr,
16326 IncrStmt.get(), Inner, LoopHelper.Init->getBeginLoc(),
16327 LoopHelper.Init->getBeginLoc(), LoopHelper.Inc->getEndLoc());
16328 }
16329
16330 // Create grid loops from the inside to the outside.
16331 for (int I = NumLoops - 1; I >= 0; --I) {
16332 auto &LoopHelper = LoopHelpers[I];
16333 Expr *NumIterations = LoopHelper.NumIterations;
16334 DeclRefExpr *OrigCntVar = cast<DeclRefExpr>(Val: LoopHelper.Counters[0]);
16335 QualType IVTy = NumIterations->getType();
16336
16337 // For init-statement: auto .grid.iv = 0
16338 SemaRef.AddInitializerToDecl(
16339 dcl: FloorIndVars[I],
16340 init: SemaRef.ActOnIntegerConstant(Loc: LoopHelper.Init->getExprLoc(), Val: 0).get(),
16341 /*DirectInit=*/false);
16342 Decl *CounterDecl = FloorIndVars[I];
16343 StmtResult InitStmt = new (Context)
16344 DeclStmt(DeclGroupRef::Create(C&: Context, Decls: &CounterDecl, NumDecls: 1),
16345 OrigCntVar->getBeginLoc(), OrigCntVar->getEndLoc());
16346 if (!InitStmt.isUsable())
16347 return StmtError();
16348
16349 // For cond-expression: .floor.iv < NumIterations
16350 ExprResult CondExpr = SemaRef.BuildBinOp(
16351 S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_LT,
16352 LHSExpr: makeFloorIVRef(SemaRef, FloorIndVars, I, IVTy, OrigCntVar),
16353 RHSExpr: NumIterations);
16354 if (!CondExpr.isUsable())
16355 return StmtError();
16356
16357 // For incr-statement: .floor.iv += DimStripeSize
16358 ExprResult IncrStmt = SemaRef.BuildBinOp(
16359 S: CurScope, OpLoc: LoopHelper.Inc->getExprLoc(), Opc: BO_AddAssign,
16360 LHSExpr: makeFloorIVRef(SemaRef, FloorIndVars, I, IVTy, OrigCntVar),
16361 RHSExpr: MakeDimStripeSize(I));
16362 if (!IncrStmt.isUsable())
16363 return StmtError();
16364
16365 Inner = new (Context)
16366 ForStmt(Context, InitStmt.get(), CondExpr.get(), nullptr,
16367 IncrStmt.get(), Inner, LoopHelper.Init->getBeginLoc(),
16368 LoopHelper.Init->getBeginLoc(), LoopHelper.Inc->getEndLoc());
16369 }
16370
16371 return OMPStripeDirective::Create(C: Context, StartLoc, EndLoc, Clauses,
16372 NumLoops, AssociatedStmt: AStmt, TransformedStmt: Inner,
16373 PreInits: buildPreInits(Context, PreInits));
16374}
16375
16376StmtResult SemaOpenMP::ActOnOpenMPUnrollDirective(ArrayRef<OMPClause *> Clauses,
16377 Stmt *AStmt,
16378 SourceLocation StartLoc,
16379 SourceLocation EndLoc) {
16380 ASTContext &Context = getASTContext();
16381 Scope *CurScope = SemaRef.getCurScope();
16382 // Empty statement should only be possible if there already was an error.
16383 if (!AStmt)
16384 return StmtError();
16385
16386 if (checkMutuallyExclusiveClauses(S&: SemaRef, Clauses,
16387 MutuallyExclusiveClauses: {OMPC_partial, OMPC_full}))
16388 return StmtError();
16389
16390 const OMPFullClause *FullClause =
16391 OMPExecutableDirective::getSingleClause<OMPFullClause>(Clauses);
16392 const OMPPartialClause *PartialClause =
16393 OMPExecutableDirective::getSingleClause<OMPPartialClause>(Clauses);
16394 assert(!(FullClause && PartialClause) &&
16395 "mutual exclusivity must have been checked before");
16396
16397 constexpr unsigned NumLoops = 1;
16398 Stmt *Body = nullptr;
16399 SmallVector<OMPLoopBasedDirective::HelperExprs, NumLoops> LoopHelpers(
16400 NumLoops);
16401 SmallVector<SmallVector<Stmt *>, NumLoops + 1> OriginalInits;
16402 if (!checkTransformableLoopNest(Kind: OMPD_unroll, AStmt, NumLoops, LoopHelpers,
16403 Body, OriginalInits))
16404 return StmtError();
16405
16406 unsigned NumGeneratedTopLevelLoops = PartialClause ? 1 : 0;
16407
16408 // Delay unrolling to when template is completely instantiated.
16409 if (SemaRef.CurContext->isDependentContext())
16410 return OMPUnrollDirective::Create(C: Context, StartLoc, EndLoc, Clauses, AssociatedStmt: AStmt,
16411 NumGeneratedTopLevelLoops, TransformedStmt: nullptr,
16412 PreInits: nullptr);
16413
16414 assert(LoopHelpers.size() == NumLoops &&
16415 "Expecting a single-dimensional loop iteration space");
16416 assert(OriginalInits.size() == NumLoops &&
16417 "Expecting a single-dimensional loop iteration space");
16418 OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers.front();
16419
16420 if (FullClause) {
16421 if (!VerifyPositiveIntegerConstantInClause(
16422 Op: LoopHelper.NumIterations, CKind: OMPC_full, /*StrictlyPositive=*/false,
16423 /*SuppressExprDiags=*/true)
16424 .isUsable()) {
16425 Diag(Loc: AStmt->getBeginLoc(), DiagID: diag::err_omp_unroll_full_variable_trip_count);
16426 Diag(Loc: FullClause->getBeginLoc(), DiagID: diag::note_omp_directive_here)
16427 << "#pragma omp unroll full";
16428 return StmtError();
16429 }
16430 }
16431
16432 // The generated loop may only be passed to other loop-associated directive
16433 // when a partial clause is specified. Without the requirement it is
16434 // sufficient to generate loop unroll metadata at code-generation.
16435 if (NumGeneratedTopLevelLoops == 0)
16436 return OMPUnrollDirective::Create(C: Context, StartLoc, EndLoc, Clauses, AssociatedStmt: AStmt,
16437 NumGeneratedTopLevelLoops, TransformedStmt: nullptr,
16438 PreInits: nullptr);
16439
16440 // Otherwise, we need to provide a de-sugared/transformed AST that can be
16441 // associated with another loop directive.
16442 //
16443 // The canonical loop analysis return by checkTransformableLoopNest assumes
16444 // the following structure to be the same loop without transformations or
16445 // directives applied: \code OriginalInits; LoopHelper.PreInits;
16446 // LoopHelper.Counters;
16447 // for (; IV < LoopHelper.NumIterations; ++IV) {
16448 // LoopHelper.Updates;
16449 // Body;
16450 // }
16451 // \endcode
16452 // where IV is a variable declared and initialized to 0 in LoopHelper.PreInits
16453 // and referenced by LoopHelper.IterationVarRef.
16454 //
16455 // The unrolling directive transforms this into the following loop:
16456 // \code
16457 // OriginalInits; \
16458 // LoopHelper.PreInits; > NewPreInits
16459 // LoopHelper.Counters; /
16460 // for (auto UIV = 0; UIV < LoopHelper.NumIterations; UIV+=Factor) {
16461 // #pragma clang loop unroll_count(Factor)
16462 // for (IV = UIV; IV < UIV + Factor && UIV < LoopHelper.NumIterations; ++IV)
16463 // {
16464 // LoopHelper.Updates;
16465 // Body;
16466 // }
16467 // }
16468 // \endcode
16469 // where UIV is a new logical iteration counter. IV must be the same VarDecl
16470 // as the original LoopHelper.IterationVarRef because LoopHelper.Updates
16471 // references it. If the partially unrolled loop is associated with another
16472 // loop directive (like an OMPForDirective), it will use checkOpenMPLoop to
16473 // analyze this loop, i.e. the outer loop must fulfill the constraints of an
16474 // OpenMP canonical loop. The inner loop is not an associable canonical loop
16475 // and only exists to defer its unrolling to LLVM's LoopUnroll instead of
16476 // doing it in the frontend (by adding loop metadata). NewPreInits becomes a
16477 // property of the OMPLoopBasedDirective instead of statements in
16478 // CompoundStatement. This is to allow the loop to become a non-outermost loop
16479 // of a canonical loop nest where these PreInits are emitted before the
16480 // outermost directive.
16481
16482 // Find the loop statement.
16483 Stmt *LoopStmt = nullptr;
16484 collectLoopStmts(AStmt, LoopStmts: {LoopStmt});
16485
16486 // Determine the PreInit declarations.
16487 SmallVector<Stmt *, 4> PreInits;
16488 addLoopPreInits(Context, LoopHelper, LoopStmt, OriginalInit: OriginalInits[0], PreInits);
16489
16490 auto *IterationVarRef = cast<DeclRefExpr>(Val: LoopHelper.IterationVarRef);
16491 QualType IVTy = IterationVarRef->getType();
16492 assert(LoopHelper.Counters.size() == 1 &&
16493 "Expecting a single-dimensional loop iteration space");
16494 auto *OrigVar = cast<DeclRefExpr>(Val: LoopHelper.Counters.front());
16495
16496 // Determine the unroll factor.
16497 uint64_t Factor;
16498 SourceLocation FactorLoc;
16499 if (Expr *FactorVal = PartialClause->getFactor();
16500 FactorVal && !FactorVal->containsErrors()) {
16501 Factor = FactorVal->getIntegerConstantExpr(Ctx: Context)->getLimitedValue();
16502 FactorLoc = FactorVal->getExprLoc();
16503 } else {
16504 // TODO: Use a better profitability model.
16505 Factor = 2;
16506 }
16507 assert(Factor > 0 && "Expected positive unroll factor");
16508 auto MakeFactorExpr = [this, Factor, IVTy, FactorLoc]() {
16509 return IntegerLiteral::Create(
16510 C: getASTContext(), V: llvm::APInt(getASTContext().getIntWidth(T: IVTy), Factor),
16511 type: IVTy, l: FactorLoc);
16512 };
16513
16514 // Iteration variable SourceLocations.
16515 SourceLocation OrigVarLoc = OrigVar->getExprLoc();
16516 SourceLocation OrigVarLocBegin = OrigVar->getBeginLoc();
16517 SourceLocation OrigVarLocEnd = OrigVar->getEndLoc();
16518
16519 // Internal variable names.
16520 std::string OrigVarName = OrigVar->getNameInfo().getAsString();
16521 std::string OuterIVName = (Twine(".unrolled.iv.") + OrigVarName).str();
16522 std::string InnerIVName = (Twine(".unroll_inner.iv.") + OrigVarName).str();
16523
16524 // Create the iteration variable for the unrolled loop.
16525 VarDecl *OuterIVDecl =
16526 buildVarDecl(SemaRef, Loc: {}, Type: IVTy, Name: OuterIVName, Attrs: nullptr, OrigRef: OrigVar);
16527 auto MakeOuterRef = [this, OuterIVDecl, IVTy, OrigVarLoc]() {
16528 return buildDeclRefExpr(S&: SemaRef, D: OuterIVDecl, Ty: IVTy, Loc: OrigVarLoc);
16529 };
16530
16531 // Iteration variable for the inner loop: Reuse the iteration variable created
16532 // by checkOpenMPLoop.
16533 auto *InnerIVDecl = cast<VarDecl>(Val: IterationVarRef->getDecl());
16534 InnerIVDecl->setDeclName(&SemaRef.PP.getIdentifierTable().get(Name: InnerIVName));
16535 auto MakeInnerRef = [this, InnerIVDecl, IVTy, OrigVarLoc]() {
16536 return buildDeclRefExpr(S&: SemaRef, D: InnerIVDecl, Ty: IVTy, Loc: OrigVarLoc);
16537 };
16538
16539 // Make a copy of the NumIterations expression for each use: By the AST
16540 // constraints, every expression object in a DeclContext must be unique.
16541 CaptureVars CopyTransformer(SemaRef);
16542 auto MakeNumIterations = [&CopyTransformer, &LoopHelper]() -> Expr * {
16543 return AssertSuccess(
16544 R: CopyTransformer.TransformExpr(E: LoopHelper.NumIterations));
16545 };
16546
16547 // Inner For init-statement: auto .unroll_inner.iv = .unrolled.iv
16548 ExprResult LValueConv = SemaRef.DefaultLvalueConversion(E: MakeOuterRef());
16549 SemaRef.AddInitializerToDecl(dcl: InnerIVDecl, init: LValueConv.get(),
16550 /*DirectInit=*/false);
16551 StmtResult InnerInit = new (Context)
16552 DeclStmt(DeclGroupRef(InnerIVDecl), OrigVarLocBegin, OrigVarLocEnd);
16553 if (!InnerInit.isUsable())
16554 return StmtError();
16555
16556 // Inner For cond-expression:
16557 // \code
16558 // .unroll_inner.iv < .unrolled.iv + Factor &&
16559 // .unroll_inner.iv < NumIterations
16560 // \endcode
16561 // This conjunction of two conditions allows ScalarEvolution to derive the
16562 // maximum trip count of the inner loop.
16563 ExprResult EndOfTile =
16564 SemaRef.BuildBinOp(S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_Add,
16565 LHSExpr: MakeOuterRef(), RHSExpr: MakeFactorExpr());
16566 if (!EndOfTile.isUsable())
16567 return StmtError();
16568 ExprResult InnerCond1 =
16569 SemaRef.BuildBinOp(S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_LT,
16570 LHSExpr: MakeInnerRef(), RHSExpr: EndOfTile.get());
16571 if (!InnerCond1.isUsable())
16572 return StmtError();
16573 ExprResult InnerCond2 =
16574 SemaRef.BuildBinOp(S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_LT,
16575 LHSExpr: MakeInnerRef(), RHSExpr: MakeNumIterations());
16576 if (!InnerCond2.isUsable())
16577 return StmtError();
16578 ExprResult InnerCond =
16579 SemaRef.BuildBinOp(S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_LAnd,
16580 LHSExpr: InnerCond1.get(), RHSExpr: InnerCond2.get());
16581 if (!InnerCond.isUsable())
16582 return StmtError();
16583
16584 // Inner For incr-statement: ++.unroll_inner.iv
16585 ExprResult InnerIncr = SemaRef.BuildUnaryOp(
16586 S: CurScope, OpLoc: LoopHelper.Inc->getExprLoc(), Opc: UO_PreInc, Input: MakeInnerRef());
16587 if (!InnerIncr.isUsable())
16588 return StmtError();
16589
16590 // Inner For statement.
16591 SmallVector<Stmt *> InnerBodyStmts;
16592 InnerBodyStmts.append(in_start: LoopHelper.Updates.begin(), in_end: LoopHelper.Updates.end());
16593 if (auto *CXXRangeFor = dyn_cast<CXXForRangeStmt>(Val: LoopStmt))
16594 InnerBodyStmts.push_back(Elt: CXXRangeFor->getLoopVarStmt());
16595 InnerBodyStmts.push_back(Elt: Body);
16596 CompoundStmt *InnerBody =
16597 CompoundStmt::Create(C: getASTContext(), Stmts: InnerBodyStmts, FPFeatures: FPOptionsOverride(),
16598 LB: Body->getBeginLoc(), RB: Body->getEndLoc());
16599 ForStmt *InnerFor = new (Context)
16600 ForStmt(Context, InnerInit.get(), InnerCond.get(), nullptr,
16601 InnerIncr.get(), InnerBody, LoopHelper.Init->getBeginLoc(),
16602 LoopHelper.Init->getBeginLoc(), LoopHelper.Inc->getEndLoc());
16603
16604 // Unroll metadata for the inner loop.
16605 // This needs to take into account the remainder portion of the unrolled loop,
16606 // hence `unroll(full)` does not apply here, even though the LoopUnroll pass
16607 // supports multiple loop exits. Instead, unroll using a factor equivalent to
16608 // the maximum trip count, which will also generate a remainder loop. Just
16609 // `unroll(enable)` (which could have been useful if the user has not
16610 // specified a concrete factor; even though the outer loop cannot be
16611 // influenced anymore, would avoid more code bloat than necessary) will refuse
16612 // the loop because "Won't unroll; remainder loop could not be generated when
16613 // assuming runtime trip count". Even if it did work, it must not choose a
16614 // larger unroll factor than the maximum loop length, or it would always just
16615 // execute the remainder loop.
16616 LoopHintAttr *UnrollHintAttr =
16617 LoopHintAttr::CreateImplicit(Ctx&: Context, Option: LoopHintAttr::UnrollCount,
16618 State: LoopHintAttr::Numeric, Value: MakeFactorExpr());
16619 AttributedStmt *InnerUnrolled = AttributedStmt::Create(
16620 C: getASTContext(), Loc: StartLoc, Attrs: {UnrollHintAttr}, SubStmt: InnerFor);
16621
16622 // Outer For init-statement: auto .unrolled.iv = 0
16623 SemaRef.AddInitializerToDecl(
16624 dcl: OuterIVDecl,
16625 init: SemaRef.ActOnIntegerConstant(Loc: LoopHelper.Init->getExprLoc(), Val: 0).get(),
16626 /*DirectInit=*/false);
16627 StmtResult OuterInit = new (Context)
16628 DeclStmt(DeclGroupRef(OuterIVDecl), OrigVarLocBegin, OrigVarLocEnd);
16629 if (!OuterInit.isUsable())
16630 return StmtError();
16631
16632 // Outer For cond-expression: .unrolled.iv < NumIterations
16633 ExprResult OuterConde =
16634 SemaRef.BuildBinOp(S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_LT,
16635 LHSExpr: MakeOuterRef(), RHSExpr: MakeNumIterations());
16636 if (!OuterConde.isUsable())
16637 return StmtError();
16638
16639 // Outer For incr-statement: .unrolled.iv += Factor
16640 ExprResult OuterIncr =
16641 SemaRef.BuildBinOp(S: CurScope, OpLoc: LoopHelper.Inc->getExprLoc(), Opc: BO_AddAssign,
16642 LHSExpr: MakeOuterRef(), RHSExpr: MakeFactorExpr());
16643 if (!OuterIncr.isUsable())
16644 return StmtError();
16645
16646 // Outer For statement.
16647 ForStmt *OuterFor = new (Context)
16648 ForStmt(Context, OuterInit.get(), OuterConde.get(), nullptr,
16649 OuterIncr.get(), InnerUnrolled, LoopHelper.Init->getBeginLoc(),
16650 LoopHelper.Init->getBeginLoc(), LoopHelper.Inc->getEndLoc());
16651
16652 return OMPUnrollDirective::Create(C: Context, StartLoc, EndLoc, Clauses, AssociatedStmt: AStmt,
16653 NumGeneratedTopLevelLoops, TransformedStmt: OuterFor,
16654 PreInits: buildPreInits(Context, PreInits));
16655}
16656
16657StmtResult SemaOpenMP::ActOnOpenMPReverseDirective(Stmt *AStmt,
16658 SourceLocation StartLoc,
16659 SourceLocation EndLoc) {
16660 ASTContext &Context = getASTContext();
16661 Scope *CurScope = SemaRef.getCurScope();
16662
16663 // Empty statement should only be possible if there already was an error.
16664 if (!AStmt)
16665 return StmtError();
16666
16667 constexpr unsigned NumLoops = 1;
16668 Stmt *Body = nullptr;
16669 SmallVector<OMPLoopBasedDirective::HelperExprs, NumLoops> LoopHelpers(
16670 NumLoops);
16671 SmallVector<SmallVector<Stmt *>, NumLoops + 1> OriginalInits;
16672 if (!checkTransformableLoopNest(Kind: OMPD_reverse, AStmt, NumLoops, LoopHelpers,
16673 Body, OriginalInits))
16674 return StmtError();
16675
16676 // Delay applying the transformation to when template is completely
16677 // instantiated.
16678 if (SemaRef.CurContext->isDependentContext())
16679 return OMPReverseDirective::Create(C: Context, StartLoc, EndLoc, AssociatedStmt: AStmt,
16680 NumLoops, TransformedStmt: nullptr, PreInits: nullptr);
16681
16682 assert(LoopHelpers.size() == NumLoops &&
16683 "Expecting a single-dimensional loop iteration space");
16684 assert(OriginalInits.size() == NumLoops &&
16685 "Expecting a single-dimensional loop iteration space");
16686 OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers.front();
16687
16688 // Find the loop statement.
16689 Stmt *LoopStmt = nullptr;
16690 collectLoopStmts(AStmt, LoopStmts: {LoopStmt});
16691
16692 // Determine the PreInit declarations.
16693 SmallVector<Stmt *> PreInits;
16694 addLoopPreInits(Context, LoopHelper, LoopStmt, OriginalInit: OriginalInits[0], PreInits);
16695
16696 auto *IterationVarRef = cast<DeclRefExpr>(Val: LoopHelper.IterationVarRef);
16697 QualType IVTy = IterationVarRef->getType();
16698 uint64_t IVWidth = Context.getTypeSize(T: IVTy);
16699 auto *OrigVar = cast<DeclRefExpr>(Val: LoopHelper.Counters.front());
16700
16701 // Iteration variable SourceLocations.
16702 SourceLocation OrigVarLoc = OrigVar->getExprLoc();
16703 SourceLocation OrigVarLocBegin = OrigVar->getBeginLoc();
16704 SourceLocation OrigVarLocEnd = OrigVar->getEndLoc();
16705
16706 // Locations pointing to the transformation.
16707 SourceLocation TransformLoc = StartLoc;
16708 SourceLocation TransformLocBegin = StartLoc;
16709 SourceLocation TransformLocEnd = EndLoc;
16710
16711 // Internal variable names.
16712 std::string OrigVarName = OrigVar->getNameInfo().getAsString();
16713 SmallString<64> ForwardIVName(".forward.iv.");
16714 ForwardIVName += OrigVarName;
16715 SmallString<64> ReversedIVName(".reversed.iv.");
16716 ReversedIVName += OrigVarName;
16717
16718 // LoopHelper.Updates will read the logical iteration number from
16719 // LoopHelper.IterationVarRef, compute the value of the user loop counter of
16720 // that logical iteration from it, then assign it to the user loop counter
16721 // variable. We cannot directly use LoopHelper.IterationVarRef as the
16722 // induction variable of the generated loop because it may cause an underflow:
16723 // \code{.c}
16724 // for (unsigned i = 0; i < n; ++i)
16725 // body(i);
16726 // \endcode
16727 //
16728 // Naive reversal:
16729 // \code{.c}
16730 // for (unsigned i = n-1; i >= 0; --i)
16731 // body(i);
16732 // \endcode
16733 //
16734 // Instead, we introduce a new iteration variable representing the logical
16735 // iteration counter of the original loop, convert it to the logical iteration
16736 // number of the reversed loop, then let LoopHelper.Updates compute the user's
16737 // loop iteration variable from it.
16738 // \code{.cpp}
16739 // for (auto .forward.iv = 0; .forward.iv < n; ++.forward.iv) {
16740 // auto .reversed.iv = n - .forward.iv - 1;
16741 // i = (.reversed.iv + 0) * 1; // LoopHelper.Updates
16742 // body(i); // Body
16743 // }
16744 // \endcode
16745
16746 // Subexpressions with more than one use. One of the constraints of an AST is
16747 // that every node object must appear at most once, hence we define a lambda
16748 // that creates a new AST node at every use.
16749 CaptureVars CopyTransformer(SemaRef);
16750 auto MakeNumIterations = [&CopyTransformer, &LoopHelper]() -> Expr * {
16751 return AssertSuccess(
16752 R: CopyTransformer.TransformExpr(E: LoopHelper.NumIterations));
16753 };
16754
16755 // Create the iteration variable for the forward loop (from 0 to n-1).
16756 VarDecl *ForwardIVDecl =
16757 buildVarDecl(SemaRef, Loc: {}, Type: IVTy, Name: ForwardIVName, Attrs: nullptr, OrigRef: OrigVar);
16758 auto MakeForwardRef = [&SemaRef = this->SemaRef, ForwardIVDecl, IVTy,
16759 OrigVarLoc]() {
16760 return buildDeclRefExpr(S&: SemaRef, D: ForwardIVDecl, Ty: IVTy, Loc: OrigVarLoc);
16761 };
16762
16763 // Iteration variable for the reversed induction variable (from n-1 downto 0):
16764 // Reuse the iteration variable created by checkOpenMPLoop.
16765 auto *ReversedIVDecl = cast<VarDecl>(Val: IterationVarRef->getDecl());
16766 ReversedIVDecl->setDeclName(
16767 &SemaRef.PP.getIdentifierTable().get(Name: ReversedIVName));
16768
16769 // For init-statement:
16770 // \code{.cpp}
16771 // auto .forward.iv = 0;
16772 // \endcode
16773 auto *Zero = IntegerLiteral::Create(C: Context, V: llvm::APInt::getZero(numBits: IVWidth),
16774 type: ForwardIVDecl->getType(), l: OrigVarLoc);
16775 SemaRef.AddInitializerToDecl(dcl: ForwardIVDecl, init: Zero, /*DirectInit=*/false);
16776 StmtResult Init = new (Context)
16777 DeclStmt(DeclGroupRef(ForwardIVDecl), OrigVarLocBegin, OrigVarLocEnd);
16778 if (!Init.isUsable())
16779 return StmtError();
16780
16781 // Forward iv cond-expression:
16782 // \code{.cpp}
16783 // .forward.iv < MakeNumIterations()
16784 // \endcode
16785 ExprResult Cond =
16786 SemaRef.BuildBinOp(S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_LT,
16787 LHSExpr: MakeForwardRef(), RHSExpr: MakeNumIterations());
16788 if (!Cond.isUsable())
16789 return StmtError();
16790
16791 // Forward incr-statement:
16792 // \code{.c}
16793 // ++.forward.iv
16794 // \endcode
16795 ExprResult Incr = SemaRef.BuildUnaryOp(S: CurScope, OpLoc: LoopHelper.Inc->getExprLoc(),
16796 Opc: UO_PreInc, Input: MakeForwardRef());
16797 if (!Incr.isUsable())
16798 return StmtError();
16799
16800 // Reverse the forward-iv:
16801 // \code{.cpp}
16802 // auto .reversed.iv = MakeNumIterations() - 1 - .forward.iv
16803 // \endcode
16804 auto *One = IntegerLiteral::Create(C: Context, V: llvm::APInt(IVWidth, 1), type: IVTy,
16805 l: TransformLoc);
16806 ExprResult Minus = SemaRef.BuildBinOp(S: CurScope, OpLoc: TransformLoc, Opc: BO_Sub,
16807 LHSExpr: MakeNumIterations(), RHSExpr: One);
16808 if (!Minus.isUsable())
16809 return StmtError();
16810 Minus = SemaRef.BuildBinOp(S: CurScope, OpLoc: TransformLoc, Opc: BO_Sub, LHSExpr: Minus.get(),
16811 RHSExpr: MakeForwardRef());
16812 if (!Minus.isUsable())
16813 return StmtError();
16814 StmtResult InitReversed = new (Context) DeclStmt(
16815 DeclGroupRef(ReversedIVDecl), TransformLocBegin, TransformLocEnd);
16816 if (!InitReversed.isUsable())
16817 return StmtError();
16818 SemaRef.AddInitializerToDecl(dcl: ReversedIVDecl, init: Minus.get(),
16819 /*DirectInit=*/false);
16820
16821 // The new loop body.
16822 SmallVector<Stmt *, 4> BodyStmts;
16823 BodyStmts.reserve(N: LoopHelper.Updates.size() + 2 +
16824 (isa<CXXForRangeStmt>(Val: LoopStmt) ? 1 : 0));
16825 BodyStmts.push_back(Elt: InitReversed.get());
16826 llvm::append_range(C&: BodyStmts, R&: LoopHelper.Updates);
16827 if (auto *CXXRangeFor = dyn_cast<CXXForRangeStmt>(Val: LoopStmt))
16828 BodyStmts.push_back(Elt: CXXRangeFor->getLoopVarStmt());
16829 BodyStmts.push_back(Elt: Body);
16830 auto *ReversedBody =
16831 CompoundStmt::Create(C: Context, Stmts: BodyStmts, FPFeatures: FPOptionsOverride(),
16832 LB: Body->getBeginLoc(), RB: Body->getEndLoc());
16833
16834 // Finally create the reversed For-statement.
16835 auto *ReversedFor = new (Context)
16836 ForStmt(Context, Init.get(), Cond.get(), nullptr, Incr.get(),
16837 ReversedBody, LoopHelper.Init->getBeginLoc(),
16838 LoopHelper.Init->getBeginLoc(), LoopHelper.Inc->getEndLoc());
16839 return OMPReverseDirective::Create(C: Context, StartLoc, EndLoc, AssociatedStmt: AStmt, NumLoops,
16840 TransformedStmt: ReversedFor,
16841 PreInits: buildPreInits(Context, PreInits));
16842}
16843
16844/// Build the AST for \#pragma omp split counts(c1, c2, ...).
16845///
16846/// Splits the single associated loop into N consecutive loops, where N is the
16847/// number of count expressions.
16848StmtResult SemaOpenMP::ActOnOpenMPSplitDirective(ArrayRef<OMPClause *> Clauses,
16849 Stmt *AStmt,
16850 SourceLocation StartLoc,
16851 SourceLocation EndLoc) {
16852 ASTContext &Context = getASTContext();
16853 Scope *CurScope = SemaRef.getCurScope();
16854
16855 // Empty statement should only be possible if there already was an error.
16856 if (!AStmt)
16857 return StmtError();
16858
16859 const auto *CountsClause =
16860 OMPExecutableDirective::getSingleClause<OMPCountsClause>(Clauses);
16861 if (!CountsClause)
16862 return StmtError();
16863
16864 // Split applies to a single loop; check it is transformable and get helpers.
16865 constexpr unsigned NumLoops = 1;
16866 Stmt *Body = nullptr;
16867 SmallVector<OMPLoopBasedDirective::HelperExprs, NumLoops> LoopHelpers(
16868 NumLoops);
16869 SmallVector<SmallVector<Stmt *>, NumLoops + 1> OriginalInits;
16870 if (!checkTransformableLoopNest(Kind: OMPD_split, AStmt, NumLoops, LoopHelpers,
16871 Body, OriginalInits))
16872 return StmtError();
16873
16874 // Delay applying the transformation to when template is completely
16875 // instantiated.
16876 if (SemaRef.CurContext->isDependentContext())
16877 return OMPSplitDirective::Create(C: Context, StartLoc, EndLoc, Clauses,
16878 NumLoops, AssociatedStmt: AStmt, TransformedStmt: nullptr, PreInits: nullptr);
16879
16880 assert(LoopHelpers.size() == NumLoops &&
16881 "Expecting a single-dimensional loop iteration space");
16882 assert(OriginalInits.size() == NumLoops &&
16883 "Expecting a single-dimensional loop iteration space");
16884 OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers.front();
16885
16886 // Find the loop statement.
16887 Stmt *LoopStmt = nullptr;
16888 collectLoopStmts(AStmt, LoopStmts: {LoopStmt});
16889
16890 // Determine the PreInit declarations.
16891 SmallVector<Stmt *> PreInits;
16892 addLoopPreInits(Context, LoopHelper, LoopStmt, OriginalInit: OriginalInits[0], PreInits);
16893
16894 // Type and name of the original loop variable; we create one IV per segment
16895 // and assign it to the original var so the body sees the same name.
16896 auto *IterationVarRef = cast<DeclRefExpr>(Val: LoopHelper.IterationVarRef);
16897 QualType IVTy = IterationVarRef->getType();
16898 uint64_t IVWidth = Context.getTypeSize(T: IVTy);
16899 auto *OrigVar = cast<DeclRefExpr>(Val: LoopHelper.Counters.front());
16900
16901 // Iteration variable SourceLocations.
16902 SourceLocation OrigVarLoc = OrigVar->getExprLoc();
16903 SourceLocation OrigVarLocBegin = OrigVar->getBeginLoc();
16904 SourceLocation OrigVarLocEnd = OrigVar->getEndLoc();
16905 // Internal variable names.
16906 std::string OrigVarName = OrigVar->getNameInfo().getAsString();
16907
16908 if (!CountsClause->hasOmpFill())
16909 return StmtError();
16910 unsigned FillIdx = *CountsClause->getOmpFillIndex();
16911
16912 unsigned NumItems = CountsClause->getNumCounts();
16913 SmallVector<uint64_t, 4> CountValues(NumItems, 0);
16914 ArrayRef<Expr *> Refs = CountsClause->getCountsRefs();
16915 for (unsigned I = 0; I < NumItems; ++I) {
16916 if (I == FillIdx)
16917 continue;
16918 Expr *CountExpr = Refs[I];
16919 if (!CountExpr)
16920 return OMPSplitDirective::Create(C: Context, StartLoc, EndLoc, Clauses,
16921 NumLoops, AssociatedStmt: AStmt, TransformedStmt: nullptr, PreInits: nullptr);
16922 std::optional<llvm::APSInt> OptVal =
16923 CountExpr->getIntegerConstantExpr(Ctx: Context);
16924 if (!OptVal || OptVal->isNegative())
16925 return OMPSplitDirective::Create(C: Context, StartLoc, EndLoc, Clauses,
16926 NumLoops, AssociatedStmt: AStmt, TransformedStmt: nullptr, PreInits: nullptr);
16927 CountValues[I] = OptVal->getLimitedValue();
16928 }
16929
16930 Expr *NumIterExpr = LoopHelper.NumIterations;
16931
16932 uint64_t RightSum = 0;
16933 for (unsigned I = FillIdx + 1; I < NumItems; ++I)
16934 RightSum += CountValues[I];
16935
16936 auto MakeIntLit = [&](uint64_t Val) {
16937 return IntegerLiteral::Create(C: Context, V: llvm::APInt(IVWidth, Val), type: IVTy,
16938 l: OrigVarLoc);
16939 };
16940
16941 size_t NumSegments = NumItems;
16942 SmallVector<Stmt *, 4> SplitLoops;
16943
16944 auto *IterVarDecl = cast<VarDecl>(Val: IterationVarRef->getDecl());
16945 SplitLoops.push_back(Elt: new (Context) DeclStmt(DeclGroupRef(IterVarDecl),
16946 IterationVarRef->getBeginLoc(),
16947 IterationVarRef->getEndLoc()));
16948
16949 uint64_t LeftAccum = 0;
16950 uint64_t RightRemaining = RightSum;
16951
16952 for (size_t Seg = 0; Seg < NumSegments; ++Seg) {
16953 Expr *StartExpr = nullptr;
16954 Expr *EndExpr = nullptr;
16955
16956 if (Seg < FillIdx) {
16957 StartExpr = MakeIntLit(LeftAccum);
16958 LeftAccum += CountValues[Seg];
16959 EndExpr = MakeIntLit(LeftAccum);
16960 } else if (Seg == FillIdx) {
16961 StartExpr = MakeIntLit(LeftAccum);
16962 if (RightRemaining == 0) {
16963 EndExpr = NumIterExpr;
16964 } else {
16965 ExprResult Sub =
16966 SemaRef.BuildBinOp(S: CurScope, OpLoc: OrigVarLoc, Opc: BO_Sub, LHSExpr: NumIterExpr,
16967 RHSExpr: MakeIntLit(RightRemaining));
16968 if (!Sub.isUsable())
16969 return StmtError();
16970 EndExpr = Sub.get();
16971 }
16972 } else {
16973 if (RightRemaining == RightSum) {
16974 if (RightSum == 0)
16975 StartExpr = NumIterExpr;
16976 else {
16977 ExprResult Sub =
16978 SemaRef.BuildBinOp(S: CurScope, OpLoc: OrigVarLoc, Opc: BO_Sub, LHSExpr: NumIterExpr,
16979 RHSExpr: MakeIntLit(RightRemaining));
16980 if (!Sub.isUsable())
16981 return StmtError();
16982 StartExpr = Sub.get();
16983 }
16984 } else {
16985 ExprResult Sub =
16986 SemaRef.BuildBinOp(S: CurScope, OpLoc: OrigVarLoc, Opc: BO_Sub, LHSExpr: NumIterExpr,
16987 RHSExpr: MakeIntLit(RightRemaining));
16988 if (!Sub.isUsable())
16989 return StmtError();
16990 StartExpr = Sub.get();
16991 }
16992 RightRemaining -= CountValues[Seg];
16993 if (RightRemaining == 0)
16994 EndExpr = NumIterExpr;
16995 else {
16996 ExprResult Sub =
16997 SemaRef.BuildBinOp(S: CurScope, OpLoc: OrigVarLoc, Opc: BO_Sub, LHSExpr: NumIterExpr,
16998 RHSExpr: MakeIntLit(RightRemaining));
16999 if (!Sub.isUsable())
17000 return StmtError();
17001 EndExpr = Sub.get();
17002 }
17003 }
17004
17005 SmallString<64> IVName(".split.iv.");
17006 IVName += (Twine(Seg) + "." + OrigVarName).str();
17007 VarDecl *IVDecl = buildVarDecl(SemaRef, Loc: {}, Type: IVTy, Name: IVName, Attrs: nullptr, OrigRef: OrigVar);
17008 auto MakeIVRef = [&SemaRef = this->SemaRef, IVDecl, IVTy, OrigVarLoc]() {
17009 return buildDeclRefExpr(S&: SemaRef, D: IVDecl, Ty: IVTy, Loc: OrigVarLoc);
17010 };
17011
17012 SemaRef.AddInitializerToDecl(dcl: IVDecl, init: StartExpr, /*DirectInit=*/false);
17013 StmtResult InitStmt = new (Context)
17014 DeclStmt(DeclGroupRef(IVDecl), OrigVarLocBegin, OrigVarLocEnd);
17015 if (!InitStmt.isUsable())
17016 return StmtError();
17017
17018 ExprResult CondExpr = SemaRef.BuildBinOp(
17019 S: CurScope, OpLoc: LoopHelper.Cond->getExprLoc(), Opc: BO_LT, LHSExpr: MakeIVRef(), RHSExpr: EndExpr);
17020 if (!CondExpr.isUsable())
17021 return StmtError();
17022
17023 ExprResult IncrExpr = SemaRef.BuildUnaryOp(
17024 S: CurScope, OpLoc: LoopHelper.Inc->getExprLoc(), Opc: UO_PreInc, Input: MakeIVRef());
17025 if (!IncrExpr.isUsable())
17026 return StmtError();
17027
17028 ExprResult IVAssign = SemaRef.BuildBinOp(S: CurScope, OpLoc: OrigVarLoc, Opc: BO_Assign,
17029 LHSExpr: IterationVarRef, RHSExpr: MakeIVRef());
17030 if (!IVAssign.isUsable())
17031 return StmtError();
17032
17033 SmallVector<Stmt *, 4> BodyStmts;
17034 BodyStmts.push_back(Elt: IVAssign.get());
17035 BodyStmts.append(in_start: LoopHelper.Updates.begin(), in_end: LoopHelper.Updates.end());
17036 if (auto *CXXRangeFor = dyn_cast<CXXForRangeStmt>(Val: LoopStmt)) {
17037 if (Seg == 0) {
17038 BodyStmts.push_back(Elt: CXXRangeFor->getLoopVarStmt());
17039 } else {
17040 VarDecl *LoopVar = CXXRangeFor->getLoopVariable();
17041 DeclRefExpr *LVRef = buildDeclRefExpr(
17042 S&: SemaRef, D: LoopVar, Ty: LoopVar->getType().getNonReferenceType(),
17043 Loc: OrigVarLoc);
17044 ExprResult LVAssign = SemaRef.BuildBinOp(
17045 S: CurScope, OpLoc: OrigVarLoc, Opc: BO_Assign, LHSExpr: LVRef, RHSExpr: LoopVar->getInit());
17046 if (!LVAssign.isUsable())
17047 return StmtError();
17048 BodyStmts.push_back(Elt: LVAssign.get());
17049 }
17050 }
17051 BodyStmts.push_back(Elt: Body);
17052
17053 auto *LoopBody =
17054 CompoundStmt::Create(C: Context, Stmts: BodyStmts, FPFeatures: FPOptionsOverride(),
17055 LB: Body->getBeginLoc(), RB: Body->getEndLoc());
17056
17057 auto *For = new (Context)
17058 ForStmt(Context, InitStmt.get(), CondExpr.get(), nullptr,
17059 IncrExpr.get(), LoopBody, LoopHelper.Init->getBeginLoc(),
17060 LoopHelper.Init->getBeginLoc(), LoopHelper.Inc->getEndLoc());
17061 SplitLoops.push_back(Elt: For);
17062 }
17063
17064 auto *SplitStmt = CompoundStmt::Create(
17065 C: Context, Stmts: SplitLoops, FPFeatures: FPOptionsOverride(),
17066 LB: SplitLoops.front()->getBeginLoc(), RB: SplitLoops.back()->getEndLoc());
17067
17068 return OMPSplitDirective::Create(C: Context, StartLoc, EndLoc, Clauses, NumLoops,
17069 AssociatedStmt: AStmt, TransformedStmt: SplitStmt,
17070 PreInits: buildPreInits(Context, PreInits));
17071}
17072
17073StmtResult SemaOpenMP::ActOnOpenMPInterchangeDirective(
17074 ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
17075 SourceLocation EndLoc) {
17076 ASTContext &Context = getASTContext();
17077 DeclContext *CurContext = SemaRef.CurContext;
17078 Scope *CurScope = SemaRef.getCurScope();
17079
17080 // Empty statement should only be possible if there already was an error.
17081 if (!AStmt)
17082 return StmtError();
17083
17084 // interchange without permutation clause swaps two loops.
17085 const OMPPermutationClause *PermutationClause =
17086 OMPExecutableDirective::getSingleClause<OMPPermutationClause>(Clauses);
17087 size_t NumLoops = PermutationClause ? PermutationClause->getNumLoops() : 2;
17088
17089 // Verify and diagnose loop nest.
17090 SmallVector<OMPLoopBasedDirective::HelperExprs, 4> LoopHelpers(NumLoops);
17091 Stmt *Body = nullptr;
17092 SmallVector<SmallVector<Stmt *>, 2> OriginalInits;
17093 if (!checkTransformableLoopNest(Kind: OMPD_interchange, AStmt, NumLoops,
17094 LoopHelpers, Body, OriginalInits))
17095 return StmtError();
17096
17097 // Delay interchange to when template is completely instantiated.
17098 if (CurContext->isDependentContext())
17099 return OMPInterchangeDirective::Create(C: Context, StartLoc, EndLoc, Clauses,
17100 NumLoops, AssociatedStmt: AStmt, TransformedStmt: nullptr, PreInits: nullptr);
17101
17102 // An invalid expression in the permutation clause is set to nullptr in
17103 // ActOnOpenMPPermutationClause.
17104 if (PermutationClause &&
17105 llvm::is_contained(Range: PermutationClause->getArgsRefs(), Element: nullptr))
17106 return StmtError();
17107
17108 assert(LoopHelpers.size() == NumLoops &&
17109 "Expecting loop iteration space dimensionaly to match number of "
17110 "affected loops");
17111 assert(OriginalInits.size() == NumLoops &&
17112 "Expecting loop iteration space dimensionaly to match number of "
17113 "affected loops");
17114
17115 // Decode the permutation clause.
17116 SmallVector<uint64_t, 2> Permutation;
17117 if (!PermutationClause) {
17118 Permutation = {1, 0};
17119 } else {
17120 ArrayRef<Expr *> PermArgs = PermutationClause->getArgsRefs();
17121 llvm::BitVector Flags(PermArgs.size());
17122 for (Expr *PermArg : PermArgs) {
17123 std::optional<llvm::APSInt> PermCstExpr =
17124 PermArg->getIntegerConstantExpr(Ctx: Context);
17125 if (!PermCstExpr)
17126 continue;
17127 uint64_t PermInt = PermCstExpr->getLimitedValue();
17128 assert(1 <= PermInt && PermInt <= NumLoops &&
17129 "Must be a permutation; diagnostic emitted in "
17130 "ActOnOpenMPPermutationClause");
17131 if (Flags[PermInt - 1]) {
17132 SourceRange ExprRange(PermArg->getBeginLoc(), PermArg->getEndLoc());
17133 Diag(Loc: PermArg->getExprLoc(),
17134 DiagID: diag::err_omp_interchange_permutation_value_repeated)
17135 << PermInt << ExprRange;
17136 continue;
17137 }
17138 Flags[PermInt - 1] = true;
17139
17140 Permutation.push_back(Elt: PermInt - 1);
17141 }
17142
17143 if (Permutation.size() != NumLoops)
17144 return StmtError();
17145 }
17146
17147 // Nothing to transform with trivial permutation.
17148 if (NumLoops <= 1 || llvm::all_of(Range: llvm::enumerate(First&: Permutation), P: [](auto P) {
17149 auto [Idx, Arg] = P;
17150 return Idx == Arg;
17151 }))
17152 return OMPInterchangeDirective::Create(C: Context, StartLoc, EndLoc, Clauses,
17153 NumLoops, AssociatedStmt: AStmt, TransformedStmt: AStmt, PreInits: nullptr);
17154
17155 // Find the affected loops.
17156 SmallVector<Stmt *> LoopStmts(NumLoops, nullptr);
17157 collectLoopStmts(AStmt, LoopStmts);
17158
17159 // Collect pre-init statements on the order before the permuation.
17160 SmallVector<Stmt *> PreInits;
17161 for (auto I : llvm::seq<int>(Size: NumLoops)) {
17162 OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I];
17163
17164 assert(LoopHelper.Counters.size() == 1 &&
17165 "Single-dimensional loop iteration space expected");
17166
17167 addLoopPreInits(Context, LoopHelper, LoopStmt: LoopStmts[I], OriginalInit: OriginalInits[I],
17168 PreInits);
17169 }
17170
17171 SmallVector<VarDecl *> PermutedIndVars(NumLoops);
17172 CaptureVars CopyTransformer(SemaRef);
17173
17174 // Create the permuted loops from the inside to the outside of the
17175 // interchanged loop nest. Body of the innermost new loop is the original
17176 // innermost body.
17177 Stmt *Inner = Body;
17178 for (auto TargetIdx : llvm::reverse(C: llvm::seq<int>(Size: NumLoops))) {
17179 // Get the original loop that belongs to this new position.
17180 uint64_t SourceIdx = Permutation[TargetIdx];
17181 OMPLoopBasedDirective::HelperExprs &SourceHelper = LoopHelpers[SourceIdx];
17182 Stmt *SourceLoopStmt = LoopStmts[SourceIdx];
17183 assert(SourceHelper.Counters.size() == 1 &&
17184 "Single-dimensional loop iteration space expected");
17185 auto *OrigCntVar = cast<DeclRefExpr>(Val: SourceHelper.Counters.front());
17186
17187 // Normalized loop counter variable: From 0 to n-1, always an integer type.
17188 DeclRefExpr *IterVarRef = cast<DeclRefExpr>(Val: SourceHelper.IterationVarRef);
17189 QualType IVTy = IterVarRef->getType();
17190 assert(IVTy->isIntegerType() &&
17191 "Expected the logical iteration counter to be an integer");
17192
17193 std::string OrigVarName = OrigCntVar->getNameInfo().getAsString();
17194 SourceLocation OrigVarLoc = IterVarRef->getExprLoc();
17195
17196 // Make a copy of the NumIterations expression for each use: By the AST
17197 // constraints, every expression object in a DeclContext must be unique.
17198 auto MakeNumIterations = [&CopyTransformer, &SourceHelper]() -> Expr * {
17199 return AssertSuccess(
17200 R: CopyTransformer.TransformExpr(E: SourceHelper.NumIterations));
17201 };
17202
17203 // Iteration variable for the permuted loop. Reuse the one from
17204 // checkOpenMPLoop which will also be used to update the original loop
17205 // variable.
17206 SmallString<64> PermutedCntName(".permuted_");
17207 PermutedCntName.append(Refs: {llvm::utostr(X: TargetIdx), ".iv.", OrigVarName});
17208 auto *PermutedCntDecl = cast<VarDecl>(Val: IterVarRef->getDecl());
17209 PermutedCntDecl->setDeclName(
17210 &SemaRef.PP.getIdentifierTable().get(Name: PermutedCntName));
17211 PermutedIndVars[TargetIdx] = PermutedCntDecl;
17212 auto MakePermutedRef = [this, PermutedCntDecl, IVTy, OrigVarLoc]() {
17213 return buildDeclRefExpr(S&: SemaRef, D: PermutedCntDecl, Ty: IVTy, Loc: OrigVarLoc);
17214 };
17215
17216 // For init-statement:
17217 // \code
17218 // auto .permuted_{target}.iv = 0
17219 // \endcode
17220 ExprResult Zero = SemaRef.ActOnIntegerConstant(Loc: OrigVarLoc, Val: 0);
17221 if (!Zero.isUsable())
17222 return StmtError();
17223 SemaRef.AddInitializerToDecl(dcl: PermutedCntDecl, init: Zero.get(),
17224 /*DirectInit=*/false);
17225 StmtResult InitStmt = new (Context)
17226 DeclStmt(DeclGroupRef(PermutedCntDecl), OrigCntVar->getBeginLoc(),
17227 OrigCntVar->getEndLoc());
17228 if (!InitStmt.isUsable())
17229 return StmtError();
17230
17231 // For cond-expression:
17232 // \code
17233 // .permuted_{target}.iv < MakeNumIterations()
17234 // \endcode
17235 ExprResult CondExpr =
17236 SemaRef.BuildBinOp(S: CurScope, OpLoc: SourceHelper.Cond->getExprLoc(), Opc: BO_LT,
17237 LHSExpr: MakePermutedRef(), RHSExpr: MakeNumIterations());
17238 if (!CondExpr.isUsable())
17239 return StmtError();
17240
17241 // For incr-statement:
17242 // \code
17243 // ++.tile.iv
17244 // \endcode
17245 ExprResult IncrStmt = SemaRef.BuildUnaryOp(
17246 S: CurScope, OpLoc: SourceHelper.Inc->getExprLoc(), Opc: UO_PreInc, Input: MakePermutedRef());
17247 if (!IncrStmt.isUsable())
17248 return StmtError();
17249
17250 SmallVector<Stmt *, 4> BodyParts(SourceHelper.Updates.begin(),
17251 SourceHelper.Updates.end());
17252 if (auto *SourceCXXFor = dyn_cast<CXXForRangeStmt>(Val: SourceLoopStmt))
17253 BodyParts.push_back(Elt: SourceCXXFor->getLoopVarStmt());
17254 BodyParts.push_back(Elt: Inner);
17255 Inner = CompoundStmt::Create(C: Context, Stmts: BodyParts, FPFeatures: FPOptionsOverride(),
17256 LB: Inner->getBeginLoc(), RB: Inner->getEndLoc());
17257 Inner = new (Context) ForStmt(
17258 Context, InitStmt.get(), CondExpr.get(), nullptr, IncrStmt.get(), Inner,
17259 SourceHelper.Init->getBeginLoc(), SourceHelper.Init->getBeginLoc(),
17260 SourceHelper.Inc->getEndLoc());
17261 }
17262
17263 return OMPInterchangeDirective::Create(C: Context, StartLoc, EndLoc, Clauses,
17264 NumLoops, AssociatedStmt: AStmt, TransformedStmt: Inner,
17265 PreInits: buildPreInits(Context, PreInits));
17266}
17267
17268StmtResult
17269SemaOpenMP::ActOnOpenMPFlattenDirective(ArrayRef<OMPClause *> Clauses,
17270 Stmt *AStmt, SourceLocation StartLoc,
17271 SourceLocation EndLoc) {
17272 ASTContext &Context = getASTContext();
17273 DeclContext *CurContext = SemaRef.CurContext;
17274 Scope *CurScope = SemaRef.getCurScope();
17275
17276 // Empty statement should only be possible if there already was an error.
17277 if (!AStmt)
17278 return StmtError();
17279
17280 // flatten without 'depth' clause combines two loops; 'depth(k)' selects k.
17281 unsigned NumLoops = 2;
17282 bool DepthIsDependent = false;
17283 const auto *DepthClause =
17284 OMPExecutableDirective::getSingleClause<OMPDepthClause>(Clauses);
17285 if (DepthClause) {
17286 Expr *DepthExpr = DepthClause->getDepth();
17287 if (DepthExpr && DepthExpr->isInstantiationDependent()) {
17288 DepthIsDependent = true;
17289 } else if (DepthExpr) {
17290 Expr::EvalResult EvalResult;
17291 if (DepthExpr->EvaluateAsInt(Result&: EvalResult, Ctx: Context))
17292 NumLoops = EvalResult.Val.getInt().getLimitedValue(
17293 Limit: std::numeric_limits<unsigned>::max());
17294 }
17295 }
17296
17297 // Count perfectly nested loops with doForAllLoops. When 'depth' is present,
17298 // walk NumLoops iterations to diagnose an insufficient nest. When it is
17299 // omitted, walk one extra loop (3 total) so we can warn that default
17300 // flatten only combines 2 of a deeper nest.
17301 if (!DepthIsDependent) {
17302 unsigned WalkLimit = DepthClause ? NumLoops : 3;
17303 unsigned Found = 0;
17304 bool Enough = OMPLoopBasedDirective::doForAllLoops(
17305 CurStmt: AStmt->IgnoreContainers(), /*TryImperfectlyNestedLoops=*/false,
17306 NumLoops: WalkLimit, Callback: [&](unsigned Cnt, Stmt *S) {
17307 if (!isa<ForStmt>(Val: S) && !isa<CXXForRangeStmt>(Val: S))
17308 return true;
17309 Found = Cnt + 1;
17310 return false;
17311 });
17312 if (DepthClause && !Enough) {
17313 Diag(Loc: AStmt->getBeginLoc(), DiagID: diag::err_omp_not_for)
17314 << /*expected N for loops form=*/1
17315 << getOpenMPDirectiveName(D: OMPD_flatten) << NumLoops << (Found > 0)
17316 << Found;
17317 return StmtError();
17318 }
17319 if (!DepthClause && Found >= 3) {
17320 Diag(Loc: StartLoc, DiagID: diag::warn_omp_flatten_omitted_depth);
17321 if (SemaRef.getLangOpts().OpenMP >= 61)
17322 Diag(Loc: StartLoc, DiagID: diag::note_omp_flatten_insert_depth)
17323 << FixItHint::CreateInsertion(InsertionLoc: EndLoc, Code: " depth(2)");
17324 }
17325 }
17326
17327 // Defer when 'depth' is instantiation-dependent (concrete k unknown until
17328 // instantiation).
17329 if (DepthIsDependent)
17330 return OMPFlattenDirective::Create(C: Context, StartLoc, EndLoc, Clauses,
17331 NumLoops, AssociatedStmt: AStmt, TransformedStmt: nullptr, PreInits: nullptr,
17332 Finals: nullptr);
17333
17334 // Verify and diagnose loop nest.
17335 SmallVector<OMPLoopBasedDirective::HelperExprs, 4> LoopHelpers(NumLoops);
17336 Stmt *Body = nullptr;
17337 SmallVector<SmallVector<Stmt *>, 4> OriginalInits;
17338 if (!checkTransformableLoopNest(Kind: OMPD_flatten, AStmt, NumLoops, LoopHelpers,
17339 Body, OriginalInits))
17340 return StmtError();
17341
17342 // Delay flattening to when template is completely instantiated.
17343 if (CurContext->isDependentContext())
17344 return OMPFlattenDirective::Create(C: Context, StartLoc, EndLoc, Clauses,
17345 NumLoops, AssociatedStmt: AStmt, TransformedStmt: nullptr, PreInits: nullptr,
17346 Finals: nullptr);
17347
17348 assert(LoopHelpers.size() == NumLoops &&
17349 "Expecting loop iteration space dimensionality to match number of "
17350 "affected loops");
17351 assert(OriginalInits.size() == NumLoops &&
17352 "Expecting loop iteration space dimensionality to match number of "
17353 "affected loops");
17354
17355 // Find the affected loops.
17356 SmallVector<Stmt *> LoopStmts(NumLoops, nullptr);
17357 collectLoopStmts(AStmt, LoopStmts);
17358
17359 // Collect pre-init statements in outer-to-inner order.
17360 SmallVector<Stmt *> PreInits;
17361 for (auto I : llvm::seq<unsigned>(Size: NumLoops)) {
17362 OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I];
17363 assert(LoopHelper.Counters.size() == 1 &&
17364 "Single-dimensional loop iteration space expected");
17365 addLoopPreInits(Context, LoopHelper, LoopStmt: LoopStmts[I], OriginalInit: OriginalInits[I],
17366 PreInits);
17367 }
17368
17369 CaptureVars CopyTransformer(SemaRef);
17370 auto MakeNumIterations = [&CopyTransformer,
17371 &LoopHelpers](unsigned I) -> Expr * {
17372 return AssertSuccess(
17373 R: CopyTransformer.TransformExpr(E: LoopHelpers[I].NumIterations));
17374 };
17375
17376 OMPLoopBasedDirective::HelperExprs &OutermostHelper = LoopHelpers[0];
17377 auto *OutermostCntVar = cast<DeclRefExpr>(Val: OutermostHelper.Counters.front());
17378 SourceLocation OrigVarLoc = OutermostCntVar->getExprLoc();
17379 SourceLocation OrigVarLocBegin = OutermostCntVar->getBeginLoc();
17380 SourceLocation OrigVarLocEnd = OutermostCntVar->getEndLoc();
17381 SourceLocation CondLoc = OutermostHelper.Cond->getExprLoc();
17382
17383 // Product of trip counts; mirror 'collapse' IV-width selection to avoid
17384 // overflow when several counts are multiplied.
17385 auto BuildTripCount = [&](unsigned Bits) -> ExprResult {
17386 ExprResult Product;
17387 for (unsigned I = 0; I < NumLoops; ++I) {
17388 ExprResult N = widenIterationCount(Bits, E: MakeNumIterations(I), SemaRef);
17389 if (!N.isUsable())
17390 return ExprError();
17391 if (I == 0)
17392 Product = N;
17393 else
17394 Product = SemaRef.BuildBinOp(S: CurScope, OpLoc: CondLoc, Opc: BO_Mul, LHSExpr: Product.get(),
17395 RHSExpr: N.get());
17396 if (!Product.isUsable())
17397 return ExprError();
17398 }
17399 return Product;
17400 };
17401
17402 bool AllCountsLessThan32Bits =
17403 llvm::all_of(Range: llvm::seq<unsigned>(Size: NumLoops), P: [&](unsigned I) {
17404 return Context.getTypeSize(T: LoopHelpers[I].NumIterations->getType()) <
17405 32;
17406 });
17407
17408 ExprResult TripCount;
17409 if (AllCountsLessThan32Bits || NumLoops == 1) {
17410 TripCount = BuildTripCount(/*Bits=*/32);
17411 } else {
17412 ExprResult TripCount64 = BuildTripCount(/*Bits=*/64);
17413 if (!TripCount64.isUsable())
17414 return StmtError();
17415 TripCount = TripCount64;
17416 if (TripCount64.get()->isIntegerConstantExpr(Ctx: Context)) {
17417 ExprResult TripCount32 = BuildTripCount(/*Bits=*/32);
17418 if (TripCount32.isUsable() &&
17419 Context.getTypeSize(T: TripCount32.get()->getType()) == 32 &&
17420 fitsInto(
17421 /*Bits=*/32,
17422 Signed: TripCount32.get()->getType()->hasSignedIntegerRepresentation(),
17423 E: TripCount64.get(), SemaRef))
17424 TripCount = TripCount32;
17425 }
17426 }
17427 if (!TripCount.isUsable())
17428 return StmtError();
17429
17430 QualType IVTy = TripCount.get()->getType();
17431 uint64_t IVWidth = Context.getTypeSize(T: IVTy);
17432
17433 // Build a condition that is true if the outermost \p Count loops all have at
17434 // least one iteration.
17435 auto BuildHasIterations = [&](unsigned Count) -> ExprResult {
17436 ExprResult Result;
17437 for (unsigned I = 0; I < Count; ++I) {
17438 ExprResult LoopPreCond =
17439 CopyTransformer.TransformExpr(E: LoopHelpers[I].PreCond);
17440 if (!LoopPreCond.isUsable())
17441 return ExprError();
17442 if (I == 0)
17443 Result = LoopPreCond;
17444 else
17445 Result = SemaRef.BuildBinOp(S: CurScope, OpLoc: CondLoc, Opc: BO_LAnd, LHSExpr: Result.get(),
17446 RHSExpr: LoopPreCond.get());
17447 if (!Result.isUsable())
17448 return ExprError();
17449 }
17450 return Result;
17451 };
17452
17453 // NumIterations may wrap or overflow when an empty loop has extreme runtime
17454 // bounds. Test whether every original loop has at least one iteration before
17455 // evaluating their product.
17456 ExprResult HasIterations = BuildHasIterations(NumLoops);
17457 if (!HasIterations.isUsable())
17458 return StmtError();
17459 Expr *ZeroTripCount = IntegerLiteral::Create(
17460 C: Context, V: llvm::APInt::getZero(numBits: IVWidth), type: IVTy, l: CondLoc);
17461 TripCount = SemaRef.ActOnConditionalOp(QuestionLoc: CondLoc, ColonLoc: CondLoc, CondExpr: HasIterations.get(),
17462 LHSExpr: TripCount.get(), RHSExpr: ZeroTripCount);
17463 if (!TripCount.isUsable())
17464 return StmtError();
17465
17466 auto MakeNumIterationsInIVTy = [&](unsigned I) -> Expr * {
17467 return AssertSuccess(R: SemaRef.PerformImplicitConversion(
17468 From: MakeNumIterations(I), ToType: IVTy, Action: AssignmentAction::Converting,
17469 /*AllowExplicit=*/true));
17470 };
17471
17472 // Divisors in index recovery use (N == 0 ? 1 : N) so a zero trip count does
17473 // not warn.
17474 auto MakeDivisorInIVTy = [&](unsigned I) -> Expr * {
17475 Expr *N = MakeNumIterationsInIVTy(I);
17476 Expr *NCmp = MakeNumIterationsInIVTy(I);
17477 auto MakeCst = [&](uint64_t V) -> Expr * {
17478 return IntegerLiteral::Create(C: Context, V: llvm::APInt(IVWidth, V), type: IVTy,
17479 l: CondLoc);
17480 };
17481 ExprResult IsZero =
17482 SemaRef.BuildBinOp(S: CurScope, OpLoc: CondLoc, Opc: BO_EQ, LHSExpr: NCmp, RHSExpr: MakeCst(0));
17483 if (!IsZero.isUsable())
17484 return N;
17485 return AssertSuccess(R: SemaRef.ActOnConditionalOp(
17486 QuestionLoc: CondLoc, ColonLoc: CondLoc, CondExpr: IsZero.get(), LHSExpr: MakeCst(1), RHSExpr: N));
17487 };
17488
17489 // \code{.cpp}
17490 // for (auto .flatten.iv = 0; .flatten.iv < n0 * n1 * ...; ++.flatten.iv) {
17491 // .flatten.iv.0 = .flatten.iv / (n1 * ...);
17492 // i0 = ...; // Updates[0]
17493 // .flatten.iv.1 = (.flatten.iv / ...) % n1;
17494 // i1 = ...; // Updates[1]
17495 // ...
17496 // body(i0, i1, ...);
17497 // }
17498 // \endcode
17499 SmallString<64> FlattenedIVName(".flatten.iv");
17500 VarDecl *FlattenedIVDecl = buildVarDecl(SemaRef, Loc: {}, Type: IVTy, Name: FlattenedIVName,
17501 Attrs: nullptr, OrigRef: OutermostCntVar);
17502 auto MakeFlattenedRef = [&SemaRef = this->SemaRef, FlattenedIVDecl, IVTy,
17503 OrigVarLoc]() {
17504 return buildDeclRefExpr(S&: SemaRef, D: FlattenedIVDecl, Ty: IVTy, Loc: OrigVarLoc);
17505 };
17506
17507 // For init-statement:
17508 // \code{.cpp}
17509 // auto .flatten.iv = 0;
17510 // \endcode
17511 auto *Zero = IntegerLiteral::Create(C: Context, V: llvm::APInt::getZero(numBits: IVWidth),
17512 type: IVTy, l: OrigVarLoc);
17513 SemaRef.AddInitializerToDecl(dcl: FlattenedIVDecl, init: Zero, /*DirectInit=*/false);
17514 StmtResult Init = new (Context)
17515 DeclStmt(DeclGroupRef(FlattenedIVDecl), OrigVarLocBegin, OrigVarLocEnd);
17516 if (!Init.isUsable())
17517 return StmtError();
17518
17519 // For cond-expression:
17520 // \code{.cpp}
17521 // .flatten.iv < n0 * n1 * ... * n(k-1)
17522 // \endcode
17523 ExprResult Cond = SemaRef.BuildBinOp(S: CurScope, OpLoc: CondLoc, Opc: BO_LT,
17524 LHSExpr: MakeFlattenedRef(), RHSExpr: TripCount.get());
17525 if (!Cond.isUsable())
17526 return StmtError();
17527
17528 // For incr-statement:
17529 // \code{.cpp}
17530 // ++.flatten.iv
17531 // \endcode
17532 ExprResult Incr =
17533 SemaRef.BuildUnaryOp(S: CurScope, OpLoc: OutermostHelper.Inc->getExprLoc(),
17534 Opc: UO_PreInc, Input: MakeFlattenedRef());
17535 if (!Incr.isUsable())
17536 return StmtError();
17537
17538 // Recover each logical iteration counter via mixed-radix div/mod; reuse the
17539 // iteration variables from checkOpenMPLoop so Updates compute user counters.
17540 SmallVector<Stmt *, 8> BodyStmts;
17541 for (unsigned I = 0; I < NumLoops; ++I) {
17542 OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I];
17543 auto *IVRef = cast<DeclRefExpr>(Val: LoopHelper.IterationVarRef);
17544 auto *IVDecl = cast<VarDecl>(Val: IVRef->getDecl());
17545 std::string IVName = (".flatten.iv." + llvm::Twine(I)).str();
17546 IVDecl->setDeclName(&SemaRef.PP.getIdentifierTable().get(Name: IVName));
17547
17548 ExprResult Value = MakeFlattenedRef();
17549 if (I + 1 < NumLoops) {
17550 ExprResult Divisor = MakeDivisorInIVTy(I + 1);
17551 for (unsigned J = I + 2; J < NumLoops; ++J) {
17552 Divisor = SemaRef.BuildBinOp(S: CurScope, OpLoc: OrigVarLoc, Opc: BO_Mul,
17553 LHSExpr: Divisor.get(), RHSExpr: MakeDivisorInIVTy(J));
17554 if (!Divisor.isUsable())
17555 return StmtError();
17556 }
17557 Value = SemaRef.BuildBinOp(S: CurScope, OpLoc: OrigVarLoc, Opc: BO_Div, LHSExpr: Value.get(),
17558 RHSExpr: Divisor.get());
17559 if (!Value.isUsable())
17560 return StmtError();
17561 }
17562 if (I > 0) {
17563 Value = SemaRef.BuildBinOp(S: CurScope, OpLoc: OrigVarLoc, Opc: BO_Rem, LHSExpr: Value.get(),
17564 RHSExpr: MakeDivisorInIVTy(I));
17565 if (!Value.isUsable())
17566 return StmtError();
17567 }
17568
17569 SemaRef.AddInitializerToDecl(dcl: IVDecl, init: Value.get(), /*DirectInit=*/false);
17570 StmtResult IVStmt = new (Context)
17571 DeclStmt(DeclGroupRef(IVDecl), OrigVarLocBegin, OrigVarLocEnd);
17572 if (!IVStmt.isUsable())
17573 return StmtError();
17574
17575 BodyStmts.push_back(Elt: IVStmt.get());
17576 llvm::append_range(C&: BodyStmts, R&: LoopHelper.Updates);
17577 if (auto *CXXFor = dyn_cast<CXXForRangeStmt>(Val: LoopStmts[I]))
17578 BodyStmts.push_back(Elt: CXXFor->getLoopVarStmt());
17579 }
17580 BodyStmts.push_back(Elt: Body);
17581 auto *FlattenedBody =
17582 CompoundStmt::Create(C: Context, Stmts: BodyStmts, FPFeatures: FPOptionsOverride(),
17583 LB: Body->getBeginLoc(), RB: Body->getEndLoc());
17584
17585 auto *FlattenedFor = new (Context) ForStmt(
17586 Context, Init.get(), Cond.get(), nullptr, Incr.get(), FlattenedBody,
17587 OutermostHelper.Init->getBeginLoc(), OutermostHelper.Init->getBeginLoc(),
17588 OutermostHelper.Inc->getEndLoc());
17589
17590 // A counter only reaches its final value if its own loop and all enclosing
17591 // loops execute at least one iteration; otherwise it keeps the value assigned
17592 // by the pre-inits. Guarding also avoids evaluating 'start + n * step' for an
17593 // empty loop, whose trip count may have wrapped.
17594 SmallVector<Stmt *, 4> Finals;
17595 for (unsigned I = 0; I < NumLoops; ++I) {
17596 assert(LoopHelpers[I].Finals.size() == 1 &&
17597 "Single-dimensional loop iteration space expected");
17598 ExprResult Final =
17599 CopyTransformer.TransformExpr(E: LoopHelpers[I].Finals.front());
17600 if (!Final.isUsable())
17601 return StmtError();
17602 ExprResult FinalCond = BuildHasIterations(/*Count=*/I + 1);
17603 if (!FinalCond.isUsable())
17604 return StmtError();
17605 Finals.push_back(Elt: IfStmt::Create(Ctx: Context, IL: CondLoc, Kind: IfStatementKind::Ordinary,
17606 Init: nullptr, Var: nullptr, Cond: FinalCond.get(), LPL: CondLoc,
17607 RPL: CondLoc, Then: Final.get(), EL: SourceLocation(),
17608 Else: nullptr));
17609 }
17610 Stmt *FinalsStmt = CompoundStmt::Create(C: Context, Stmts: Finals, FPFeatures: FPOptionsOverride(),
17611 LB: FlattenedFor->getBeginLoc(),
17612 RB: FlattenedFor->getEndLoc());
17613
17614 return OMPFlattenDirective::Create(
17615 C: Context, StartLoc, EndLoc, Clauses, NumLoops, AssociatedStmt: AStmt, TransformedStmt: FlattenedFor,
17616 PreInits: buildPreInits(Context, PreInits), Finals: FinalsStmt);
17617}
17618
17619StmtResult SemaOpenMP::ActOnOpenMPFuseDirective(ArrayRef<OMPClause *> Clauses,
17620 Stmt *AStmt,
17621 SourceLocation StartLoc,
17622 SourceLocation EndLoc) {
17623
17624 ASTContext &Context = getASTContext();
17625 DeclContext *CurrContext = SemaRef.CurContext;
17626 Scope *CurScope = SemaRef.getCurScope();
17627 CaptureVars CopyTransformer(SemaRef);
17628
17629 // Ensure the structured block is not empty
17630 if (!AStmt)
17631 return StmtError();
17632
17633 if (const auto *DepthC =
17634 OMPExecutableDirective::getSingleClause<OMPDepthClause>(Clauses)) {
17635 Diag(Loc: DepthC->getBeginLoc(), DiagID: diag::err_omp_clause_not_supported_yet)
17636 << "depth" << getOpenMPDirectiveName(D: OMPD_fuse);
17637 return StmtError();
17638 }
17639
17640 // Defer transformation in dependent contexts
17641 // The NumLoopNests argument is set to a placeholder 1 (even though
17642 // using looprange fuse could yield up to 3 top level loop nests)
17643 // because a dependent context could prevent determining its true value
17644 if (CurrContext->isDependentContext())
17645 return OMPFuseDirective::Create(C: Context, StartLoc, EndLoc, Clauses,
17646 /* NumLoops */ NumGeneratedTopLevelLoops: 1, AssociatedStmt: AStmt, TransformedStmt: nullptr, PreInits: nullptr);
17647
17648 // Validate that the potential loop sequence is transformable for fusion
17649 // Also collect the HelperExprs, Loop Stmts, Inits, and Number of loops
17650 LoopSequenceAnalysis SeqAnalysis;
17651 if (!checkTransformableLoopSequence(Kind: OMPD_fuse, AStmt, SeqAnalysis, Context))
17652 return StmtError();
17653
17654 // SeqAnalysis.LoopSeqSize exists mostly to handle dependent contexts,
17655 // otherwise it must be the same as SeqAnalysis.Loops.size().
17656 assert(SeqAnalysis.LoopSeqSize == SeqAnalysis.Loops.size() &&
17657 "Inconsistent size of the loop sequence and the number of loops "
17658 "found in the sequence");
17659
17660 // Handle clauses, which can be any of the following: [looprange, apply]
17661 const auto *LRC =
17662 OMPExecutableDirective::getSingleClause<OMPLoopRangeClause>(Clauses);
17663
17664 // The clause arguments are invalidated if any error arises
17665 // such as non-constant or non-positive arguments
17666 if (LRC && (!LRC->getFirst() || !LRC->getCount()))
17667 return StmtError();
17668
17669 // Delayed semantic check of LoopRange constraint
17670 // Evaluates the loop range arguments and returns the first and count values
17671 auto EvaluateLoopRangeArguments = [&Context](Expr *First, Expr *Count,
17672 uint64_t &FirstVal,
17673 uint64_t &CountVal) {
17674 llvm::APSInt FirstInt = First->EvaluateKnownConstInt(Ctx: Context);
17675 llvm::APSInt CountInt = Count->EvaluateKnownConstInt(Ctx: Context);
17676 FirstVal = FirstInt.getLimitedValue();
17677 CountVal = CountInt.getLimitedValue();
17678 };
17679
17680 // OpenMP [6.0, Restrictions]
17681 // first + count - 1 must not evaluate to a value greater than the
17682 // loop sequence length of the associated canonical loop sequence.
17683 auto ValidLoopRange = [](uint64_t FirstVal, uint64_t CountVal,
17684 unsigned NumLoops) -> bool {
17685 return FirstVal + CountVal - 1 <= NumLoops;
17686 };
17687 uint64_t FirstVal = 1, CountVal = 0, LastVal = SeqAnalysis.LoopSeqSize;
17688
17689 // Validates the loop range after evaluating the semantic information
17690 // and ensures that the range is valid for the given loop sequence size.
17691 // Expressions are evaluated at compile time to obtain constant values.
17692 if (LRC) {
17693 EvaluateLoopRangeArguments(LRC->getFirst(), LRC->getCount(), FirstVal,
17694 CountVal);
17695 if (CountVal == 1)
17696 SemaRef.Diag(Loc: LRC->getCountLoc(), DiagID: diag::warn_omp_redundant_fusion)
17697 << getOpenMPDirectiveName(D: OMPD_fuse);
17698
17699 if (!ValidLoopRange(FirstVal, CountVal, SeqAnalysis.LoopSeqSize)) {
17700 SemaRef.Diag(Loc: LRC->getFirstLoc(), DiagID: diag::err_omp_invalid_looprange)
17701 << getOpenMPDirectiveName(D: OMPD_fuse) << FirstVal
17702 << (FirstVal + CountVal - 1) << SeqAnalysis.LoopSeqSize;
17703 return StmtError();
17704 }
17705
17706 LastVal = FirstVal + CountVal - 1;
17707 }
17708
17709 // Complete fusion generates a single canonical loop nest
17710 // However looprange clause may generate several loop nests
17711 unsigned NumGeneratedTopLevelLoops =
17712 LRC ? SeqAnalysis.LoopSeqSize - CountVal + 1 : 1;
17713
17714 // Emit a warning for redundant loop fusion when the sequence contains only
17715 // one loop.
17716 if (SeqAnalysis.LoopSeqSize == 1)
17717 SemaRef.Diag(Loc: AStmt->getBeginLoc(), DiagID: diag::warn_omp_redundant_fusion)
17718 << getOpenMPDirectiveName(D: OMPD_fuse);
17719
17720 // Select the type with the largest bit width among all induction variables
17721 QualType IVType =
17722 SeqAnalysis.Loops[FirstVal - 1].HelperExprs.IterationVarRef->getType();
17723 for (unsigned I : llvm::seq<unsigned>(Begin: FirstVal, End: LastVal)) {
17724 QualType CurrentIVType =
17725 SeqAnalysis.Loops[I].HelperExprs.IterationVarRef->getType();
17726 if (Context.getTypeSize(T: CurrentIVType) > Context.getTypeSize(T: IVType)) {
17727 IVType = CurrentIVType;
17728 }
17729 }
17730 uint64_t IVBitWidth = Context.getIntWidth(T: IVType);
17731
17732 // Create pre-init declarations for all loops lower bounds, upper bounds,
17733 // strides and num-iterations for every top level loop in the fusion
17734 SmallVector<VarDecl *, 4> LBVarDecls;
17735 SmallVector<VarDecl *, 4> STVarDecls;
17736 SmallVector<VarDecl *, 4> NIVarDecls;
17737 SmallVector<VarDecl *, 4> UBVarDecls;
17738 SmallVector<VarDecl *, 4> IVVarDecls;
17739
17740 // Helper lambda to create variables for bounds, strides, and other
17741 // expressions. Generates both the variable declaration and the corresponding
17742 // initialization statement.
17743 auto CreateHelperVarAndStmt =
17744 [&, &SemaRef = SemaRef](Expr *ExprToCopy, const std::string &BaseName,
17745 unsigned I, bool NeedsNewVD = false) {
17746 Expr *TransformedExpr =
17747 AssertSuccess(R: CopyTransformer.TransformExpr(E: ExprToCopy));
17748 if (!TransformedExpr)
17749 return std::pair<VarDecl *, StmtResult>(nullptr, StmtError());
17750
17751 auto Name = (Twine(".omp.") + BaseName + std::to_string(val: I)).str();
17752
17753 VarDecl *VD;
17754 if (NeedsNewVD) {
17755 VD = buildVarDecl(SemaRef, Loc: SourceLocation(), Type: IVType, Name);
17756 SemaRef.AddInitializerToDecl(dcl: VD, init: TransformedExpr, DirectInit: false);
17757 } else {
17758 // Create a unique variable name
17759 DeclRefExpr *DRE = cast<DeclRefExpr>(Val: TransformedExpr);
17760 VD = cast<VarDecl>(Val: DRE->getDecl());
17761 VD->setDeclName(&SemaRef.PP.getIdentifierTable().get(Name));
17762 }
17763 // Create the corresponding declaration statement
17764 StmtResult DeclStmt = new (Context) class DeclStmt(
17765 DeclGroupRef(VD), SourceLocation(), SourceLocation());
17766 return std::make_pair(x&: VD, y&: DeclStmt);
17767 };
17768
17769 // PreInits hold a sequence of variable declarations that must be executed
17770 // before the fused loop begins. These include bounds, strides, and other
17771 // helper variables required for the transformation. Other loop transforms
17772 // also contain their own preinits
17773 SmallVector<Stmt *> PreInits;
17774
17775 // Update the general preinits using the preinits generated by loop sequence
17776 // generating loop transformations. These preinits differ slightly from
17777 // single-loop transformation preinits, as they can be detached from a
17778 // specific loop inside multiple generated loop nests. This happens
17779 // because certain helper variables, like '.omp.fuse.max', are introduced to
17780 // handle fused iteration spaces and may not be directly tied to a single
17781 // original loop. The preinit structure must ensure that hidden variables
17782 // like '.omp.fuse.max' are still properly handled.
17783 // Transformations that apply this concept: Loopranged Fuse, Split
17784 llvm::append_range(C&: PreInits, R&: SeqAnalysis.LoopSequencePreInits);
17785
17786 // Process each single loop to generate and collect declarations
17787 // and statements for all helper expressions related to
17788 // particular single loop nests
17789
17790 // Also In the case of the fused loops, we keep track of their original
17791 // inits by appending them to their preinits statement, and in the case of
17792 // transformations, also append their preinits (which contain the original
17793 // loop initialization statement or other statements)
17794
17795 // Firstly we need to set TransformIndex to match the begining of the
17796 // looprange section
17797 unsigned int TransformIndex = 0;
17798 for (unsigned I : llvm::seq<unsigned>(Size: FirstVal - 1)) {
17799 if (SeqAnalysis.Loops[I].isLoopTransformation())
17800 ++TransformIndex;
17801 }
17802
17803 for (unsigned int I = FirstVal - 1, J = 0; I < LastVal; ++I, ++J) {
17804 if (SeqAnalysis.Loops[I].isRegularLoop()) {
17805 addLoopPreInits(Context, LoopHelper&: SeqAnalysis.Loops[I].HelperExprs,
17806 LoopStmt: SeqAnalysis.Loops[I].TheForStmt,
17807 OriginalInit: SeqAnalysis.Loops[I].OriginalInits, PreInits);
17808 } else if (SeqAnalysis.Loops[I].isLoopTransformation()) {
17809 // For transformed loops, insert both pre-inits and original inits.
17810 // Order matters: pre-inits may define variables used in the original
17811 // inits such as upper bounds...
17812 SmallVector<Stmt *> &TransformPreInit =
17813 SeqAnalysis.Loops[TransformIndex++].TransformsPreInits;
17814 llvm::append_range(C&: PreInits, R&: TransformPreInit);
17815
17816 addLoopPreInits(Context, LoopHelper&: SeqAnalysis.Loops[I].HelperExprs,
17817 LoopStmt: SeqAnalysis.Loops[I].TheForStmt,
17818 OriginalInit: SeqAnalysis.Loops[I].OriginalInits, PreInits);
17819 }
17820 auto [UBVD, UBDStmt] =
17821 CreateHelperVarAndStmt(SeqAnalysis.Loops[I].HelperExprs.UB, "ub", J);
17822 auto [LBVD, LBDStmt] =
17823 CreateHelperVarAndStmt(SeqAnalysis.Loops[I].HelperExprs.LB, "lb", J);
17824 auto [STVD, STDStmt] =
17825 CreateHelperVarAndStmt(SeqAnalysis.Loops[I].HelperExprs.ST, "st", J);
17826 auto [NIVD, NIDStmt] = CreateHelperVarAndStmt(
17827 SeqAnalysis.Loops[I].HelperExprs.NumIterations, "ni", J, true);
17828 auto [IVVD, IVDStmt] = CreateHelperVarAndStmt(
17829 SeqAnalysis.Loops[I].HelperExprs.IterationVarRef, "iv", J);
17830
17831 assert(LBVD && STVD && NIVD && IVVD &&
17832 "OpenMP Fuse Helper variables creation failed");
17833
17834 UBVarDecls.push_back(Elt: UBVD);
17835 LBVarDecls.push_back(Elt: LBVD);
17836 STVarDecls.push_back(Elt: STVD);
17837 NIVarDecls.push_back(Elt: NIVD);
17838 IVVarDecls.push_back(Elt: IVVD);
17839
17840 PreInits.push_back(Elt: LBDStmt.get());
17841 PreInits.push_back(Elt: STDStmt.get());
17842 PreInits.push_back(Elt: NIDStmt.get());
17843 PreInits.push_back(Elt: IVDStmt.get());
17844 }
17845
17846 auto MakeVarDeclRef = [&SemaRef = this->SemaRef](VarDecl *VD) {
17847 return buildDeclRefExpr(S&: SemaRef, D: VD, Ty: VD->getType(), Loc: VD->getLocation(),
17848 RefersToCapture: false);
17849 };
17850
17851 // Following up the creation of the final fused loop will be performed
17852 // which has the following shape (considering the selected loops):
17853 //
17854 // for (fuse.index = 0; fuse.index < max(ni0, ni1..., nik); ++fuse.index) {
17855 // if (fuse.index < ni0){
17856 // iv0 = lb0 + st0 * fuse.index;
17857 // original.index0 = iv0
17858 // body(0);
17859 // }
17860 // if (fuse.index < ni1){
17861 // iv1 = lb1 + st1 * fuse.index;
17862 // original.index1 = iv1
17863 // body(1);
17864 // }
17865 //
17866 // ...
17867 //
17868 // if (fuse.index < nik){
17869 // ivk = lbk + stk * fuse.index;
17870 // original.indexk = ivk
17871 // body(k); Expr *InitVal = IntegerLiteral::Create(Context,
17872 // llvm::APInt(IVWidth, 0),
17873 // }
17874
17875 // 1. Create the initialized fuse index
17876 StringRef IndexName = ".omp.fuse.index";
17877 Expr *InitVal = IntegerLiteral::Create(C: Context, V: llvm::APInt(IVBitWidth, 0),
17878 type: IVType, l: SourceLocation());
17879 VarDecl *IndexDecl =
17880 buildVarDecl(SemaRef, Loc: {}, Type: IVType, Name: IndexName, Attrs: nullptr, OrigRef: nullptr);
17881 SemaRef.AddInitializerToDecl(dcl: IndexDecl, init: InitVal, DirectInit: false);
17882 StmtResult InitStmt = new (Context)
17883 DeclStmt(DeclGroupRef(IndexDecl), SourceLocation(), SourceLocation());
17884
17885 if (!InitStmt.isUsable())
17886 return StmtError();
17887
17888 auto MakeIVRef = [&SemaRef = this->SemaRef, IndexDecl, IVType,
17889 Loc = InitVal->getExprLoc()]() {
17890 return buildDeclRefExpr(S&: SemaRef, D: IndexDecl, Ty: IVType, Loc, RefersToCapture: false);
17891 };
17892
17893 // 2. Iteratively compute the max number of logical iterations Max(NI_1, NI_2,
17894 // ..., NI_k)
17895 //
17896 // This loop accumulates the maximum value across multiple expressions,
17897 // ensuring each step constructs a unique AST node for correctness. By using
17898 // intermediate temporary variables and conditional operators, we maintain
17899 // distinct nodes and avoid duplicating subtrees, For instance, max(a,b,c):
17900 // omp.temp0 = max(a, b)
17901 // omp.temp1 = max(omp.temp0, c)
17902 // omp.fuse.max = max(omp.temp1, omp.temp0)
17903
17904 ExprResult MaxExpr;
17905 // I is the range of loops in the sequence that we fuse.
17906 for (unsigned I = FirstVal - 1, J = 0; I < LastVal; ++I, ++J) {
17907 DeclRefExpr *NIRef = MakeVarDeclRef(NIVarDecls[J]);
17908 QualType NITy = NIRef->getType();
17909
17910 if (MaxExpr.isUnset()) {
17911 // Initialize MaxExpr with the first NI expression
17912 MaxExpr = NIRef;
17913 } else {
17914 // Create a new acummulator variable t_i = MaxExpr
17915 std::string TempName = (Twine(".omp.temp.") + Twine(J)).str();
17916 VarDecl *TempDecl =
17917 buildVarDecl(SemaRef, Loc: {}, Type: NITy, Name: TempName, Attrs: nullptr, OrigRef: nullptr);
17918 TempDecl->setInit(MaxExpr.get());
17919 DeclRefExpr *TempRef =
17920 buildDeclRefExpr(S&: SemaRef, D: TempDecl, Ty: NITy, Loc: SourceLocation(), RefersToCapture: false);
17921 DeclRefExpr *TempRef2 =
17922 buildDeclRefExpr(S&: SemaRef, D: TempDecl, Ty: NITy, Loc: SourceLocation(), RefersToCapture: false);
17923 // Add a DeclStmt to PreInits to ensure the variable is declared.
17924 StmtResult TempStmt = new (Context)
17925 DeclStmt(DeclGroupRef(TempDecl), SourceLocation(), SourceLocation());
17926
17927 if (!TempStmt.isUsable())
17928 return StmtError();
17929 PreInits.push_back(Elt: TempStmt.get());
17930
17931 // Build MaxExpr <-(MaxExpr > NIRef ? MaxExpr : NIRef)
17932 ExprResult Comparison =
17933 SemaRef.BuildBinOp(S: nullptr, OpLoc: SourceLocation(), Opc: BO_GT, LHSExpr: TempRef, RHSExpr: NIRef);
17934 // Handle any errors in Comparison creation
17935 if (!Comparison.isUsable())
17936 return StmtError();
17937
17938 DeclRefExpr *NIRef2 = MakeVarDeclRef(NIVarDecls[J]);
17939 // Update MaxExpr using a conditional expression to hold the max value
17940 MaxExpr = new (Context) ConditionalOperator(
17941 Comparison.get(), SourceLocation(), TempRef2, SourceLocation(),
17942 NIRef2->getExprStmt(), NITy, VK_LValue, OK_Ordinary);
17943
17944 if (!MaxExpr.isUsable())
17945 return StmtError();
17946 }
17947 }
17948 if (!MaxExpr.isUsable())
17949 return StmtError();
17950
17951 // 3. Declare the max variable
17952 const std::string MaxName = Twine(".omp.fuse.max").str();
17953 VarDecl *MaxDecl =
17954 buildVarDecl(SemaRef, Loc: {}, Type: IVType, Name: MaxName, Attrs: nullptr, OrigRef: nullptr);
17955 MaxDecl->setInit(MaxExpr.get());
17956 DeclRefExpr *MaxRef = buildDeclRefExpr(S&: SemaRef, D: MaxDecl, Ty: IVType, Loc: {}, RefersToCapture: false);
17957 StmtResult MaxStmt = new (Context)
17958 DeclStmt(DeclGroupRef(MaxDecl), SourceLocation(), SourceLocation());
17959
17960 if (MaxStmt.isInvalid())
17961 return StmtError();
17962 PreInits.push_back(Elt: MaxStmt.get());
17963
17964 // 4. Create condition Expr: index < n_max
17965 ExprResult CondExpr = SemaRef.BuildBinOp(S: CurScope, OpLoc: SourceLocation(), Opc: BO_LT,
17966 LHSExpr: MakeIVRef(), RHSExpr: MaxRef);
17967 if (!CondExpr.isUsable())
17968 return StmtError();
17969
17970 // 5. Increment Expr: ++index
17971 ExprResult IncrExpr =
17972 SemaRef.BuildUnaryOp(S: CurScope, OpLoc: SourceLocation(), Opc: UO_PreInc, Input: MakeIVRef());
17973 if (!IncrExpr.isUsable())
17974 return StmtError();
17975
17976 // 6. Build the Fused Loop Body
17977 // The final fused loop iterates over the maximum logical range. Inside the
17978 // loop, each original loop's index is calculated dynamically, and its body
17979 // is executed conditionally.
17980 //
17981 // Each sub-loop's body is guarded by a conditional statement to ensure
17982 // it executes only within its logical iteration range:
17983 //
17984 // if (fuse.index < ni_k){
17985 // iv_k = lb_k + st_k * fuse.index;
17986 // original.index = iv_k
17987 // body(k);
17988 // }
17989
17990 CompoundStmt *FusedBody = nullptr;
17991 SmallVector<Stmt *, 4> FusedBodyStmts;
17992 for (unsigned I = FirstVal - 1, J = 0; I < LastVal; ++I, ++J) {
17993 // Assingment of the original sub-loop index to compute the logical index
17994 // IV_k = LB_k + omp.fuse.index * ST_k
17995 ExprResult IdxExpr =
17996 SemaRef.BuildBinOp(S: CurScope, OpLoc: SourceLocation(), Opc: BO_Mul,
17997 LHSExpr: MakeVarDeclRef(STVarDecls[J]), RHSExpr: MakeIVRef());
17998 if (!IdxExpr.isUsable())
17999 return StmtError();
18000 IdxExpr = SemaRef.BuildBinOp(S: CurScope, OpLoc: SourceLocation(), Opc: BO_Add,
18001 LHSExpr: MakeVarDeclRef(LBVarDecls[J]), RHSExpr: IdxExpr.get());
18002
18003 if (!IdxExpr.isUsable())
18004 return StmtError();
18005 IdxExpr = SemaRef.BuildBinOp(S: CurScope, OpLoc: SourceLocation(), Opc: BO_Assign,
18006 LHSExpr: MakeVarDeclRef(IVVarDecls[J]), RHSExpr: IdxExpr.get());
18007 if (!IdxExpr.isUsable())
18008 return StmtError();
18009
18010 // Update the original i_k = IV_k
18011 SmallVector<Stmt *, 4> BodyStmts;
18012 BodyStmts.push_back(Elt: IdxExpr.get());
18013 llvm::append_range(C&: BodyStmts, R&: SeqAnalysis.Loops[I].HelperExprs.Updates);
18014
18015 // If the loop is a CXXForRangeStmt then the iterator variable is needed
18016 if (auto *SourceCXXFor =
18017 dyn_cast<CXXForRangeStmt>(Val: SeqAnalysis.Loops[I].TheForStmt))
18018 BodyStmts.push_back(Elt: SourceCXXFor->getLoopVarStmt());
18019
18020 Stmt *Body =
18021 (isa<ForStmt>(Val: SeqAnalysis.Loops[I].TheForStmt))
18022 ? cast<ForStmt>(Val: SeqAnalysis.Loops[I].TheForStmt)->getBody()
18023 : cast<CXXForRangeStmt>(Val: SeqAnalysis.Loops[I].TheForStmt)->getBody();
18024 BodyStmts.push_back(Elt: Body);
18025
18026 CompoundStmt *CombinedBody =
18027 CompoundStmt::Create(C: Context, Stmts: BodyStmts, FPFeatures: FPOptionsOverride(),
18028 LB: SourceLocation(), RB: SourceLocation());
18029 ExprResult Condition =
18030 SemaRef.BuildBinOp(S: CurScope, OpLoc: SourceLocation(), Opc: BO_LT, LHSExpr: MakeIVRef(),
18031 RHSExpr: MakeVarDeclRef(NIVarDecls[J]));
18032
18033 if (!Condition.isUsable())
18034 return StmtError();
18035
18036 IfStmt *IfStatement = IfStmt::Create(
18037 Ctx: Context, IL: SourceLocation(), Kind: IfStatementKind::Ordinary, Init: nullptr, Var: nullptr,
18038 Cond: Condition.get(), LPL: SourceLocation(), RPL: SourceLocation(), Then: CombinedBody,
18039 EL: SourceLocation(), Else: nullptr);
18040
18041 FusedBodyStmts.push_back(Elt: IfStatement);
18042 }
18043 FusedBody = CompoundStmt::Create(C: Context, Stmts: FusedBodyStmts, FPFeatures: FPOptionsOverride(),
18044 LB: SourceLocation(), RB: SourceLocation());
18045
18046 // 7. Construct the final fused loop
18047 ForStmt *FusedForStmt = new (Context)
18048 ForStmt(Context, InitStmt.get(), CondExpr.get(), nullptr, IncrExpr.get(),
18049 FusedBody, InitStmt.get()->getBeginLoc(), SourceLocation(),
18050 IncrExpr.get()->getEndLoc());
18051
18052 // In the case of looprange, the result of fuse won't simply
18053 // be a single loop (ForStmt), but rather a loop sequence
18054 // (CompoundStmt) of 3 parts: the pre-fusion loops, the fused loop
18055 // and the post-fusion loops, preserving its original order.
18056 //
18057 // Note: If looprange clause produces a single fused loop nest then
18058 // this compound statement wrapper is unnecessary (Therefore this
18059 // treatment is skipped)
18060
18061 Stmt *FusionStmt = FusedForStmt;
18062 if (LRC && CountVal != SeqAnalysis.LoopSeqSize) {
18063 SmallVector<Stmt *, 4> FinalLoops;
18064
18065 // Reset the transform index
18066 TransformIndex = 0;
18067
18068 // Collect all non-fused loops before and after the fused region.
18069 // Pre-fusion and post-fusion loops are inserted in order exploiting their
18070 // symmetry, along with their corresponding transformation pre-inits if
18071 // needed. The fused loop is added between the two regions.
18072 for (unsigned I : llvm::seq<unsigned>(Size: SeqAnalysis.LoopSeqSize)) {
18073 if (I >= FirstVal - 1 && I < FirstVal + CountVal - 1) {
18074 // Update the Transformation counter to skip already treated
18075 // loop transformations
18076 if (!SeqAnalysis.Loops[I].isLoopTransformation())
18077 ++TransformIndex;
18078 continue;
18079 }
18080
18081 // No need to handle:
18082 // Regular loops: they are kept intact as-is.
18083 // Loop-sequence-generating transformations: already handled earlier.
18084 // Only TransformSingleLoop requires inserting pre-inits here
18085 if (SeqAnalysis.Loops[I].isRegularLoop()) {
18086 const auto &TransformPreInit =
18087 SeqAnalysis.Loops[TransformIndex++].TransformsPreInits;
18088 if (!TransformPreInit.empty())
18089 llvm::append_range(C&: PreInits, R: TransformPreInit);
18090 }
18091
18092 FinalLoops.push_back(Elt: SeqAnalysis.Loops[I].TheForStmt);
18093 }
18094
18095 FinalLoops.insert(I: FinalLoops.begin() + (FirstVal - 1), Elt: FusedForStmt);
18096 FusionStmt = CompoundStmt::Create(C: Context, Stmts: FinalLoops, FPFeatures: FPOptionsOverride(),
18097 LB: SourceLocation(), RB: SourceLocation());
18098 }
18099 return OMPFuseDirective::Create(C: Context, StartLoc, EndLoc, Clauses,
18100 NumGeneratedTopLevelLoops, AssociatedStmt: AStmt, TransformedStmt: FusionStmt,
18101 PreInits: buildPreInits(Context, PreInits));
18102}
18103
18104OMPClause *SemaOpenMP::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
18105 Expr *Expr,
18106 SourceLocation StartLoc,
18107 SourceLocation LParenLoc,
18108 SourceLocation EndLoc) {
18109 OMPClause *Res = nullptr;
18110 switch (Kind) {
18111 case OMPC_final:
18112 Res = ActOnOpenMPFinalClause(Condition: Expr, StartLoc, LParenLoc, EndLoc);
18113 break;
18114 case OMPC_safelen:
18115 Res = ActOnOpenMPSafelenClause(Length: Expr, StartLoc, LParenLoc, EndLoc);
18116 break;
18117 case OMPC_simdlen:
18118 Res = ActOnOpenMPSimdlenClause(Length: Expr, StartLoc, LParenLoc, EndLoc);
18119 break;
18120 case OMPC_allocator:
18121 Res = ActOnOpenMPAllocatorClause(Allocator: Expr, StartLoc, LParenLoc, EndLoc);
18122 break;
18123 case OMPC_collapse:
18124 Res = ActOnOpenMPCollapseClause(NumForLoops: Expr, StartLoc, LParenLoc, EndLoc);
18125 break;
18126 case OMPC_ordered:
18127 Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc, LParenLoc, NumForLoops: Expr);
18128 break;
18129 case OMPC_nowait:
18130 Res = ActOnOpenMPNowaitClause(StartLoc, EndLoc, LParenLoc, Condition: Expr);
18131 break;
18132 case OMPC_priority:
18133 Res = ActOnOpenMPPriorityClause(Priority: Expr, StartLoc, LParenLoc, EndLoc);
18134 break;
18135 case OMPC_hint:
18136 Res = ActOnOpenMPHintClause(Hint: Expr, StartLoc, LParenLoc, EndLoc);
18137 break;
18138 case OMPC_depobj:
18139 Res = ActOnOpenMPDepobjClause(Depobj: Expr, StartLoc, LParenLoc, EndLoc);
18140 break;
18141 case OMPC_detach:
18142 Res = ActOnOpenMPDetachClause(Evt: Expr, StartLoc, LParenLoc, EndLoc);
18143 break;
18144 case OMPC_novariants:
18145 Res = ActOnOpenMPNovariantsClause(Condition: Expr, StartLoc, LParenLoc, EndLoc);
18146 break;
18147 case OMPC_nocontext:
18148 Res = ActOnOpenMPNocontextClause(Condition: Expr, StartLoc, LParenLoc, EndLoc);
18149 break;
18150 case OMPC_filter:
18151 Res = ActOnOpenMPFilterClause(ThreadID: Expr, StartLoc, LParenLoc, EndLoc);
18152 break;
18153 case OMPC_partial:
18154 Res = ActOnOpenMPPartialClause(FactorExpr: Expr, StartLoc, LParenLoc, EndLoc);
18155 break;
18156 case OMPC_depth:
18157 Res = ActOnOpenMPDepthClause(DepthExpr: Expr, StartLoc, LParenLoc, EndLoc);
18158 break;
18159 case OMPC_message:
18160 Res = ActOnOpenMPMessageClause(MS: Expr, StartLoc, LParenLoc, EndLoc);
18161 break;
18162 case OMPC_align:
18163 Res = ActOnOpenMPAlignClause(Alignment: Expr, StartLoc, LParenLoc, EndLoc);
18164 break;
18165 case OMPC_ompx_dyn_cgroup_mem:
18166 Res = ActOnOpenMPXDynCGroupMemClause(Size: Expr, StartLoc, LParenLoc, EndLoc);
18167 break;
18168 case OMPC_holds:
18169 Res = ActOnOpenMPHoldsClause(E: Expr, StartLoc, LParenLoc, EndLoc);
18170 break;
18171 case OMPC_transparent:
18172 Res = ActOnOpenMPTransparentClause(Transparent: Expr, StartLoc, LParenLoc, EndLoc);
18173 break;
18174 case OMPC_dyn_groupprivate:
18175 case OMPC_grainsize:
18176 case OMPC_num_tasks:
18177 case OMPC_num_threads:
18178 case OMPC_device:
18179 case OMPC_if:
18180 case OMPC_default:
18181 case OMPC_proc_bind:
18182 case OMPC_schedule:
18183 case OMPC_private:
18184 case OMPC_firstprivate:
18185 case OMPC_lastprivate:
18186 case OMPC_shared:
18187 case OMPC_reduction:
18188 case OMPC_task_reduction:
18189 case OMPC_in_reduction:
18190 case OMPC_linear:
18191 case OMPC_aligned:
18192 case OMPC_copyin:
18193 case OMPC_copyprivate:
18194 case OMPC_untied:
18195 case OMPC_mergeable:
18196 case OMPC_threadprivate:
18197 case OMPC_groupprivate:
18198 case OMPC_sizes:
18199 case OMPC_allocate:
18200 case OMPC_flush:
18201 case OMPC_read:
18202 case OMPC_write:
18203 case OMPC_update:
18204 case OMPC_capture:
18205 case OMPC_compare:
18206 case OMPC_seq_cst:
18207 case OMPC_acq_rel:
18208 case OMPC_acquire:
18209 case OMPC_release:
18210 case OMPC_relaxed:
18211 case OMPC_depend:
18212 case OMPC_threads:
18213 case OMPC_simd:
18214 case OMPC_map:
18215 case OMPC_nogroup:
18216 case OMPC_dist_schedule:
18217 case OMPC_defaultmap:
18218 case OMPC_unknown:
18219 case OMPC_uniform:
18220 case OMPC_to:
18221 case OMPC_from:
18222 case OMPC_use_device_ptr:
18223 case OMPC_use_device_addr:
18224 case OMPC_is_device_ptr:
18225 case OMPC_unified_address:
18226 case OMPC_unified_shared_memory:
18227 case OMPC_reverse_offload:
18228 case OMPC_dynamic_allocators:
18229 case OMPC_atomic_default_mem_order:
18230 case OMPC_self_maps:
18231 case OMPC_device_type:
18232 case OMPC_match:
18233 case OMPC_nontemporal:
18234 case OMPC_order:
18235 case OMPC_at:
18236 case OMPC_severity:
18237 case OMPC_destroy:
18238 case OMPC_inclusive:
18239 case OMPC_exclusive:
18240 case OMPC_uses_allocators:
18241 case OMPC_affinity:
18242 case OMPC_when:
18243 case OMPC_bind:
18244 case OMPC_num_teams:
18245 case OMPC_thread_limit:
18246 default:
18247 llvm_unreachable("Clause is not allowed.");
18248 }
18249 return Res;
18250}
18251
18252// An OpenMP directive such as 'target parallel' has two captured regions:
18253// for the 'target' and 'parallel' respectively. This function returns
18254// the region in which to capture expressions associated with a clause.
18255// A return value of OMPD_unknown signifies that the expression should not
18256// be captured.
18257static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
18258 OpenMPDirectiveKind DKind, OpenMPClauseKind CKind,
18259 llvm::omp::Version OMPVersion,
18260 OpenMPDirectiveKind NameModifier = OMPD_unknown) {
18261 assert(isAllowedClauseForDirective(DKind, CKind, OMPVersion) &&
18262 "Invalid directive with CKind-clause");
18263
18264 // Invalid modifier will be diagnosed separately, just return OMPD_unknown.
18265 if (NameModifier != OMPD_unknown &&
18266 !isAllowedClauseForDirective(D: NameModifier, C: CKind, V: OMPVersion))
18267 return OMPD_unknown;
18268
18269 ArrayRef<OpenMPDirectiveKind> Leafs = getLeafConstructsOrSelf(D: DKind);
18270
18271 // [5.2:341:24-30]
18272 // If the clauses have expressions on them, such as for various clauses where
18273 // the argument of the clause is an expression, or lower-bound, length, or
18274 // stride expressions inside array sections (or subscript and stride
18275 // expressions in subscript-triplet for Fortran), or linear-step or alignment
18276 // expressions, the expressions are evaluated immediately before the construct
18277 // to which the clause has been split or duplicated per the above rules
18278 // (therefore inside of the outer leaf constructs). However, the expressions
18279 // inside the num_teams and thread_limit clauses are always evaluated before
18280 // the outermost leaf construct.
18281
18282 // Process special cases first.
18283 switch (CKind) {
18284 case OMPC_if:
18285 switch (DKind) {
18286 case OMPD_teams_loop:
18287 case OMPD_target_teams_loop:
18288 // For [target] teams loop, assume capture region is 'teams' so it's
18289 // available for codegen later to use if/when necessary.
18290 return OMPD_teams;
18291 case OMPD_target_update:
18292 case OMPD_target_enter_data:
18293 case OMPD_target_exit_data:
18294 return OMPD_task;
18295 default:
18296 break;
18297 }
18298 break;
18299 case OMPC_num_teams:
18300 case OMPC_thread_limit:
18301 case OMPC_ompx_dyn_cgroup_mem:
18302 case OMPC_dyn_groupprivate:
18303 // TODO: This may need to consider teams too.
18304 if (Leafs[0] == OMPD_target)
18305 return OMPD_target;
18306 break;
18307 case OMPC_device:
18308 if (Leafs[0] == OMPD_target ||
18309 llvm::is_contained(Set: {OMPD_dispatch, OMPD_target_update,
18310 OMPD_target_enter_data, OMPD_target_exit_data},
18311 Element: DKind))
18312 return OMPD_task;
18313 break;
18314 case OMPC_novariants:
18315 case OMPC_nocontext:
18316 if (DKind == OMPD_dispatch)
18317 return OMPD_task;
18318 break;
18319 case OMPC_when:
18320 if (DKind == OMPD_metadirective)
18321 return OMPD_metadirective;
18322 break;
18323 case OMPC_filter:
18324 return OMPD_unknown;
18325 default:
18326 break;
18327 }
18328
18329 // If none of the special cases above applied, and DKind is a capturing
18330 // directive, find the innermost enclosing leaf construct that allows the
18331 // clause, and returns the corresponding capture region.
18332
18333 auto GetEnclosingRegion = [&](int EndIdx, OpenMPClauseKind Clause) {
18334 // Find the index in "Leafs" of the last leaf that allows the given
18335 // clause. The search will only include indexes [0, EndIdx).
18336 // EndIdx may be set to the index of the NameModifier, if present.
18337 int InnermostIdx = [&]() {
18338 for (int I = EndIdx - 1; I >= 0; --I) {
18339 if (isAllowedClauseForDirective(D: Leafs[I], C: Clause, V: OMPVersion))
18340 return I;
18341 }
18342 return -1;
18343 }();
18344
18345 // Find the nearest enclosing capture region.
18346 SmallVector<OpenMPDirectiveKind, 2> Regions;
18347 for (int I = InnermostIdx - 1; I >= 0; --I) {
18348 if (!isOpenMPCapturingDirective(DKind: Leafs[I]))
18349 continue;
18350 Regions.clear();
18351 getOpenMPCaptureRegions(CaptureRegions&: Regions, DKind: Leafs[I]);
18352 if (Regions[0] != OMPD_unknown)
18353 return Regions.back();
18354 }
18355 return OMPD_unknown;
18356 };
18357
18358 if (isOpenMPCapturingDirective(DKind)) {
18359 auto GetLeafIndex = [&](OpenMPDirectiveKind Dir) {
18360 for (int I = 0, E = Leafs.size(); I != E; ++I) {
18361 if (Leafs[I] == Dir)
18362 return I + 1;
18363 }
18364 return 0;
18365 };
18366
18367 int End = NameModifier == OMPD_unknown ? Leafs.size()
18368 : GetLeafIndex(NameModifier);
18369 return GetEnclosingRegion(End, CKind);
18370 }
18371
18372 return OMPD_unknown;
18373}
18374
18375OMPClause *SemaOpenMP::ActOnOpenMPIfClause(
18376 OpenMPDirectiveKind NameModifier, Expr *Condition, SourceLocation StartLoc,
18377 SourceLocation LParenLoc, SourceLocation NameModifierLoc,
18378 SourceLocation ColonLoc, SourceLocation EndLoc) {
18379 Expr *ValExpr = Condition;
18380 Stmt *HelperValStmt = nullptr;
18381 OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
18382 if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
18383 !Condition->isInstantiationDependent() &&
18384 !Condition->containsUnexpandedParameterPack()) {
18385 ExprResult Val = SemaRef.CheckBooleanCondition(Loc: StartLoc, E: Condition);
18386 if (Val.isInvalid())
18387 return nullptr;
18388
18389 ValExpr = Val.get();
18390
18391 OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
18392 CaptureRegion = getOpenMPCaptureRegionForClause(
18393 DKind, CKind: OMPC_if, OMPVersion: getLangOpts().getOpenMPVersion(), NameModifier);
18394 if (CaptureRegion != OMPD_unknown &&
18395 !SemaRef.CurContext->isDependentContext()) {
18396 ValExpr = SemaRef.MakeFullExpr(Arg: ValExpr).get();
18397 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
18398 ValExpr = tryBuildCapture(SemaRef, Capture: ValExpr, Captures).get();
18399 HelperValStmt = buildPreInits(Context&: getASTContext(), Captures);
18400 }
18401 }
18402
18403 return new (getASTContext())
18404 OMPIfClause(NameModifier, ValExpr, HelperValStmt, CaptureRegion, StartLoc,
18405 LParenLoc, NameModifierLoc, ColonLoc, EndLoc);
18406}
18407
18408OMPClause *SemaOpenMP::ActOnOpenMPFinalClause(Expr *Condition,
18409 SourceLocation StartLoc,
18410 SourceLocation LParenLoc,
18411 SourceLocation EndLoc) {
18412 Expr *ValExpr = Condition;
18413 Stmt *HelperValStmt = nullptr;
18414 OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
18415 if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
18416 !Condition->isInstantiationDependent() &&
18417 !Condition->containsUnexpandedParameterPack()) {
18418 ExprResult Val = SemaRef.CheckBooleanCondition(Loc: StartLoc, E: Condition);
18419 if (Val.isInvalid())
18420 return nullptr;
18421
18422 ValExpr = SemaRef.MakeFullExpr(Arg: Val.get()).get();
18423
18424 OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
18425 CaptureRegion = getOpenMPCaptureRegionForClause(
18426 DKind, CKind: OMPC_final, OMPVersion: getLangOpts().getOpenMPVersion());
18427 if (CaptureRegion != OMPD_unknown &&
18428 !SemaRef.CurContext->isDependentContext()) {
18429 ValExpr = SemaRef.MakeFullExpr(Arg: ValExpr).get();
18430 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
18431 ValExpr = tryBuildCapture(SemaRef, Capture: ValExpr, Captures).get();
18432 HelperValStmt = buildPreInits(Context&: getASTContext(), Captures);
18433 }
18434 }
18435
18436 return new (getASTContext()) OMPFinalClause(
18437 ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
18438}
18439
18440ExprResult
18441SemaOpenMP::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc,
18442 Expr *Op) {
18443 if (!Op)
18444 return ExprError();
18445
18446 class IntConvertDiagnoser : public Sema::ICEConvertDiagnoser {
18447 public:
18448 IntConvertDiagnoser()
18449 : ICEConvertDiagnoser(/*AllowScopedEnumerations=*/false, false, true) {}
18450 SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
18451 QualType T) override {
18452 return S.Diag(Loc, DiagID: diag::err_omp_not_integral) << T;
18453 }
18454 SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc,
18455 QualType T) override {
18456 return S.Diag(Loc, DiagID: diag::err_omp_incomplete_type) << T;
18457 }
18458 SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc,
18459 QualType T,
18460 QualType ConvTy) override {
18461 return S.Diag(Loc, DiagID: diag::err_omp_explicit_conversion) << T << ConvTy;
18462 }
18463 SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv,
18464 QualType ConvTy) override {
18465 return S.Diag(Loc: Conv->getLocation(), DiagID: diag::note_omp_conversion_here)
18466 << ConvTy->isEnumeralType() << ConvTy;
18467 }
18468 SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
18469 QualType T) override {
18470 return S.Diag(Loc, DiagID: diag::err_omp_ambiguous_conversion) << T;
18471 }
18472 SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv,
18473 QualType ConvTy) override {
18474 return S.Diag(Loc: Conv->getLocation(), DiagID: diag::note_omp_conversion_here)
18475 << ConvTy->isEnumeralType() << ConvTy;
18476 }
18477 SemaDiagnosticBuilder diagnoseConversion(Sema &, SourceLocation, QualType,
18478 QualType) override {
18479 llvm_unreachable("conversion functions are permitted");
18480 }
18481 } ConvertDiagnoser;
18482 return SemaRef.PerformContextualImplicitConversion(Loc, FromE: Op, Converter&: ConvertDiagnoser);
18483}
18484
18485static bool
18486isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, OpenMPClauseKind CKind,
18487 bool StrictlyPositive, bool BuildCapture = false,
18488 OpenMPDirectiveKind DKind = OMPD_unknown,
18489 OpenMPDirectiveKind *CaptureRegion = nullptr,
18490 Stmt **HelperValStmt = nullptr) {
18491 if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() &&
18492 !ValExpr->isInstantiationDependent()) {
18493 SourceLocation Loc = ValExpr->getExprLoc();
18494 ExprResult Value =
18495 SemaRef.OpenMP().PerformOpenMPImplicitIntegerConversion(Loc, Op: ValExpr);
18496 if (Value.isInvalid())
18497 return false;
18498
18499 ValExpr = Value.get();
18500 // The expression must evaluate to a non-negative integer value.
18501 if (std::optional<llvm::APSInt> Result =
18502 ValExpr->getIntegerConstantExpr(Ctx: SemaRef.Context)) {
18503 if (Result->isSigned() &&
18504 !((!StrictlyPositive && Result->isNonNegative()) ||
18505 (StrictlyPositive && Result->isStrictlyPositive()))) {
18506 SemaRef.Diag(Loc, DiagID: diag::err_omp_negative_expression_in_clause)
18507 << getOpenMPClauseNameForDiag(C: CKind) << (StrictlyPositive ? 1 : 0)
18508 << ValExpr->getSourceRange();
18509 return false;
18510 }
18511 }
18512 if (!BuildCapture)
18513 return true;
18514 *CaptureRegion = getOpenMPCaptureRegionForClause(
18515 DKind, CKind, OMPVersion: SemaRef.getLangOpts().getOpenMPVersion());
18516 if (*CaptureRegion != OMPD_unknown &&
18517 !SemaRef.CurContext->isDependentContext()) {
18518 ValExpr = SemaRef.MakeFullExpr(Arg: ValExpr).get();
18519 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
18520 ValExpr = tryBuildCapture(SemaRef, Capture: ValExpr, Captures).get();
18521 *HelperValStmt = buildPreInits(Context&: SemaRef.Context, Captures);
18522 }
18523 }
18524 return true;
18525}
18526
18527static std::string getListOfPossibleValues(OpenMPClauseKind K, unsigned First,
18528 unsigned Last,
18529 ArrayRef<unsigned> Exclude = {}) {
18530 SmallString<256> Buffer;
18531 llvm::raw_svector_ostream Out(Buffer);
18532 unsigned Skipped = Exclude.size();
18533 for (unsigned I = First; I < Last; ++I) {
18534 if (llvm::is_contained(Range&: Exclude, Element: I)) {
18535 --Skipped;
18536 continue;
18537 }
18538 Out << "'" << getOpenMPSimpleClauseTypeName(Kind: K, Type: I) << "'";
18539 if (I + Skipped + 2 == Last)
18540 Out << " or ";
18541 else if (I + Skipped + 1 != Last)
18542 Out << ", ";
18543 }
18544 return std::string(Out.str());
18545}
18546
18547OMPClause *SemaOpenMP::ActOnOpenMPNumThreadsClause(
18548 ArrayRef<Expr *> VarList, OpenMPNumThreadsClauseModifier SimpleModifier,
18549 SourceLocation SimpleModifierLoc,
18550 OpenMPNumThreadsClauseModifier ComplexModifier, Expr *ComplexModifierExpr,
18551 SourceLocation ComplexModifierLoc, SourceLocation StartLoc,
18552 SourceLocation LParenLoc, SourceLocation EndLoc) {
18553 // Check that modifiers were correctly specified.
18554 if (ComplexModifierLoc.isValid() &&
18555 (ComplexModifier != OMPC_NUMTHREADS_dims || !ComplexModifierExpr)) {
18556 Diag(Loc: ComplexModifierLoc, DiagID: diag::err_omp_malformed_complex_modifier)
18557 << getOpenMPSimpleClauseTypeName(Kind: OMPC_num_threads, Type: OMPC_NUMTHREADS_dims)
18558 << getOpenMPClauseName(C: OMPC_num_threads);
18559 return nullptr;
18560 }
18561 if (SimpleModifierLoc.isValid() && SimpleModifier == OMPC_NUMTHREADS_dims) {
18562 Diag(Loc: SimpleModifierLoc, DiagID: diag::err_omp_malformed_complex_modifier)
18563 << getOpenMPSimpleClauseTypeName(Kind: OMPC_num_threads, Type: OMPC_NUMTHREADS_dims)
18564 << getOpenMPClauseName(C: OMPC_num_threads);
18565 return nullptr;
18566 }
18567 if (SimpleModifierLoc.isValid() && SimpleModifier != OMPC_NUMTHREADS_strict) {
18568 Diag(Loc: SimpleModifierLoc, DiagID: diag::err_omp_unexpected_clause_value)
18569 << getOpenMPSimpleClauseTypeName(Kind: OMPC_num_threads,
18570 Type: OMPC_NUMTHREADS_strict)
18571 << getOpenMPClauseName(C: OMPC_num_threads);
18572 return nullptr;
18573 }
18574
18575 if (VarList.empty())
18576 return nullptr;
18577
18578 SmallVector<Expr *, 3> Vars(VarList.begin(), VarList.end());
18579 for (Expr *&ValExpr : Vars) {
18580 // OpenMP [2.5, Restrictions]
18581 // The num_threads expression must evaluate to a positive integer value.
18582 if (!isNonNegativeIntegerValue(ValExpr, SemaRef, CKind: OMPC_num_threads,
18583 /*StrictlyPositive=*/true))
18584 return nullptr;
18585 }
18586
18587 if (ComplexModifier == OMPC_NUMTHREADS_dims) {
18588 ExprResult Res = ActOnOpenMPDimsModifier(Kind: OMPC_num_threads, Modifier: ComplexModifier,
18589 ModifierExpr: ComplexModifierExpr,
18590 ModifierLoc: ComplexModifierLoc, VarList: Vars, VarListEndLoc: EndLoc);
18591 if (Res.isInvalid())
18592 return nullptr;
18593 ComplexModifierExpr = Res.get();
18594
18595 if (validateMultidimClauseExprs(SemaRef&: *this, ClauseKind: OMPC_num_threads, ClauseBeginLoc: StartLoc, ClauseVarList: Vars,
18596 DimsModifierExpr: ComplexModifierExpr))
18597 return nullptr;
18598 }
18599 if (SimpleModifier == OMPC_NUMTHREADS_strict && getLangOpts().OpenMP < 60) {
18600 Diag(Loc: SimpleModifierLoc, DiagID: diag::err_omp_modifier_requires_version)
18601 << getOpenMPSimpleClauseTypeName(Kind: OMPC_num_threads, Type: SimpleModifier)
18602 << getOpenMPClauseName(C: OMPC_num_threads) << "6.0";
18603 return nullptr;
18604 }
18605
18606 OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
18607 OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause(
18608 DKind, CKind: OMPC_num_threads, OMPVersion: getLangOpts().getOpenMPVersion());
18609 if (CaptureRegion == OMPD_unknown || SemaRef.CurContext->isDependentContext())
18610 return OMPNumThreadsClause::Create(
18611 C: getASTContext(), CaptureRegion, StartLoc, LParenLoc, EndLoc, VL: Vars,
18612 PrescriptivenessModifier: SimpleModifier, DimsModifier: ComplexModifier, PrescriptivenessModifierLoc: SimpleModifierLoc, DimsModifierLoc: ComplexModifierLoc,
18613 DimsModifierExpr: ComplexModifierExpr, /*PreInit=*/nullptr);
18614
18615 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
18616 for (Expr *&ValExpr : Vars) {
18617 ValExpr = SemaRef.MakeFullExpr(Arg: ValExpr).get();
18618 ValExpr = tryBuildCapture(SemaRef, Capture: ValExpr, Captures).get();
18619 }
18620 if (ComplexModifierExpr) {
18621 ComplexModifierExpr = SemaRef.MakeFullExpr(Arg: ComplexModifierExpr).get();
18622 ComplexModifierExpr =
18623 tryBuildCapture(SemaRef, Capture: ComplexModifierExpr, Captures).get();
18624 }
18625 Stmt *PreInit = buildPreInits(Context&: getASTContext(), Captures);
18626
18627 return OMPNumThreadsClause::Create(
18628 C: getASTContext(), CaptureRegion, StartLoc, LParenLoc, EndLoc, VL: Vars,
18629 PrescriptivenessModifier: SimpleModifier, DimsModifier: ComplexModifier, PrescriptivenessModifierLoc: SimpleModifierLoc, DimsModifierLoc: ComplexModifierLoc,
18630 DimsModifierExpr: ComplexModifierExpr, PreInit);
18631}
18632
18633ExprResult SemaOpenMP::VerifyPositiveIntegerConstantInClause(
18634 Expr *E, OpenMPClauseKind CKind, bool StrictlyPositive,
18635 bool SuppressExprDiags) {
18636 if (!E)
18637 return ExprError();
18638 if (E->isValueDependent() || E->isTypeDependent() ||
18639 E->isInstantiationDependent() || E->containsUnexpandedParameterPack())
18640 return E;
18641
18642 llvm::APSInt Result;
18643 ExprResult ICE;
18644 if (SuppressExprDiags) {
18645 // Use a custom diagnoser that suppresses 'note' diagnostics about the
18646 // expression.
18647 struct SuppressedDiagnoser : public Sema::VerifyICEDiagnoser {
18648 SuppressedDiagnoser() : VerifyICEDiagnoser(/*Suppress=*/true) {}
18649 SemaBase::SemaDiagnosticBuilder
18650 diagnoseNotICE(Sema &S, SourceLocation Loc) override {
18651 llvm_unreachable("Diagnostic suppressed");
18652 }
18653 } Diagnoser;
18654 ICE = SemaRef.VerifyIntegerConstantExpression(E, Result: &Result, Diagnoser,
18655 CanFold: AllowFoldKind::Allow);
18656 } else {
18657 ICE =
18658 SemaRef.VerifyIntegerConstantExpression(E, Result: &Result,
18659 /*FIXME*/ CanFold: AllowFoldKind::Allow);
18660 }
18661 if (ICE.isInvalid())
18662 return ExprError();
18663
18664 if ((StrictlyPositive && !Result.isStrictlyPositive()) ||
18665 (!StrictlyPositive && !Result.isNonNegative())) {
18666 Diag(Loc: E->getExprLoc(), DiagID: diag::err_omp_negative_expression_in_clause)
18667 << getOpenMPClauseNameForDiag(C: CKind) << (StrictlyPositive ? 1 : 0)
18668 << E->getSourceRange();
18669 return ExprError();
18670 }
18671 if ((CKind == OMPC_aligned || CKind == OMPC_align ||
18672 CKind == OMPC_allocate) &&
18673 !Result.isPowerOf2()) {
18674 Diag(Loc: E->getExprLoc(), DiagID: diag::warn_omp_alignment_not_power_of_two)
18675 << E->getSourceRange();
18676 return ExprError();
18677 }
18678
18679 if (!Result.isRepresentableByInt64()) {
18680 Diag(Loc: E->getExprLoc(), DiagID: diag::err_omp_large_expression_in_clause)
18681 << getOpenMPClauseNameForDiag(C: CKind) << E->getSourceRange();
18682 return ExprError();
18683 }
18684
18685 if (CKind == OMPC_collapse && DSAStack->getAssociatedLoops() == 1)
18686 DSAStack->setAssociatedLoops(Result.getExtValue());
18687 else if (CKind == OMPC_ordered)
18688 DSAStack->setAssociatedLoops(Result.getExtValue());
18689 return ICE;
18690}
18691
18692void SemaOpenMP::setOpenMPDeviceNum(int Num) { DeviceNum = Num; }
18693
18694void SemaOpenMP::setOpenMPDeviceNumID(StringRef ID) { DeviceNumID = ID; }
18695
18696int SemaOpenMP::getOpenMPDeviceNum() const { return DeviceNum; }
18697
18698void SemaOpenMP::ActOnOpenMPDeviceNum(Expr *DeviceNumExpr) {
18699 llvm::APSInt Result;
18700 Expr::EvalResult EvalResult;
18701 // Evaluate the expression to an integer value
18702 if (!DeviceNumExpr->isValueDependent() &&
18703 DeviceNumExpr->EvaluateAsInt(Result&: EvalResult, Ctx: SemaRef.Context)) {
18704 // The device expression must evaluate to a non-negative integer value.
18705 Result = EvalResult.Val.getInt();
18706 if (Result.isNonNegative()) {
18707 setOpenMPDeviceNum(Result.getZExtValue());
18708 } else {
18709 Diag(Loc: DeviceNumExpr->getExprLoc(),
18710 DiagID: diag::err_omp_negative_expression_in_clause)
18711 << "device_num" << 0 << DeviceNumExpr->getSourceRange();
18712 }
18713 } else if (auto *DeclRef = dyn_cast<DeclRefExpr>(Val: DeviceNumExpr)) {
18714 // Check if the expression is an identifier
18715 IdentifierInfo *IdInfo = DeclRef->getDecl()->getIdentifier();
18716 if (IdInfo) {
18717 setOpenMPDeviceNumID(IdInfo->getName());
18718 }
18719 } else {
18720 Diag(Loc: DeviceNumExpr->getExprLoc(), DiagID: diag::err_expected_expression);
18721 }
18722}
18723
18724OMPClause *SemaOpenMP::ActOnOpenMPSafelenClause(Expr *Len,
18725 SourceLocation StartLoc,
18726 SourceLocation LParenLoc,
18727 SourceLocation EndLoc) {
18728 // OpenMP [2.8.1, simd construct, Description]
18729 // The parameter of the safelen clause must be a constant
18730 // positive integer expression.
18731 ExprResult Safelen = VerifyPositiveIntegerConstantInClause(E: Len, CKind: OMPC_safelen);
18732 if (Safelen.isInvalid())
18733 return nullptr;
18734 return new (getASTContext())
18735 OMPSafelenClause(Safelen.get(), StartLoc, LParenLoc, EndLoc);
18736}
18737
18738OMPClause *SemaOpenMP::ActOnOpenMPSimdlenClause(Expr *Len,
18739 SourceLocation StartLoc,
18740 SourceLocation LParenLoc,
18741 SourceLocation EndLoc) {
18742 // OpenMP [2.8.1, simd construct, Description]
18743 // The parameter of the simdlen clause must be a constant
18744 // positive integer expression.
18745 ExprResult Simdlen = VerifyPositiveIntegerConstantInClause(E: Len, CKind: OMPC_simdlen);
18746 if (Simdlen.isInvalid())
18747 return nullptr;
18748 return new (getASTContext())
18749 OMPSimdlenClause(Simdlen.get(), StartLoc, LParenLoc, EndLoc);
18750}
18751
18752/// Tries to find omp_allocator_handle_t type.
18753static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc,
18754 DSAStackTy *Stack) {
18755 if (!Stack->getOMPAllocatorHandleT().isNull())
18756 return true;
18757
18758 // Set the allocator handle type.
18759 IdentifierInfo *II = &S.PP.getIdentifierTable().get(Name: "omp_allocator_handle_t");
18760 ParsedType PT = S.getTypeName(II: *II, NameLoc: Loc, S: S.getCurScope());
18761 if (!PT.getAsOpaquePtr() || PT.get().isNull()) {
18762 S.Diag(Loc, DiagID: diag::err_omp_implied_type_not_found)
18763 << "omp_allocator_handle_t";
18764 return false;
18765 }
18766 QualType AllocatorHandleEnumTy = PT.get();
18767 AllocatorHandleEnumTy.addConst();
18768
18769 // Fill the predefined allocator map.
18770 bool ErrorFound = false;
18771 for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
18772 auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
18773 StringRef Allocator =
18774 OMPAllocateDeclAttr::ConvertAllocatorTypeTyToStr(Val: AllocatorKind);
18775 DeclarationName AllocatorName = &S.getASTContext().Idents.get(Name: Allocator);
18776 auto *VD = dyn_cast_or_null<ValueDecl>(
18777 Val: S.LookupSingleName(S: S.TUScope, Name: AllocatorName, Loc, NameKind: Sema::LookupAnyName));
18778 if (!VD) {
18779 ErrorFound = true;
18780 break;
18781 }
18782 QualType AllocatorType =
18783 VD->getType().getNonLValueExprType(Context: S.getASTContext());
18784 ExprResult Res = S.BuildDeclRefExpr(D: VD, Ty: AllocatorType, VK: VK_LValue, Loc);
18785 if (!Res.isUsable()) {
18786 ErrorFound = true;
18787 break;
18788 }
18789 Res = S.PerformImplicitConversion(From: Res.get(), ToType: AllocatorHandleEnumTy,
18790 Action: AssignmentAction::Initializing,
18791 /*AllowExplicit=*/true);
18792 if (!Res.isUsable()) {
18793 ErrorFound = true;
18794 break;
18795 }
18796 Stack->setAllocator(AllocatorKind, Allocator: Res.get());
18797 }
18798 if (ErrorFound) {
18799 S.Diag(Loc, DiagID: diag::err_omp_implied_type_not_found)
18800 << "omp_allocator_handle_t";
18801 return false;
18802 }
18803
18804 // Record the type only now. It is what tells a later call that the map above
18805 // is ready to be read, so setting it before the map is filled would let that
18806 // call proceed on a map this one gave up on halfway through.
18807 Stack->setOMPAllocatorHandleT(AllocatorHandleEnumTy);
18808
18809 return true;
18810}
18811
18812OMPClause *SemaOpenMP::ActOnOpenMPAllocatorClause(Expr *A,
18813 SourceLocation StartLoc,
18814 SourceLocation LParenLoc,
18815 SourceLocation EndLoc) {
18816 // OpenMP [2.11.3, allocate Directive, Description]
18817 // allocator is an expression of omp_allocator_handle_t type.
18818 if (!findOMPAllocatorHandleT(S&: SemaRef, Loc: A->getExprLoc(), DSAStack))
18819 return nullptr;
18820
18821 ExprResult Allocator = SemaRef.DefaultLvalueConversion(E: A);
18822 if (Allocator.isInvalid())
18823 return nullptr;
18824 Allocator = SemaRef.PerformImplicitConversion(
18825 From: Allocator.get(), DSAStack->getOMPAllocatorHandleT(),
18826 Action: AssignmentAction::Initializing,
18827 /*AllowExplicit=*/true);
18828 if (Allocator.isInvalid())
18829 return nullptr;
18830 return new (getASTContext())
18831 OMPAllocatorClause(Allocator.get(), StartLoc, LParenLoc, EndLoc);
18832}
18833
18834OMPClause *SemaOpenMP::ActOnOpenMPCollapseClause(Expr *NumForLoops,
18835 SourceLocation StartLoc,
18836 SourceLocation LParenLoc,
18837 SourceLocation EndLoc) {
18838 // OpenMP [2.7.1, loop construct, Description]
18839 // OpenMP [2.8.1, simd construct, Description]
18840 // OpenMP [2.9.6, distribute construct, Description]
18841 // The parameter of the collapse clause must be a constant
18842 // positive integer expression.
18843 ExprResult NumForLoopsResult =
18844 VerifyPositiveIntegerConstantInClause(E: NumForLoops, CKind: OMPC_collapse);
18845 if (NumForLoopsResult.isInvalid())
18846 return nullptr;
18847 return new (getASTContext())
18848 OMPCollapseClause(NumForLoopsResult.get(), StartLoc, LParenLoc, EndLoc);
18849}
18850
18851OMPClause *SemaOpenMP::ActOnOpenMPOrderedClause(SourceLocation StartLoc,
18852 SourceLocation EndLoc,
18853 SourceLocation LParenLoc,
18854 Expr *NumForLoops) {
18855 // OpenMP [2.7.1, loop construct, Description]
18856 // OpenMP [2.8.1, simd construct, Description]
18857 // OpenMP [2.9.6, distribute construct, Description]
18858 // The parameter of the ordered clause must be a constant
18859 // positive integer expression if any.
18860 if (NumForLoops && LParenLoc.isValid()) {
18861 ExprResult NumForLoopsResult =
18862 VerifyPositiveIntegerConstantInClause(E: NumForLoops, CKind: OMPC_ordered);
18863 if (NumForLoopsResult.isInvalid())
18864 return nullptr;
18865 NumForLoops = NumForLoopsResult.get();
18866 } else {
18867 NumForLoops = nullptr;
18868 }
18869 auto *Clause =
18870 OMPOrderedClause::Create(C: getASTContext(), Num: NumForLoops,
18871 NumLoops: NumForLoops ? DSAStack->getAssociatedLoops() : 0,
18872 StartLoc, LParenLoc, EndLoc);
18873 DSAStack->setOrderedRegion(/*IsOrdered=*/true, Param: NumForLoops, Clause);
18874 return Clause;
18875}
18876
18877OMPClause *SemaOpenMP::ActOnOpenMPSimpleClause(
18878 OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc,
18879 SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) {
18880 OMPClause *Res = nullptr;
18881 switch (Kind) {
18882 case OMPC_proc_bind:
18883 Res = ActOnOpenMPProcBindClause(Kind: static_cast<ProcBindKind>(Argument),
18884 KindLoc: ArgumentLoc, StartLoc, LParenLoc, EndLoc);
18885 break;
18886 case OMPC_atomic_default_mem_order:
18887 Res = ActOnOpenMPAtomicDefaultMemOrderClause(
18888 Kind: static_cast<OpenMPAtomicDefaultMemOrderClauseKind>(Argument),
18889 KindLoc: ArgumentLoc, StartLoc, LParenLoc, EndLoc);
18890 break;
18891 case OMPC_fail:
18892 Res = ActOnOpenMPFailClause(Kind: static_cast<OpenMPClauseKind>(Argument),
18893 KindLoc: ArgumentLoc, StartLoc, LParenLoc, EndLoc);
18894 break;
18895 case OMPC_update_depend_objects:
18896 Res = ActOnOpenMPUpdateDependObjectsClause(
18897 Kind: static_cast<OpenMPDependClauseKind>(Argument), KindLoc: ArgumentLoc, StartLoc,
18898 LParenLoc, EndLoc);
18899 break;
18900 case OMPC_bind:
18901 Res = ActOnOpenMPBindClause(Kind: static_cast<OpenMPBindClauseKind>(Argument),
18902 KindLoc: ArgumentLoc, StartLoc, LParenLoc, EndLoc);
18903 break;
18904 case OMPC_at:
18905 Res = ActOnOpenMPAtClause(Kind: static_cast<OpenMPAtClauseKind>(Argument),
18906 KindLoc: ArgumentLoc, StartLoc, LParenLoc, EndLoc);
18907 break;
18908 case OMPC_severity:
18909 Res = ActOnOpenMPSeverityClause(
18910 Kind: static_cast<OpenMPSeverityClauseKind>(Argument), KindLoc: ArgumentLoc, StartLoc,
18911 LParenLoc, EndLoc);
18912 break;
18913 case OMPC_threadset:
18914 Res = ActOnOpenMPThreadsetClause(Kind: static_cast<OpenMPThreadsetKind>(Argument),
18915 KindLoc: ArgumentLoc, StartLoc, LParenLoc, EndLoc);
18916 break;
18917 case OMPC_if:
18918 case OMPC_final:
18919 case OMPC_num_threads:
18920 case OMPC_safelen:
18921 case OMPC_simdlen:
18922 case OMPC_sizes:
18923 case OMPC_depth:
18924 case OMPC_allocator:
18925 case OMPC_collapse:
18926 case OMPC_schedule:
18927 case OMPC_private:
18928 case OMPC_firstprivate:
18929 case OMPC_lastprivate:
18930 case OMPC_shared:
18931 case OMPC_reduction:
18932 case OMPC_task_reduction:
18933 case OMPC_in_reduction:
18934 case OMPC_linear:
18935 case OMPC_aligned:
18936 case OMPC_copyin:
18937 case OMPC_copyprivate:
18938 case OMPC_ordered:
18939 case OMPC_nowait:
18940 case OMPC_untied:
18941 case OMPC_mergeable:
18942 case OMPC_threadprivate:
18943 case OMPC_groupprivate:
18944 case OMPC_allocate:
18945 case OMPC_flush:
18946 case OMPC_depobj:
18947 case OMPC_read:
18948 case OMPC_write:
18949 case OMPC_capture:
18950 case OMPC_compare:
18951 case OMPC_update:
18952 case OMPC_seq_cst:
18953 case OMPC_acq_rel:
18954 case OMPC_acquire:
18955 case OMPC_release:
18956 case OMPC_relaxed:
18957 case OMPC_depend:
18958 case OMPC_device:
18959 case OMPC_threads:
18960 case OMPC_simd:
18961 case OMPC_map:
18962 case OMPC_num_teams:
18963 case OMPC_thread_limit:
18964 case OMPC_priority:
18965 case OMPC_grainsize:
18966 case OMPC_nogroup:
18967 case OMPC_num_tasks:
18968 case OMPC_hint:
18969 case OMPC_dist_schedule:
18970 case OMPC_default:
18971 case OMPC_defaultmap:
18972 case OMPC_unknown:
18973 case OMPC_uniform:
18974 case OMPC_to:
18975 case OMPC_from:
18976 case OMPC_use_device_ptr:
18977 case OMPC_use_device_addr:
18978 case OMPC_is_device_ptr:
18979 case OMPC_has_device_addr:
18980 case OMPC_unified_address:
18981 case OMPC_unified_shared_memory:
18982 case OMPC_reverse_offload:
18983 case OMPC_dynamic_allocators:
18984 case OMPC_self_maps:
18985 case OMPC_device_type:
18986 case OMPC_match:
18987 case OMPC_nontemporal:
18988 case OMPC_destroy:
18989 case OMPC_novariants:
18990 case OMPC_nocontext:
18991 case OMPC_detach:
18992 case OMPC_inclusive:
18993 case OMPC_exclusive:
18994 case OMPC_uses_allocators:
18995 case OMPC_affinity:
18996 case OMPC_when:
18997 case OMPC_message:
18998 default:
18999 llvm_unreachable("Clause is not allowed.");
19000 }
19001 return Res;
19002}
19003
19004OMPClause *SemaOpenMP::ActOnOpenMPDefaultClause(
19005 llvm::omp::DefaultKind M, SourceLocation MLoc,
19006 OpenMPDefaultClauseVariableCategory VCKind, SourceLocation VCKindLoc,
19007 SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) {
19008 if (M == OMP_DEFAULT_unknown) {
19009 Diag(Loc: MLoc, DiagID: diag::err_omp_unexpected_clause_value)
19010 << getListOfPossibleValues(K: OMPC_default, /*First=*/0,
19011 /*Last=*/unsigned(OMP_DEFAULT_unknown))
19012 << getOpenMPClauseNameForDiag(C: OMPC_default);
19013 return nullptr;
19014 }
19015 if (VCKind == OMPC_DEFAULT_VC_unknown) {
19016 Diag(Loc: VCKindLoc, DiagID: diag::err_omp_default_vc)
19017 << getOpenMPSimpleClauseTypeName(Kind: OMPC_default, Type: unsigned(M));
19018 return nullptr;
19019 }
19020
19021 bool IsTargetDefault =
19022 getLangOpts().OpenMP >= 60 &&
19023 isOpenMPTargetExecutionDirective(DSAStack->getCurrentDirective());
19024
19025 // OpenMP 6.0, page 224, lines 3-4 default Clause, Semantics
19026 // If data-sharing-attribute is shared then the clause has no effect
19027 // on a target construct;
19028 if (IsTargetDefault && M == OMP_DEFAULT_shared)
19029 return nullptr;
19030
19031 auto SetDefaultClauseAttrs = [&](llvm::omp::DefaultKind M,
19032 OpenMPDefaultClauseVariableCategory VCKind) {
19033 OpenMPDefaultmapClauseModifier DefMapMod;
19034 OpenMPDefaultmapClauseKind DefMapKind;
19035 // default data-sharing-attribute
19036 switch (M) {
19037 case OMP_DEFAULT_none:
19038 if (IsTargetDefault)
19039 DefMapMod = OMPC_DEFAULTMAP_MODIFIER_none;
19040 else
19041 DSAStack->setDefaultDSANone(MLoc);
19042 break;
19043 case OMP_DEFAULT_firstprivate:
19044 if (IsTargetDefault)
19045 DefMapMod = OMPC_DEFAULTMAP_MODIFIER_firstprivate;
19046 else
19047 DSAStack->setDefaultDSAFirstPrivate(MLoc);
19048 break;
19049 case OMP_DEFAULT_private:
19050 if (IsTargetDefault)
19051 DefMapMod = OMPC_DEFAULTMAP_MODIFIER_private;
19052 else
19053 DSAStack->setDefaultDSAPrivate(MLoc);
19054 break;
19055 case OMP_DEFAULT_shared:
19056 assert(!IsTargetDefault && "DSA shared invalid with target directive");
19057 DSAStack->setDefaultDSAShared(MLoc);
19058 break;
19059 default:
19060 llvm_unreachable("unexpected DSA in OpenMP default clause");
19061 }
19062 // default variable-category
19063 switch (VCKind) {
19064 case OMPC_DEFAULT_VC_aggregate:
19065 if (IsTargetDefault)
19066 DefMapKind = OMPC_DEFAULTMAP_aggregate;
19067 else
19068 DSAStack->setDefaultDSAVCAggregate(VCKindLoc);
19069 break;
19070 case OMPC_DEFAULT_VC_pointer:
19071 if (IsTargetDefault)
19072 DefMapKind = OMPC_DEFAULTMAP_pointer;
19073 else
19074 DSAStack->setDefaultDSAVCPointer(VCKindLoc);
19075 break;
19076 case OMPC_DEFAULT_VC_scalar:
19077 if (IsTargetDefault)
19078 DefMapKind = OMPC_DEFAULTMAP_scalar;
19079 else
19080 DSAStack->setDefaultDSAVCScalar(VCKindLoc);
19081 break;
19082 case OMPC_DEFAULT_VC_all:
19083 if (IsTargetDefault)
19084 DefMapKind = OMPC_DEFAULTMAP_all;
19085 else
19086 DSAStack->setDefaultDSAVCAll(VCKindLoc);
19087 break;
19088 default:
19089 llvm_unreachable("unexpected variable category in OpenMP default clause");
19090 }
19091 // OpenMP 6.0, page 224, lines 4-5 default Clause, Semantics
19092 // otherwise, its effect on a target construct is equivalent to
19093 // specifying the defaultmap clause with the same data-sharing-attribute
19094 // and variable-category.
19095 //
19096 // If earlier than OpenMP 6.0, or not a target directive, the default DSA
19097 // is/was set as before.
19098 if (IsTargetDefault) {
19099 if (DefMapKind == OMPC_DEFAULTMAP_all) {
19100 DSAStack->setDefaultDMAAttr(M: DefMapMod, Kind: OMPC_DEFAULTMAP_aggregate, Loc: MLoc);
19101 DSAStack->setDefaultDMAAttr(M: DefMapMod, Kind: OMPC_DEFAULTMAP_scalar, Loc: MLoc);
19102 DSAStack->setDefaultDMAAttr(M: DefMapMod, Kind: OMPC_DEFAULTMAP_pointer, Loc: MLoc);
19103 } else {
19104 DSAStack->setDefaultDMAAttr(M: DefMapMod, Kind: DefMapKind, Loc: MLoc);
19105 }
19106 }
19107 };
19108
19109 SetDefaultClauseAttrs(M, VCKind);
19110 return new (getASTContext())
19111 OMPDefaultClause(M, MLoc, VCKind, VCKindLoc, StartLoc, LParenLoc, EndLoc);
19112}
19113
19114OMPClause *SemaOpenMP::ActOnOpenMPThreadsetClause(OpenMPThreadsetKind Kind,
19115 SourceLocation KindLoc,
19116 SourceLocation StartLoc,
19117 SourceLocation LParenLoc,
19118 SourceLocation EndLoc) {
19119 if (Kind == OMPC_THREADSET_unknown) {
19120 Diag(Loc: KindLoc, DiagID: diag::err_omp_unexpected_clause_value)
19121 << getListOfPossibleValues(K: OMPC_threadset, /*First=*/0,
19122 /*Last=*/unsigned(OMPC_THREADSET_unknown))
19123 << getOpenMPClauseName(C: OMPC_threadset);
19124 return nullptr;
19125 }
19126
19127 return new (getASTContext())
19128 OMPThreadsetClause(Kind, KindLoc, StartLoc, LParenLoc, EndLoc);
19129}
19130
19131static OMPClause *
19132createTransparentClause(Sema &SemaRef, ASTContext &Ctx, Expr *ImpexTypeArg,
19133 Stmt *HelperValStmt, OpenMPDirectiveKind CaptureRegion,
19134 SourceLocation StartLoc, SourceLocation LParenLoc,
19135 SourceLocation EndLoc) {
19136 ExprResult ER = SemaRef.DefaultLvalueConversion(E: ImpexTypeArg);
19137 if (ER.isInvalid())
19138 return nullptr;
19139
19140 return new (Ctx) OMPTransparentClause(ER.get(), HelperValStmt, CaptureRegion,
19141 StartLoc, LParenLoc, EndLoc);
19142}
19143
19144OMPClause *SemaOpenMP::ActOnOpenMPTransparentClause(Expr *ImpexTypeArg,
19145 SourceLocation StartLoc,
19146 SourceLocation LParenLoc,
19147 SourceLocation EndLoc) {
19148 Stmt *HelperValStmt = nullptr;
19149 OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
19150 OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause(
19151 DKind, CKind: OMPC_transparent, OMPVersion: getLangOpts().getOpenMPVersion());
19152 if (CaptureRegion != OMPD_unknown &&
19153 !SemaRef.CurContext->isDependentContext()) {
19154 Expr *ValExpr = SemaRef.MakeFullExpr(Arg: ImpexTypeArg).get();
19155 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
19156 ValExpr = tryBuildCapture(SemaRef, Capture: ValExpr, Captures).get();
19157 HelperValStmt = buildPreInits(Context&: getASTContext(), Captures);
19158 }
19159 if (!ImpexTypeArg) {
19160 return new (getASTContext())
19161 OMPTransparentClause(ImpexTypeArg, HelperValStmt, CaptureRegion,
19162 StartLoc, LParenLoc, EndLoc);
19163 }
19164 QualType Ty = ImpexTypeArg->getType();
19165
19166 if (const auto *TT = Ty->getAs<TypedefType>()) {
19167 const TypedefNameDecl *TypedefDecl = TT->getDecl();
19168 llvm::StringRef TypedefName = TypedefDecl->getName();
19169 IdentifierInfo &II = SemaRef.PP.getIdentifierTable().get(Name: TypedefName);
19170 ParsedType ImpexTy =
19171 SemaRef.getTypeName(II, NameLoc: StartLoc, S: SemaRef.getCurScope());
19172 if (!ImpexTy.getAsOpaquePtr() || ImpexTy.get().isNull()) {
19173 SemaRef.Diag(Loc: StartLoc, DiagID: diag::err_omp_implied_type_not_found)
19174 << TypedefName;
19175 return nullptr;
19176 }
19177 return new (getASTContext())
19178 OMPTransparentClause(ImpexTypeArg, HelperValStmt, CaptureRegion,
19179 StartLoc, LParenLoc, EndLoc);
19180 }
19181
19182 if (Ty->isEnumeralType())
19183 return createTransparentClause(SemaRef, Ctx&: getASTContext(), ImpexTypeArg,
19184 HelperValStmt, CaptureRegion, StartLoc,
19185 LParenLoc, EndLoc);
19186 if (Ty->isIntegerType()) {
19187 if (isNonNegativeIntegerValue(ValExpr&: ImpexTypeArg, SemaRef, CKind: OMPC_transparent,
19188 /*StrictlyPositive=*/false)) {
19189 ExprResult Value =
19190 SemaRef.OpenMP().PerformOpenMPImplicitIntegerConversion(Loc: StartLoc,
19191 Op: ImpexTypeArg);
19192 if (std::optional<llvm::APSInt> Result =
19193 Value.get()->getIntegerConstantExpr(Ctx: SemaRef.Context)) {
19194 if (Result->isNegative() ||
19195 Result >
19196 static_cast<int64_t>(SemaOpenMP::OpenMPImpexType::OMP_Export))
19197 SemaRef.Diag(Loc: StartLoc, DiagID: diag::err_omp_transparent_invalid_value);
19198 }
19199 return new (getASTContext())
19200 OMPTransparentClause(ImpexTypeArg, HelperValStmt, CaptureRegion,
19201 StartLoc, LParenLoc, EndLoc);
19202 }
19203 }
19204 if (!isNonNegativeIntegerValue(ValExpr&: ImpexTypeArg, SemaRef, CKind: OMPC_transparent,
19205 /*StrictlyPositive=*/true))
19206 return nullptr;
19207 return new (getASTContext()) OMPTransparentClause(
19208 ImpexTypeArg, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
19209}
19210
19211OMPClause *SemaOpenMP::ActOnOpenMPProcBindClause(ProcBindKind Kind,
19212 SourceLocation KindKwLoc,
19213 SourceLocation StartLoc,
19214 SourceLocation LParenLoc,
19215 SourceLocation EndLoc) {
19216 if (Kind == OMP_PROC_BIND_unknown) {
19217 Diag(Loc: KindKwLoc, DiagID: diag::err_omp_unexpected_clause_value)
19218 << getListOfPossibleValues(K: OMPC_proc_bind,
19219 /*First=*/unsigned(OMP_PROC_BIND_master),
19220 /*Last=*/
19221 unsigned(getLangOpts().OpenMP > 50
19222 ? OMP_PROC_BIND_primary
19223 : OMP_PROC_BIND_spread) +
19224 1)
19225 << getOpenMPClauseNameForDiag(C: OMPC_proc_bind);
19226 return nullptr;
19227 }
19228 if (Kind == OMP_PROC_BIND_primary && getLangOpts().OpenMP < 51)
19229 Diag(Loc: KindKwLoc, DiagID: diag::err_omp_unexpected_clause_value)
19230 << getListOfPossibleValues(K: OMPC_proc_bind,
19231 /*First=*/unsigned(OMP_PROC_BIND_master),
19232 /*Last=*/
19233 unsigned(OMP_PROC_BIND_spread) + 1)
19234 << getOpenMPClauseNameForDiag(C: OMPC_proc_bind);
19235 return new (getASTContext())
19236 OMPProcBindClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
19237}
19238
19239OMPClause *SemaOpenMP::ActOnOpenMPAtomicDefaultMemOrderClause(
19240 OpenMPAtomicDefaultMemOrderClauseKind Kind, SourceLocation KindKwLoc,
19241 SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) {
19242 if (Kind == OMPC_ATOMIC_DEFAULT_MEM_ORDER_unknown) {
19243 Diag(Loc: KindKwLoc, DiagID: diag::err_omp_unexpected_clause_value)
19244 << getListOfPossibleValues(
19245 K: OMPC_atomic_default_mem_order, /*First=*/0,
19246 /*Last=*/OMPC_ATOMIC_DEFAULT_MEM_ORDER_unknown)
19247 << getOpenMPClauseNameForDiag(C: OMPC_atomic_default_mem_order);
19248 return nullptr;
19249 }
19250 return new (getASTContext()) OMPAtomicDefaultMemOrderClause(
19251 Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
19252}
19253
19254OMPClause *SemaOpenMP::ActOnOpenMPAtClause(OpenMPAtClauseKind Kind,
19255 SourceLocation KindKwLoc,
19256 SourceLocation StartLoc,
19257 SourceLocation LParenLoc,
19258 SourceLocation EndLoc) {
19259 if (Kind == OMPC_AT_unknown) {
19260 Diag(Loc: KindKwLoc, DiagID: diag::err_omp_unexpected_clause_value)
19261 << getListOfPossibleValues(K: OMPC_at, /*First=*/0,
19262 /*Last=*/OMPC_AT_unknown)
19263 << getOpenMPClauseNameForDiag(C: OMPC_at);
19264 return nullptr;
19265 }
19266 return new (getASTContext())
19267 OMPAtClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
19268}
19269
19270OMPClause *SemaOpenMP::ActOnOpenMPSeverityClause(OpenMPSeverityClauseKind Kind,
19271 SourceLocation KindKwLoc,
19272 SourceLocation StartLoc,
19273 SourceLocation LParenLoc,
19274 SourceLocation EndLoc) {
19275 if (Kind == OMPC_SEVERITY_unknown) {
19276 Diag(Loc: KindKwLoc, DiagID: diag::err_omp_unexpected_clause_value)
19277 << getListOfPossibleValues(K: OMPC_severity, /*First=*/0,
19278 /*Last=*/OMPC_SEVERITY_unknown)
19279 << getOpenMPClauseNameForDiag(C: OMPC_severity);
19280 return nullptr;
19281 }
19282 return new (getASTContext())
19283 OMPSeverityClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
19284}
19285
19286OMPClause *SemaOpenMP::ActOnOpenMPMessageClause(Expr *ME,
19287 SourceLocation StartLoc,
19288 SourceLocation LParenLoc,
19289 SourceLocation EndLoc) {
19290 assert(ME && "NULL expr in Message clause");
19291 QualType Type = ME->getType();
19292 if ((!Type->isPointerType() && !Type->isArrayType()) ||
19293 !Type->getPointeeOrArrayElementType()->isAnyCharacterType()) {
19294 Diag(Loc: ME->getBeginLoc(), DiagID: diag::warn_clause_expected_string)
19295 << getOpenMPClauseNameForDiag(C: OMPC_message) << 0;
19296 return nullptr;
19297 }
19298
19299 Stmt *HelperValStmt = nullptr;
19300
19301 // Depending on whether this clause appears in an executable context or not,
19302 // we may or may not build a capture.
19303 OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
19304 OpenMPDirectiveKind CaptureRegion =
19305 DKind == OMPD_unknown
19306 ? OMPD_unknown
19307 : getOpenMPCaptureRegionForClause(DKind, CKind: OMPC_message,
19308 OMPVersion: getLangOpts().getOpenMPVersion());
19309 if (CaptureRegion != OMPD_unknown &&
19310 !SemaRef.CurContext->isDependentContext()) {
19311 ME = SemaRef.MakeFullExpr(Arg: ME).get();
19312 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
19313 ME = tryBuildCapture(SemaRef, Capture: ME, Captures).get();
19314 HelperValStmt = buildPreInits(Context&: getASTContext(), Captures);
19315 }
19316
19317 // Convert array type to pointer type if needed.
19318 ME = SemaRef.DefaultFunctionArrayLvalueConversion(E: ME).get();
19319
19320 return new (getASTContext()) OMPMessageClause(
19321 ME, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
19322}
19323
19324OMPClause *SemaOpenMP::ActOnOpenMPOrderClause(
19325 OpenMPOrderClauseModifier Modifier, OpenMPOrderClauseKind Kind,
19326 SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc,
19327 SourceLocation KindLoc, SourceLocation EndLoc) {
19328 if (Kind != OMPC_ORDER_concurrent ||
19329 (getLangOpts().OpenMP < 51 && MLoc.isValid())) {
19330 // Kind should be concurrent,
19331 // Modifiers introduced in OpenMP 5.1
19332 static_assert(OMPC_ORDER_unknown > 0,
19333 "OMPC_ORDER_unknown not greater than 0");
19334
19335 Diag(Loc: KindLoc, DiagID: diag::err_omp_unexpected_clause_value)
19336 << getListOfPossibleValues(K: OMPC_order,
19337 /*First=*/0,
19338 /*Last=*/OMPC_ORDER_unknown)
19339 << getOpenMPClauseNameForDiag(C: OMPC_order);
19340 return nullptr;
19341 }
19342 if (getLangOpts().OpenMP >= 51 && Modifier == OMPC_ORDER_MODIFIER_unknown &&
19343 MLoc.isValid()) {
19344 Diag(Loc: MLoc, DiagID: diag::err_omp_unexpected_clause_value)
19345 << getListOfPossibleValues(K: OMPC_order,
19346 /*First=*/OMPC_ORDER_MODIFIER_unknown + 1,
19347 /*Last=*/OMPC_ORDER_MODIFIER_last)
19348 << getOpenMPClauseNameForDiag(C: OMPC_order);
19349 } else if (getLangOpts().OpenMP >= 50) {
19350 DSAStack->setRegionHasOrderConcurrent(/*HasOrderConcurrent=*/true);
19351 if (DSAStack->getCurScope()) {
19352 // mark the current scope with 'order' flag
19353 unsigned existingFlags = DSAStack->getCurScope()->getFlags();
19354 DSAStack->getCurScope()->setFlags(existingFlags |
19355 Scope::OpenMPOrderClauseScope);
19356 }
19357 }
19358 return new (getASTContext()) OMPOrderClause(
19359 Kind, KindLoc, StartLoc, LParenLoc, EndLoc, Modifier, MLoc);
19360}
19361
19362OMPClause *SemaOpenMP::ActOnOpenMPUpdateDependObjectsClause(
19363 OpenMPDependClauseKind Kind, SourceLocation KindKwLoc,
19364 SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) {
19365 if (Kind == OMPC_DEPEND_unknown || Kind == OMPC_DEPEND_source ||
19366 Kind == OMPC_DEPEND_sink || Kind == OMPC_DEPEND_depobj) {
19367 SmallVector<unsigned> Except = {
19368 OMPC_DEPEND_source, OMPC_DEPEND_sink, OMPC_DEPEND_depobj,
19369 OMPC_DEPEND_outallmemory, OMPC_DEPEND_inoutallmemory};
19370 if (getLangOpts().OpenMP < 51)
19371 Except.push_back(Elt: OMPC_DEPEND_inoutset);
19372 Diag(Loc: KindKwLoc, DiagID: diag::err_omp_unexpected_clause_value)
19373 << getListOfPossibleValues(K: OMPC_depend, /*First=*/0,
19374 /*Last=*/OMPC_DEPEND_unknown, Exclude: Except)
19375 << getOpenMPClauseNameForDiag(C: OMPC_update_depend_objects);
19376 return nullptr;
19377 }
19378 return OMPUpdateDependObjectsClause::Create(
19379 C: getASTContext(), StartLoc, LParenLoc, ArgumentLoc: KindKwLoc, DK: Kind, EndLoc);
19380}
19381
19382OMPClause *SemaOpenMP::ActOnOpenMPSizesClause(ArrayRef<Expr *> SizeExprs,
19383 SourceLocation StartLoc,
19384 SourceLocation LParenLoc,
19385 SourceLocation EndLoc) {
19386 SmallVector<Expr *> SanitizedSizeExprs(SizeExprs);
19387
19388 for (Expr *&SizeExpr : SanitizedSizeExprs) {
19389 // Skip if already sanitized, e.g. during a partial template instantiation.
19390 if (!SizeExpr)
19391 continue;
19392
19393 bool IsValid = isNonNegativeIntegerValue(ValExpr&: SizeExpr, SemaRef, CKind: OMPC_sizes,
19394 /*StrictlyPositive=*/true);
19395
19396 // isNonNegativeIntegerValue returns true for non-integral types (but still
19397 // emits error diagnostic), so check for the expected type explicitly.
19398 QualType SizeTy = SizeExpr->getType();
19399 if (!SizeTy->isIntegerType())
19400 IsValid = false;
19401
19402 // Handling in templates is tricky. There are four possibilities to
19403 // consider:
19404 //
19405 // 1a. The expression is valid and we are in a instantiated template or not
19406 // in a template:
19407 // Pass valid expression to be further analysed later in Sema.
19408 // 1b. The expression is valid and we are in a template (including partial
19409 // instantiation):
19410 // isNonNegativeIntegerValue skipped any checks so there is no
19411 // guarantee it will be correct after instantiation.
19412 // ActOnOpenMPSizesClause will be called again at instantiation when
19413 // it is not in a dependent context anymore. This may cause warnings
19414 // to be emitted multiple times.
19415 // 2a. The expression is invalid and we are in an instantiated template or
19416 // not in a template:
19417 // Invalidate the expression with a clearly wrong value (nullptr) so
19418 // later in Sema we do not have to do the same validity analysis again
19419 // or crash from unexpected data. Error diagnostics have already been
19420 // emitted.
19421 // 2b. The expression is invalid and we are in a template (including partial
19422 // instantiation):
19423 // Pass the invalid expression as-is, template instantiation may
19424 // replace unexpected types/values with valid ones. The directives
19425 // with this clause must not try to use these expressions in dependent
19426 // contexts, but delay analysis until full instantiation.
19427 if (!SizeExpr->isInstantiationDependent() && !IsValid)
19428 SizeExpr = nullptr;
19429 }
19430
19431 return OMPSizesClause::Create(C: getASTContext(), StartLoc, LParenLoc, EndLoc,
19432 Sizes: SanitizedSizeExprs);
19433}
19434
19435OMPClause *SemaOpenMP::ActOnOpenMPCountsClause(ArrayRef<Expr *> CountExprs,
19436 SourceLocation StartLoc,
19437 SourceLocation LParenLoc,
19438 SourceLocation EndLoc,
19439 std::optional<unsigned> FillIdx,
19440 SourceLocation FillLoc,
19441 unsigned FillCount) {
19442 SmallVector<Expr *> SanitizedCountExprs(CountExprs);
19443
19444 // OpenMP 6.0: each list item in counts(...) is either the omp_fill keyword
19445 // or an integral constant expression (non-negative). Runtime variables are
19446 // not permitted; this matches split codegen, which needs segment sizes at
19447 // compile time.
19448 for (unsigned I = 0; I < SanitizedCountExprs.size(); ++I) {
19449 Expr *&CountExpr = SanitizedCountExprs[I];
19450 if (FillIdx && I == *FillIdx)
19451 continue;
19452 if (!CountExpr)
19453 continue;
19454
19455 ExprResult Verified = VerifyPositiveIntegerConstantInClause(
19456 E: CountExpr, CKind: OMPC_counts, /*StrictlyPositive=*/false);
19457 if (Verified.isInvalid())
19458 CountExpr = nullptr;
19459 else
19460 CountExpr = Verified.get();
19461 }
19462
19463 if (FillCount != 1) {
19464 Diag(Loc: FillCount == 0 ? StartLoc : FillLoc,
19465 DiagID: diag::err_omp_split_counts_not_one_omp_fill);
19466 }
19467
19468 return OMPCountsClause::Create(C: getASTContext(), StartLoc, LParenLoc, EndLoc,
19469 Counts: SanitizedCountExprs, FillIdx, FillLoc);
19470}
19471
19472OMPClause *SemaOpenMP::ActOnOpenMPPermutationClause(ArrayRef<Expr *> PermExprs,
19473 SourceLocation StartLoc,
19474 SourceLocation LParenLoc,
19475 SourceLocation EndLoc) {
19476 size_t NumLoops = PermExprs.size();
19477 SmallVector<Expr *> SanitizedPermExprs;
19478 llvm::append_range(C&: SanitizedPermExprs, R&: PermExprs);
19479
19480 for (Expr *&PermExpr : SanitizedPermExprs) {
19481 // Skip if template-dependent or already sanitized, e.g. during a partial
19482 // template instantiation.
19483 if (!PermExpr || PermExpr->isInstantiationDependent())
19484 continue;
19485
19486 llvm::APSInt PermVal;
19487 ExprResult PermEvalExpr = SemaRef.VerifyIntegerConstantExpression(
19488 E: PermExpr, Result: &PermVal, CanFold: AllowFoldKind::Allow);
19489 bool IsValid = PermEvalExpr.isUsable();
19490 if (IsValid)
19491 PermExpr = PermEvalExpr.get();
19492
19493 if (IsValid && (PermVal < 1 || NumLoops < PermVal)) {
19494 SourceRange ExprRange(PermEvalExpr.get()->getBeginLoc(),
19495 PermEvalExpr.get()->getEndLoc());
19496 Diag(Loc: PermEvalExpr.get()->getExprLoc(),
19497 DiagID: diag::err_omp_interchange_permutation_value_range)
19498 << NumLoops << ExprRange;
19499 IsValid = false;
19500 }
19501
19502 if (!PermExpr->isInstantiationDependent() && !IsValid)
19503 PermExpr = nullptr;
19504 }
19505
19506 return OMPPermutationClause::Create(C: getASTContext(), StartLoc, LParenLoc,
19507 EndLoc, Args: SanitizedPermExprs);
19508}
19509
19510OMPClause *SemaOpenMP::ActOnOpenMPFullClause(SourceLocation StartLoc,
19511 SourceLocation EndLoc) {
19512 return new (getASTContext()) OMPFullClause(StartLoc, EndLoc);
19513}
19514
19515OMPClause *SemaOpenMP::ActOnOpenMPPartialClause(Expr *FactorExpr,
19516 SourceLocation StartLoc,
19517 SourceLocation LParenLoc,
19518 SourceLocation EndLoc) {
19519 if (FactorExpr) {
19520 // If an argument is specified, it must be a constant (or an unevaluated
19521 // template expression).
19522 ExprResult FactorResult = VerifyPositiveIntegerConstantInClause(
19523 E: FactorExpr, CKind: OMPC_partial, /*StrictlyPositive=*/true);
19524 if (FactorResult.isInvalid())
19525 return nullptr;
19526 FactorExpr = FactorResult.get();
19527 }
19528
19529 return new (getASTContext())
19530 OMPPartialClause(StartLoc, LParenLoc, EndLoc, FactorExpr);
19531}
19532
19533OMPClause *SemaOpenMP::ActOnOpenMPDepthClause(Expr *DepthExpr,
19534 SourceLocation StartLoc,
19535 SourceLocation LParenLoc,
19536 SourceLocation EndLoc) {
19537 // The depth-expr must be a positive integer constant expression and
19538 // not greater than the number of loops in the associated loop nest.
19539 ExprResult DepthResult = VerifyPositiveIntegerConstantInClause(
19540 E: DepthExpr, CKind: OMPC_depth, /*StrictlyPositive=*/true);
19541 if (DepthResult.isInvalid())
19542 return nullptr;
19543 DepthExpr = DepthResult.get();
19544
19545 return new (getASTContext())
19546 OMPDepthClause(StartLoc, LParenLoc, EndLoc, DepthExpr);
19547}
19548
19549OMPClause *SemaOpenMP::ActOnOpenMPLoopRangeClause(
19550 Expr *First, Expr *Count, SourceLocation StartLoc, SourceLocation LParenLoc,
19551 SourceLocation FirstLoc, SourceLocation CountLoc, SourceLocation EndLoc) {
19552
19553 // OpenMP [6.0, Restrictions]
19554 // First and Count must be integer expressions with positive value
19555 ExprResult FirstVal =
19556 VerifyPositiveIntegerConstantInClause(E: First, CKind: OMPC_looprange);
19557 if (FirstVal.isInvalid())
19558 First = nullptr;
19559
19560 ExprResult CountVal =
19561 VerifyPositiveIntegerConstantInClause(E: Count, CKind: OMPC_looprange);
19562 if (CountVal.isInvalid())
19563 Count = nullptr;
19564
19565 // OpenMP [6.0, Restrictions]
19566 // first + count - 1 must not evaluate to a value greater than the
19567 // loop sequence length of the associated canonical loop sequence.
19568 // This check must be performed afterwards due to the delayed
19569 // parsing and computation of the associated loop sequence
19570 return new (getASTContext()) OMPLoopRangeClause(
19571 StartLoc, LParenLoc, FirstLoc, CountLoc, EndLoc, First, Count);
19572}
19573
19574OMPClause *SemaOpenMP::ActOnOpenMPAlignClause(Expr *A, SourceLocation StartLoc,
19575 SourceLocation LParenLoc,
19576 SourceLocation EndLoc) {
19577 ExprResult AlignVal;
19578 AlignVal = VerifyPositiveIntegerConstantInClause(E: A, CKind: OMPC_align);
19579 if (AlignVal.isInvalid())
19580 return nullptr;
19581 return new (getASTContext())
19582 OMPAlignClause(AlignVal.get(), StartLoc, LParenLoc, EndLoc);
19583}
19584
19585OMPClause *SemaOpenMP::ActOnOpenMPSingleExprWithArgClause(
19586 OpenMPClauseKind Kind, ArrayRef<unsigned> Argument, Expr *Expr,
19587 SourceLocation StartLoc, SourceLocation LParenLoc,
19588 ArrayRef<SourceLocation> ArgumentLoc, SourceLocation DelimLoc,
19589 SourceLocation EndLoc) {
19590 OMPClause *Res = nullptr;
19591 switch (Kind) {
19592 case OMPC_schedule: {
19593 enum { Modifier1, Modifier2, ScheduleKind, NumberOfElements };
19594 assert(Argument.size() == NumberOfElements &&
19595 ArgumentLoc.size() == NumberOfElements);
19596 Res = ActOnOpenMPScheduleClause(
19597 M1: static_cast<OpenMPScheduleClauseModifier>(Argument[Modifier1]),
19598 M2: static_cast<OpenMPScheduleClauseModifier>(Argument[Modifier2]),
19599 Kind: static_cast<OpenMPScheduleClauseKind>(Argument[ScheduleKind]), ChunkSize: Expr,
19600 StartLoc, LParenLoc, M1Loc: ArgumentLoc[Modifier1], M2Loc: ArgumentLoc[Modifier2],
19601 KindLoc: ArgumentLoc[ScheduleKind], CommaLoc: DelimLoc, EndLoc);
19602 break;
19603 }
19604 case OMPC_if:
19605 assert(Argument.size() == 1 && ArgumentLoc.size() == 1);
19606 Res = ActOnOpenMPIfClause(NameModifier: static_cast<OpenMPDirectiveKind>(Argument.back()),
19607 Condition: Expr, StartLoc, LParenLoc, NameModifierLoc: ArgumentLoc.back(),
19608 ColonLoc: DelimLoc, EndLoc);
19609 break;
19610 case OMPC_dist_schedule:
19611 Res = ActOnOpenMPDistScheduleClause(
19612 Kind: static_cast<OpenMPDistScheduleClauseKind>(Argument.back()), ChunkSize: Expr,
19613 StartLoc, LParenLoc, KindLoc: ArgumentLoc.back(), CommaLoc: DelimLoc, EndLoc);
19614 break;
19615 case OMPC_default:
19616 enum { DefaultModifier, DefaultVarCategory };
19617 Res = ActOnOpenMPDefaultClause(
19618 M: static_cast<llvm::omp::DefaultKind>(Argument[DefaultModifier]),
19619 MLoc: ArgumentLoc[DefaultModifier],
19620 VCKind: static_cast<OpenMPDefaultClauseVariableCategory>(
19621 Argument[DefaultVarCategory]),
19622 VCKindLoc: ArgumentLoc[DefaultVarCategory], StartLoc, LParenLoc, EndLoc);
19623 break;
19624 case OMPC_defaultmap:
19625 enum { Modifier, DefaultmapKind };
19626 Res = ActOnOpenMPDefaultmapClause(
19627 M: static_cast<OpenMPDefaultmapClauseModifier>(Argument[Modifier]),
19628 Kind: static_cast<OpenMPDefaultmapClauseKind>(Argument[DefaultmapKind]),
19629 StartLoc, LParenLoc, MLoc: ArgumentLoc[Modifier], KindLoc: ArgumentLoc[DefaultmapKind],
19630 EndLoc);
19631 break;
19632 case OMPC_order:
19633 enum { OrderModifier, OrderKind };
19634 Res = ActOnOpenMPOrderClause(
19635 Modifier: static_cast<OpenMPOrderClauseModifier>(Argument[OrderModifier]),
19636 Kind: static_cast<OpenMPOrderClauseKind>(Argument[OrderKind]), StartLoc,
19637 LParenLoc, MLoc: ArgumentLoc[OrderModifier], KindLoc: ArgumentLoc[OrderKind], EndLoc);
19638 break;
19639 case OMPC_device:
19640 assert(Argument.size() == 1 && ArgumentLoc.size() == 1);
19641 Res = ActOnOpenMPDeviceClause(
19642 Modifier: static_cast<OpenMPDeviceClauseModifier>(Argument.back()), Device: Expr,
19643 StartLoc, LParenLoc, ModifierLoc: ArgumentLoc.back(), EndLoc);
19644 break;
19645 case OMPC_grainsize:
19646 assert(Argument.size() == 1 && ArgumentLoc.size() == 1 &&
19647 "Modifier for grainsize clause and its location are expected.");
19648 Res = ActOnOpenMPGrainsizeClause(
19649 Modifier: static_cast<OpenMPGrainsizeClauseModifier>(Argument.back()), Size: Expr,
19650 StartLoc, LParenLoc, ModifierLoc: ArgumentLoc.back(), EndLoc);
19651 break;
19652 case OMPC_num_tasks:
19653 assert(Argument.size() == 1 && ArgumentLoc.size() == 1 &&
19654 "Modifier for num_tasks clause and its location are expected.");
19655 Res = ActOnOpenMPNumTasksClause(
19656 Modifier: static_cast<OpenMPNumTasksClauseModifier>(Argument.back()), NumTasks: Expr,
19657 StartLoc, LParenLoc, ModifierLoc: ArgumentLoc.back(), EndLoc);
19658 break;
19659 case OMPC_dyn_groupprivate: {
19660 enum { Modifier1, Modifier2, NumberOfElements };
19661 assert(Argument.size() == NumberOfElements &&
19662 ArgumentLoc.size() == NumberOfElements &&
19663 "Modifiers for dyn_groupprivate clause and their locations are "
19664 "expected.");
19665 Res = ActOnOpenMPDynGroupprivateClause(
19666 M1: static_cast<OpenMPDynGroupprivateClauseModifier>(Argument[Modifier1]),
19667 M2: static_cast<OpenMPDynGroupprivateClauseFallbackModifier>(
19668 Argument[Modifier2]),
19669 Size: Expr, StartLoc, LParenLoc, M1Loc: ArgumentLoc[Modifier1],
19670 M2Loc: ArgumentLoc[Modifier2], EndLoc);
19671 break;
19672 }
19673 case OMPC_final:
19674 case OMPC_safelen:
19675 case OMPC_simdlen:
19676 case OMPC_sizes:
19677 case OMPC_depth:
19678 case OMPC_allocator:
19679 case OMPC_collapse:
19680 case OMPC_proc_bind:
19681 case OMPC_private:
19682 case OMPC_firstprivate:
19683 case OMPC_lastprivate:
19684 case OMPC_shared:
19685 case OMPC_reduction:
19686 case OMPC_task_reduction:
19687 case OMPC_in_reduction:
19688 case OMPC_linear:
19689 case OMPC_aligned:
19690 case OMPC_copyin:
19691 case OMPC_copyprivate:
19692 case OMPC_ordered:
19693 case OMPC_nowait:
19694 case OMPC_untied:
19695 case OMPC_mergeable:
19696 case OMPC_threadprivate:
19697 case OMPC_groupprivate:
19698 case OMPC_allocate:
19699 case OMPC_flush:
19700 case OMPC_depobj:
19701 case OMPC_read:
19702 case OMPC_write:
19703 case OMPC_update:
19704 case OMPC_capture:
19705 case OMPC_compare:
19706 case OMPC_seq_cst:
19707 case OMPC_acq_rel:
19708 case OMPC_acquire:
19709 case OMPC_release:
19710 case OMPC_relaxed:
19711 case OMPC_depend:
19712 case OMPC_threads:
19713 case OMPC_simd:
19714 case OMPC_map:
19715 case OMPC_num_teams:
19716 case OMPC_thread_limit:
19717 case OMPC_priority:
19718 case OMPC_nogroup:
19719 case OMPC_hint:
19720 case OMPC_unknown:
19721 case OMPC_uniform:
19722 case OMPC_to:
19723 case OMPC_from:
19724 case OMPC_use_device_ptr:
19725 case OMPC_use_device_addr:
19726 case OMPC_is_device_ptr:
19727 case OMPC_has_device_addr:
19728 case OMPC_unified_address:
19729 case OMPC_unified_shared_memory:
19730 case OMPC_reverse_offload:
19731 case OMPC_dynamic_allocators:
19732 case OMPC_atomic_default_mem_order:
19733 case OMPC_self_maps:
19734 case OMPC_device_type:
19735 case OMPC_match:
19736 case OMPC_nontemporal:
19737 case OMPC_at:
19738 case OMPC_severity:
19739 case OMPC_message:
19740 case OMPC_destroy:
19741 case OMPC_novariants:
19742 case OMPC_nocontext:
19743 case OMPC_detach:
19744 case OMPC_inclusive:
19745 case OMPC_exclusive:
19746 case OMPC_uses_allocators:
19747 case OMPC_affinity:
19748 case OMPC_when:
19749 case OMPC_bind:
19750 default:
19751 llvm_unreachable("Clause is not allowed.");
19752 }
19753 return Res;
19754}
19755
19756static bool checkScheduleModifiers(Sema &S, OpenMPScheduleClauseModifier M1,
19757 OpenMPScheduleClauseModifier M2,
19758 SourceLocation M1Loc, SourceLocation M2Loc) {
19759 if (M1 == OMPC_SCHEDULE_MODIFIER_unknown && M1Loc.isValid()) {
19760 SmallVector<unsigned, 2> Excluded;
19761 if (M2 != OMPC_SCHEDULE_MODIFIER_unknown)
19762 Excluded.push_back(Elt: M2);
19763 if (M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic)
19764 Excluded.push_back(Elt: OMPC_SCHEDULE_MODIFIER_monotonic);
19765 if (M2 == OMPC_SCHEDULE_MODIFIER_monotonic)
19766 Excluded.push_back(Elt: OMPC_SCHEDULE_MODIFIER_nonmonotonic);
19767 S.Diag(Loc: M1Loc, DiagID: diag::err_omp_unexpected_clause_value)
19768 << getListOfPossibleValues(K: OMPC_schedule,
19769 /*First=*/OMPC_SCHEDULE_MODIFIER_unknown + 1,
19770 /*Last=*/OMPC_SCHEDULE_MODIFIER_last,
19771 Exclude: Excluded)
19772 << getOpenMPClauseNameForDiag(C: OMPC_schedule);
19773 return true;
19774 }
19775 return false;
19776}
19777
19778OMPClause *SemaOpenMP::ActOnOpenMPScheduleClause(
19779 OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2,
19780 OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc,
19781 SourceLocation LParenLoc, SourceLocation M1Loc, SourceLocation M2Loc,
19782 SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc) {
19783 if (checkScheduleModifiers(S&: SemaRef, M1, M2, M1Loc, M2Loc) ||
19784 checkScheduleModifiers(S&: SemaRef, M1: M2, M2: M1, M1Loc: M2Loc, M2Loc: M1Loc))
19785 return nullptr;
19786 // OpenMP, 2.7.1, Loop Construct, Restrictions
19787 // Either the monotonic modifier or the nonmonotonic modifier can be specified
19788 // but not both.
19789 if ((M1 == M2 && M1 != OMPC_SCHEDULE_MODIFIER_unknown) ||
19790 (M1 == OMPC_SCHEDULE_MODIFIER_monotonic &&
19791 M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic) ||
19792 (M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic &&
19793 M2 == OMPC_SCHEDULE_MODIFIER_monotonic)) {
19794 Diag(Loc: M2Loc, DiagID: diag::err_omp_unexpected_schedule_modifier)
19795 << getOpenMPSimpleClauseTypeName(Kind: OMPC_schedule, Type: M2)
19796 << getOpenMPSimpleClauseTypeName(Kind: OMPC_schedule, Type: M1);
19797 return nullptr;
19798 }
19799 if (Kind == OMPC_SCHEDULE_unknown) {
19800 std::string Values;
19801 if (M1Loc.isInvalid() && M2Loc.isInvalid()) {
19802 unsigned Exclude[] = {OMPC_SCHEDULE_unknown};
19803 Values = getListOfPossibleValues(K: OMPC_schedule, /*First=*/0,
19804 /*Last=*/OMPC_SCHEDULE_MODIFIER_last,
19805 Exclude);
19806 } else {
19807 Values = getListOfPossibleValues(K: OMPC_schedule, /*First=*/0,
19808 /*Last=*/OMPC_SCHEDULE_unknown);
19809 }
19810 Diag(Loc: KindLoc, DiagID: diag::err_omp_unexpected_clause_value)
19811 << Values << getOpenMPClauseNameForDiag(C: OMPC_schedule);
19812 return nullptr;
19813 }
19814 // OpenMP, 2.7.1, Loop Construct, Restrictions
19815 // The nonmonotonic modifier can only be specified with schedule(dynamic) or
19816 // schedule(guided).
19817 // OpenMP 5.0 does not have this restriction.
19818 if (getLangOpts().OpenMP < 50 &&
19819 (M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ||
19820 M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic) &&
19821 Kind != OMPC_SCHEDULE_dynamic && Kind != OMPC_SCHEDULE_guided) {
19822 Diag(Loc: M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ? M1Loc : M2Loc,
19823 DiagID: diag::err_omp_schedule_nonmonotonic_static);
19824 return nullptr;
19825 }
19826 Expr *ValExpr = ChunkSize;
19827 Stmt *HelperValStmt = nullptr;
19828 if (ChunkSize) {
19829 if (!ChunkSize->isValueDependent() && !ChunkSize->isTypeDependent() &&
19830 !ChunkSize->isInstantiationDependent() &&
19831 !ChunkSize->containsUnexpandedParameterPack()) {
19832 SourceLocation ChunkSizeLoc = ChunkSize->getBeginLoc();
19833 ExprResult Val =
19834 PerformOpenMPImplicitIntegerConversion(Loc: ChunkSizeLoc, Op: ChunkSize);
19835 if (Val.isInvalid())
19836 return nullptr;
19837
19838 ValExpr = Val.get();
19839
19840 // OpenMP [2.7.1, Restrictions]
19841 // chunk_size must be a loop invariant integer expression with a positive
19842 // value.
19843 if (std::optional<llvm::APSInt> Result =
19844 ValExpr->getIntegerConstantExpr(Ctx: getASTContext())) {
19845 if (Result->isSigned() && !Result->isStrictlyPositive()) {
19846 Diag(Loc: ChunkSizeLoc, DiagID: diag::err_omp_negative_expression_in_clause)
19847 << "schedule" << 1 << ChunkSize->getSourceRange();
19848 return nullptr;
19849 }
19850 } else if (getOpenMPCaptureRegionForClause(
19851 DSAStack->getCurrentDirective(), CKind: OMPC_schedule,
19852 OMPVersion: getLangOpts().getOpenMPVersion()) != OMPD_unknown &&
19853 !SemaRef.CurContext->isDependentContext()) {
19854 ValExpr = SemaRef.MakeFullExpr(Arg: ValExpr).get();
19855 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
19856 ValExpr = tryBuildCapture(SemaRef, Capture: ValExpr, Captures).get();
19857 HelperValStmt = buildPreInits(Context&: getASTContext(), Captures);
19858 }
19859 }
19860 }
19861
19862 return new (getASTContext())
19863 OMPScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc, Kind,
19864 ValExpr, HelperValStmt, M1, M1Loc, M2, M2Loc);
19865}
19866
19867OMPClause *SemaOpenMP::ActOnOpenMPClause(OpenMPClauseKind Kind,
19868 SourceLocation StartLoc,
19869 SourceLocation EndLoc) {
19870 OMPClause *Res = nullptr;
19871 switch (Kind) {
19872 case OMPC_ordered:
19873 Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc);
19874 break;
19875 case OMPC_nowait:
19876 Res = ActOnOpenMPNowaitClause(StartLoc, EndLoc,
19877 /*LParenLoc=*/SourceLocation(),
19878 /*Condition=*/nullptr);
19879 break;
19880 case OMPC_untied:
19881 Res = ActOnOpenMPUntiedClause(StartLoc, EndLoc);
19882 break;
19883 case OMPC_mergeable:
19884 Res = ActOnOpenMPMergeableClause(StartLoc, EndLoc);
19885 break;
19886 case OMPC_read:
19887 Res = ActOnOpenMPReadClause(StartLoc, EndLoc);
19888 break;
19889 case OMPC_write:
19890 Res = ActOnOpenMPWriteClause(StartLoc, EndLoc);
19891 break;
19892 case OMPC_update:
19893 Res = ActOnOpenMPUpdateClause(StartLoc, EndLoc);
19894 break;
19895 case OMPC_capture:
19896 Res = ActOnOpenMPCaptureClause(StartLoc, EndLoc);
19897 break;
19898 case OMPC_compare:
19899 Res = ActOnOpenMPCompareClause(StartLoc, EndLoc);
19900 break;
19901 case OMPC_fail:
19902 Res = ActOnOpenMPFailClause(StartLoc, EndLoc);
19903 break;
19904 case OMPC_seq_cst:
19905 Res = ActOnOpenMPSeqCstClause(StartLoc, EndLoc);
19906 break;
19907 case OMPC_acq_rel:
19908 Res = ActOnOpenMPAcqRelClause(StartLoc, EndLoc);
19909 break;
19910 case OMPC_acquire:
19911 Res = ActOnOpenMPAcquireClause(StartLoc, EndLoc);
19912 break;
19913 case OMPC_release:
19914 Res = ActOnOpenMPReleaseClause(StartLoc, EndLoc);
19915 break;
19916 case OMPC_relaxed:
19917 Res = ActOnOpenMPRelaxedClause(StartLoc, EndLoc);
19918 break;
19919 case OMPC_weak:
19920 Res = ActOnOpenMPWeakClause(StartLoc, EndLoc);
19921 break;
19922 case OMPC_threads:
19923 Res = ActOnOpenMPThreadsClause(StartLoc, EndLoc);
19924 break;
19925 case OMPC_simd:
19926 Res = ActOnOpenMPSIMDClause(StartLoc, EndLoc);
19927 break;
19928 case OMPC_nogroup:
19929 Res = ActOnOpenMPNogroupClause(StartLoc, EndLoc);
19930 break;
19931 case OMPC_unified_address:
19932 Res = ActOnOpenMPUnifiedAddressClause(StartLoc, EndLoc);
19933 break;
19934 case OMPC_unified_shared_memory:
19935 Res = ActOnOpenMPUnifiedSharedMemoryClause(StartLoc, EndLoc);
19936 break;
19937 case OMPC_reverse_offload:
19938 Res = ActOnOpenMPReverseOffloadClause(StartLoc, EndLoc);
19939 break;
19940 case OMPC_dynamic_allocators:
19941 Res = ActOnOpenMPDynamicAllocatorsClause(StartLoc, EndLoc);
19942 break;
19943 case OMPC_self_maps:
19944 Res = ActOnOpenMPSelfMapsClause(StartLoc, EndLoc);
19945 break;
19946 case OMPC_destroy:
19947 Res = ActOnOpenMPDestroyClause(/*InteropVar=*/nullptr, StartLoc,
19948 /*LParenLoc=*/SourceLocation(),
19949 /*VarLoc=*/SourceLocation(), EndLoc);
19950 break;
19951 case OMPC_full:
19952 Res = ActOnOpenMPFullClause(StartLoc, EndLoc);
19953 break;
19954 case OMPC_partial:
19955 Res = ActOnOpenMPPartialClause(FactorExpr: nullptr, StartLoc, /*LParenLoc=*/{}, EndLoc);
19956 break;
19957 case OMPC_ompx_bare:
19958 Res = ActOnOpenMPXBareClause(StartLoc, EndLoc);
19959 break;
19960 case OMPC_if:
19961 case OMPC_final:
19962 case OMPC_num_threads:
19963 case OMPC_safelen:
19964 case OMPC_simdlen:
19965 case OMPC_sizes:
19966 case OMPC_depth:
19967 case OMPC_allocator:
19968 case OMPC_collapse:
19969 case OMPC_schedule:
19970 case OMPC_private:
19971 case OMPC_firstprivate:
19972 case OMPC_lastprivate:
19973 case OMPC_shared:
19974 case OMPC_reduction:
19975 case OMPC_task_reduction:
19976 case OMPC_in_reduction:
19977 case OMPC_linear:
19978 case OMPC_aligned:
19979 case OMPC_copyin:
19980 case OMPC_copyprivate:
19981 case OMPC_default:
19982 case OMPC_proc_bind:
19983 case OMPC_threadprivate:
19984 case OMPC_groupprivate:
19985 case OMPC_allocate:
19986 case OMPC_flush:
19987 case OMPC_depobj:
19988 case OMPC_depend:
19989 case OMPC_device:
19990 case OMPC_map:
19991 case OMPC_num_teams:
19992 case OMPC_thread_limit:
19993 case OMPC_priority:
19994 case OMPC_grainsize:
19995 case OMPC_num_tasks:
19996 case OMPC_hint:
19997 case OMPC_dist_schedule:
19998 case OMPC_defaultmap:
19999 case OMPC_unknown:
20000 case OMPC_uniform:
20001 case OMPC_to:
20002 case OMPC_from:
20003 case OMPC_use_device_ptr:
20004 case OMPC_use_device_addr:
20005 case OMPC_is_device_ptr:
20006 case OMPC_has_device_addr:
20007 case OMPC_atomic_default_mem_order:
20008 case OMPC_device_type:
20009 case OMPC_match:
20010 case OMPC_nontemporal:
20011 case OMPC_order:
20012 case OMPC_at:
20013 case OMPC_severity:
20014 case OMPC_message:
20015 case OMPC_novariants:
20016 case OMPC_nocontext:
20017 case OMPC_detach:
20018 case OMPC_inclusive:
20019 case OMPC_exclusive:
20020 case OMPC_uses_allocators:
20021 case OMPC_affinity:
20022 case OMPC_when:
20023 case OMPC_ompx_dyn_cgroup_mem:
20024 case OMPC_dyn_groupprivate:
20025 default:
20026 llvm_unreachable("Clause is not allowed.");
20027 }
20028 return Res;
20029}
20030
20031OMPClause *SemaOpenMP::ActOnOpenMPNowaitClause(SourceLocation StartLoc,
20032 SourceLocation EndLoc,
20033 SourceLocation LParenLoc,
20034 Expr *Condition) {
20035 Expr *ValExpr = Condition;
20036 if (Condition && LParenLoc.isValid()) {
20037 if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
20038 !Condition->isInstantiationDependent() &&
20039 !Condition->containsUnexpandedParameterPack()) {
20040 ExprResult Val = SemaRef.CheckBooleanCondition(Loc: StartLoc, E: Condition);
20041 if (Val.isInvalid())
20042 return nullptr;
20043
20044 ValExpr = Val.get();
20045 }
20046 }
20047 DSAStack->setNowaitRegion();
20048 return new (getASTContext())
20049 OMPNowaitClause(ValExpr, StartLoc, LParenLoc, EndLoc);
20050}
20051
20052OMPClause *SemaOpenMP::ActOnOpenMPUntiedClause(SourceLocation StartLoc,
20053 SourceLocation EndLoc) {
20054 DSAStack->setUntiedRegion();
20055 return new (getASTContext()) OMPUntiedClause(StartLoc, EndLoc);
20056}
20057
20058OMPClause *SemaOpenMP::ActOnOpenMPMergeableClause(SourceLocation StartLoc,
20059 SourceLocation EndLoc) {
20060 return new (getASTContext()) OMPMergeableClause(StartLoc, EndLoc);
20061}
20062
20063OMPClause *SemaOpenMP::ActOnOpenMPReadClause(SourceLocation StartLoc,
20064 SourceLocation EndLoc) {
20065 return new (getASTContext()) OMPReadClause(StartLoc, EndLoc);
20066}
20067
20068OMPClause *SemaOpenMP::ActOnOpenMPWriteClause(SourceLocation StartLoc,
20069 SourceLocation EndLoc) {
20070 return new (getASTContext()) OMPWriteClause(StartLoc, EndLoc);
20071}
20072
20073OMPClause *SemaOpenMP::ActOnOpenMPUpdateClause(SourceLocation StartLoc,
20074 SourceLocation EndLoc) {
20075 return new (getASTContext()) OMPUpdateClause(StartLoc, EndLoc);
20076}
20077
20078OMPClause *SemaOpenMP::ActOnOpenMPCaptureClause(SourceLocation StartLoc,
20079 SourceLocation EndLoc) {
20080 return new (getASTContext()) OMPCaptureClause(StartLoc, EndLoc);
20081}
20082
20083OMPClause *SemaOpenMP::ActOnOpenMPCompareClause(SourceLocation StartLoc,
20084 SourceLocation EndLoc) {
20085 return new (getASTContext()) OMPCompareClause(StartLoc, EndLoc);
20086}
20087
20088OMPClause *SemaOpenMP::ActOnOpenMPFailClause(SourceLocation StartLoc,
20089 SourceLocation EndLoc) {
20090 return new (getASTContext()) OMPFailClause(StartLoc, EndLoc);
20091}
20092
20093OMPClause *SemaOpenMP::ActOnOpenMPFailClause(OpenMPClauseKind Parameter,
20094 SourceLocation KindLoc,
20095 SourceLocation StartLoc,
20096 SourceLocation LParenLoc,
20097 SourceLocation EndLoc) {
20098
20099 if (!checkFailClauseParameter(FailClauseParameter: Parameter)) {
20100 Diag(Loc: KindLoc, DiagID: diag::err_omp_atomic_fail_wrong_or_no_clauses);
20101 return nullptr;
20102 }
20103 return new (getASTContext())
20104 OMPFailClause(Parameter, KindLoc, StartLoc, LParenLoc, EndLoc);
20105}
20106
20107OMPClause *SemaOpenMP::ActOnOpenMPSeqCstClause(SourceLocation StartLoc,
20108 SourceLocation EndLoc) {
20109 return new (getASTContext()) OMPSeqCstClause(StartLoc, EndLoc);
20110}
20111
20112OMPClause *SemaOpenMP::ActOnOpenMPAcqRelClause(SourceLocation StartLoc,
20113 SourceLocation EndLoc) {
20114 return new (getASTContext()) OMPAcqRelClause(StartLoc, EndLoc);
20115}
20116
20117OMPClause *SemaOpenMP::ActOnOpenMPAcquireClause(SourceLocation StartLoc,
20118 SourceLocation EndLoc) {
20119 return new (getASTContext()) OMPAcquireClause(StartLoc, EndLoc);
20120}
20121
20122OMPClause *SemaOpenMP::ActOnOpenMPReleaseClause(SourceLocation StartLoc,
20123 SourceLocation EndLoc) {
20124 return new (getASTContext()) OMPReleaseClause(StartLoc, EndLoc);
20125}
20126
20127OMPClause *SemaOpenMP::ActOnOpenMPRelaxedClause(SourceLocation StartLoc,
20128 SourceLocation EndLoc) {
20129 return new (getASTContext()) OMPRelaxedClause(StartLoc, EndLoc);
20130}
20131
20132OMPClause *SemaOpenMP::ActOnOpenMPWeakClause(SourceLocation StartLoc,
20133 SourceLocation EndLoc) {
20134 return new (getASTContext()) OMPWeakClause(StartLoc, EndLoc);
20135}
20136
20137OMPClause *SemaOpenMP::ActOnOpenMPThreadsClause(SourceLocation StartLoc,
20138 SourceLocation EndLoc) {
20139 return new (getASTContext()) OMPThreadsClause(StartLoc, EndLoc);
20140}
20141
20142OMPClause *SemaOpenMP::ActOnOpenMPSIMDClause(SourceLocation StartLoc,
20143 SourceLocation EndLoc) {
20144 return new (getASTContext()) OMPSIMDClause(StartLoc, EndLoc);
20145}
20146
20147OMPClause *SemaOpenMP::ActOnOpenMPNogroupClause(SourceLocation StartLoc,
20148 SourceLocation EndLoc) {
20149 return new (getASTContext()) OMPNogroupClause(StartLoc, EndLoc);
20150}
20151
20152OMPClause *SemaOpenMP::ActOnOpenMPUnifiedAddressClause(SourceLocation StartLoc,
20153 SourceLocation EndLoc) {
20154 return new (getASTContext()) OMPUnifiedAddressClause(StartLoc, EndLoc);
20155}
20156
20157OMPClause *
20158SemaOpenMP::ActOnOpenMPUnifiedSharedMemoryClause(SourceLocation StartLoc,
20159 SourceLocation EndLoc) {
20160 return new (getASTContext()) OMPUnifiedSharedMemoryClause(StartLoc, EndLoc);
20161}
20162
20163OMPClause *SemaOpenMP::ActOnOpenMPReverseOffloadClause(SourceLocation StartLoc,
20164 SourceLocation EndLoc) {
20165 return new (getASTContext()) OMPReverseOffloadClause(StartLoc, EndLoc);
20166}
20167
20168OMPClause *
20169SemaOpenMP::ActOnOpenMPDynamicAllocatorsClause(SourceLocation StartLoc,
20170 SourceLocation EndLoc) {
20171 return new (getASTContext()) OMPDynamicAllocatorsClause(StartLoc, EndLoc);
20172}
20173
20174OMPClause *SemaOpenMP::ActOnOpenMPSelfMapsClause(SourceLocation StartLoc,
20175 SourceLocation EndLoc) {
20176 return new (getASTContext()) OMPSelfMapsClause(StartLoc, EndLoc);
20177}
20178
20179StmtResult
20180SemaOpenMP::ActOnOpenMPInteropDirective(ArrayRef<OMPClause *> Clauses,
20181 SourceLocation StartLoc,
20182 SourceLocation EndLoc) {
20183
20184 // OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
20185 // At least one action-clause must appear on a directive.
20186 if (!hasClauses(Clauses, K: OMPC_init, ClauseTypes: OMPC_use, ClauseTypes: OMPC_destroy, ClauseTypes: OMPC_nowait)) {
20187 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
20188 StringRef Expected = "'init', 'use', 'destroy', or 'nowait'";
20189 Diag(Loc: StartLoc, DiagID: diag::err_omp_no_clause_for_directive)
20190 << Expected << getOpenMPDirectiveName(D: OMPD_interop, V: OMPVersion);
20191 return StmtError();
20192 }
20193
20194 // OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
20195 // A depend clause can only appear on the directive if a targetsync
20196 // interop-type is present or the interop-var was initialized with
20197 // the targetsync interop-type.
20198
20199 // If there is any 'init' clause diagnose if there is no 'init' clause with
20200 // interop-type of 'targetsync'. Cases involving other directives cannot be
20201 // diagnosed.
20202 const OMPDependClause *DependClause = nullptr;
20203 bool HasInitClause = false;
20204 bool IsTargetSync = false;
20205 for (const OMPClause *C : Clauses) {
20206 if (IsTargetSync)
20207 break;
20208 if (const auto *InitClause = dyn_cast<OMPInitClause>(Val: C)) {
20209 HasInitClause = true;
20210 if (InitClause->getIsTargetSync())
20211 IsTargetSync = true;
20212 } else if (const auto *DC = dyn_cast<OMPDependClause>(Val: C)) {
20213 DependClause = DC;
20214 }
20215 }
20216 if (DependClause && HasInitClause && !IsTargetSync) {
20217 Diag(Loc: DependClause->getBeginLoc(), DiagID: diag::err_omp_interop_bad_depend_clause);
20218 return StmtError();
20219 }
20220
20221 // OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
20222 // Each interop-var may be specified for at most one action-clause of each
20223 // interop construct.
20224 llvm::SmallPtrSet<const ValueDecl *, 4> InteropVars;
20225 for (OMPClause *C : Clauses) {
20226 OpenMPClauseKind ClauseKind = C->getClauseKind();
20227 std::pair<ValueDecl *, bool> DeclResult;
20228 SourceLocation ELoc;
20229 SourceRange ERange;
20230
20231 if (ClauseKind == OMPC_init) {
20232 auto *E = cast<OMPInitClause>(Val: C)->getInteropVar();
20233 DeclResult = getPrivateItem(S&: SemaRef, RefExpr&: E, ELoc, ERange);
20234 } else if (ClauseKind == OMPC_use) {
20235 auto *E = cast<OMPUseClause>(Val: C)->getInteropVar();
20236 DeclResult = getPrivateItem(S&: SemaRef, RefExpr&: E, ELoc, ERange);
20237 } else if (ClauseKind == OMPC_destroy) {
20238 auto *E = cast<OMPDestroyClause>(Val: C)->getInteropVar();
20239 DeclResult = getPrivateItem(S&: SemaRef, RefExpr&: E, ELoc, ERange);
20240 }
20241
20242 if (DeclResult.first) {
20243 if (!InteropVars.insert(Ptr: DeclResult.first).second) {
20244 Diag(Loc: ELoc, DiagID: diag::err_omp_interop_var_multiple_actions)
20245 << DeclResult.first;
20246 return StmtError();
20247 }
20248 }
20249 }
20250
20251 return OMPInteropDirective::Create(C: getASTContext(), StartLoc, EndLoc,
20252 Clauses);
20253}
20254
20255static bool isValidInteropVariable(Sema &SemaRef, Expr *InteropVarExpr,
20256 SourceLocation VarLoc,
20257 OpenMPClauseKind Kind) {
20258 SourceLocation ELoc;
20259 SourceRange ERange;
20260 Expr *RefExpr = InteropVarExpr;
20261 auto Res = getPrivateItem(S&: SemaRef, RefExpr, ELoc, ERange,
20262 /*AllowArraySection=*/false,
20263 /*AllowAssumedSizeArray=*/false,
20264 /*DiagType=*/"omp_interop_t");
20265
20266 if (Res.second) {
20267 // It will be analyzed later.
20268 return true;
20269 }
20270
20271 if (!Res.first)
20272 return false;
20273
20274 // Interop variable should be of type omp_interop_t.
20275 bool HasError = false;
20276 QualType InteropType;
20277 LookupResult Result(SemaRef, &SemaRef.Context.Idents.get(Name: "omp_interop_t"),
20278 VarLoc, Sema::LookupOrdinaryName);
20279 if (SemaRef.LookupName(R&: Result, S: SemaRef.getCurScope())) {
20280 NamedDecl *ND = Result.getFoundDecl();
20281 if (const auto *TD = dyn_cast<TypeDecl>(Val: ND)) {
20282 InteropType = QualType(TD->getTypeForDecl(), 0);
20283 } else {
20284 HasError = true;
20285 }
20286 } else {
20287 HasError = true;
20288 }
20289
20290 if (HasError) {
20291 SemaRef.Diag(Loc: VarLoc, DiagID: diag::err_omp_implied_type_not_found)
20292 << "omp_interop_t";
20293 return false;
20294 }
20295
20296 QualType VarType = InteropVarExpr->getType().getUnqualifiedType();
20297 if (!SemaRef.Context.hasSameType(T1: InteropType, T2: VarType)) {
20298 SemaRef.Diag(Loc: VarLoc, DiagID: diag::err_omp_interop_variable_wrong_type);
20299 return false;
20300 }
20301
20302 // OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
20303 // The interop-var passed to init or destroy must be non-const.
20304 if ((Kind == OMPC_init || Kind == OMPC_destroy) &&
20305 isConstNotMutableType(SemaRef, Type: InteropVarExpr->getType())) {
20306 SemaRef.Diag(Loc: VarLoc, DiagID: diag::err_omp_interop_variable_expected)
20307 << /*non-const*/ 1;
20308 return false;
20309 }
20310 return true;
20311}
20312
20313OMPClause *SemaOpenMP::ActOnOpenMPInitClause(
20314 Expr *InteropVar, OMPInteropInfo &InteropInfo, SourceLocation StartLoc,
20315 SourceLocation LParenLoc, SourceLocation VarLoc, SourceLocation EndLoc) {
20316
20317 if (!isValidInteropVariable(SemaRef, InteropVarExpr: InteropVar, VarLoc, Kind: OMPC_init))
20318 return nullptr;
20319
20320 if (!checkPreferTypeArgs(S&: *this, Info: InteropInfo))
20321 return nullptr;
20322
20323 return OMPInitClause::Create(C: getASTContext(), InteropVar, InteropInfo,
20324 StartLoc, LParenLoc, VarLoc, EndLoc);
20325}
20326
20327OMPClause *SemaOpenMP::ActOnOpenMPUseClause(Expr *InteropVar,
20328 SourceLocation StartLoc,
20329 SourceLocation LParenLoc,
20330 SourceLocation VarLoc,
20331 SourceLocation EndLoc) {
20332
20333 if (!isValidInteropVariable(SemaRef, InteropVarExpr: InteropVar, VarLoc, Kind: OMPC_use))
20334 return nullptr;
20335
20336 return new (getASTContext())
20337 OMPUseClause(InteropVar, StartLoc, LParenLoc, VarLoc, EndLoc);
20338}
20339
20340OMPClause *SemaOpenMP::ActOnOpenMPDestroyClause(Expr *InteropVar,
20341 SourceLocation StartLoc,
20342 SourceLocation LParenLoc,
20343 SourceLocation VarLoc,
20344 SourceLocation EndLoc) {
20345 if (!InteropVar && getLangOpts().OpenMP >= 52 &&
20346 DSAStack->getCurrentDirective() == OMPD_depobj) {
20347 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
20348 Diag(Loc: StartLoc, DiagID: diag::err_omp_expected_clause_argument)
20349 << getOpenMPClauseNameForDiag(C: OMPC_destroy)
20350 << getOpenMPDirectiveName(D: OMPD_depobj, V: OMPVersion);
20351 return nullptr;
20352 }
20353 if (InteropVar &&
20354 !isValidInteropVariable(SemaRef, InteropVarExpr: InteropVar, VarLoc, Kind: OMPC_destroy))
20355 return nullptr;
20356
20357 return new (getASTContext())
20358 OMPDestroyClause(InteropVar, StartLoc, LParenLoc, VarLoc, EndLoc);
20359}
20360
20361OMPClause *SemaOpenMP::ActOnOpenMPNovariantsClause(Expr *Condition,
20362 SourceLocation StartLoc,
20363 SourceLocation LParenLoc,
20364 SourceLocation EndLoc) {
20365 Expr *ValExpr = Condition;
20366 Stmt *HelperValStmt = nullptr;
20367 OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
20368 if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
20369 !Condition->isInstantiationDependent() &&
20370 !Condition->containsUnexpandedParameterPack()) {
20371 ExprResult Val = SemaRef.CheckBooleanCondition(Loc: StartLoc, E: Condition);
20372 if (Val.isInvalid())
20373 return nullptr;
20374
20375 ValExpr = SemaRef.MakeFullExpr(Arg: Val.get()).get();
20376
20377 OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
20378 CaptureRegion = getOpenMPCaptureRegionForClause(
20379 DKind, CKind: OMPC_novariants, OMPVersion: getLangOpts().getOpenMPVersion());
20380 if (CaptureRegion != OMPD_unknown &&
20381 !SemaRef.CurContext->isDependentContext()) {
20382 ValExpr = SemaRef.MakeFullExpr(Arg: ValExpr).get();
20383 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
20384 ValExpr = tryBuildCapture(SemaRef, Capture: ValExpr, Captures).get();
20385 HelperValStmt = buildPreInits(Context&: getASTContext(), Captures);
20386 }
20387 }
20388
20389 return new (getASTContext()) OMPNovariantsClause(
20390 ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
20391}
20392
20393OMPClause *SemaOpenMP::ActOnOpenMPNocontextClause(Expr *Condition,
20394 SourceLocation StartLoc,
20395 SourceLocation LParenLoc,
20396 SourceLocation EndLoc) {
20397 Expr *ValExpr = Condition;
20398 Stmt *HelperValStmt = nullptr;
20399 OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
20400 if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
20401 !Condition->isInstantiationDependent() &&
20402 !Condition->containsUnexpandedParameterPack()) {
20403 ExprResult Val = SemaRef.CheckBooleanCondition(Loc: StartLoc, E: Condition);
20404 if (Val.isInvalid())
20405 return nullptr;
20406
20407 ValExpr = SemaRef.MakeFullExpr(Arg: Val.get()).get();
20408
20409 OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
20410 CaptureRegion = getOpenMPCaptureRegionForClause(
20411 DKind, CKind: OMPC_nocontext, OMPVersion: getLangOpts().getOpenMPVersion());
20412 if (CaptureRegion != OMPD_unknown &&
20413 !SemaRef.CurContext->isDependentContext()) {
20414 ValExpr = SemaRef.MakeFullExpr(Arg: ValExpr).get();
20415 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
20416 ValExpr = tryBuildCapture(SemaRef, Capture: ValExpr, Captures).get();
20417 HelperValStmt = buildPreInits(Context&: getASTContext(), Captures);
20418 }
20419 }
20420
20421 return new (getASTContext()) OMPNocontextClause(
20422 ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
20423}
20424
20425OMPClause *SemaOpenMP::ActOnOpenMPFilterClause(Expr *ThreadID,
20426 SourceLocation StartLoc,
20427 SourceLocation LParenLoc,
20428 SourceLocation EndLoc) {
20429 Expr *ValExpr = ThreadID;
20430 Stmt *HelperValStmt = nullptr;
20431
20432 OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
20433 OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause(
20434 DKind, CKind: OMPC_filter, OMPVersion: getLangOpts().getOpenMPVersion());
20435 if (CaptureRegion != OMPD_unknown &&
20436 !SemaRef.CurContext->isDependentContext()) {
20437 ValExpr = SemaRef.MakeFullExpr(Arg: ValExpr).get();
20438 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
20439 ValExpr = tryBuildCapture(SemaRef, Capture: ValExpr, Captures).get();
20440 HelperValStmt = buildPreInits(Context&: getASTContext(), Captures);
20441 }
20442
20443 return new (getASTContext()) OMPFilterClause(
20444 ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
20445}
20446
20447OMPClause *SemaOpenMP::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
20448 ArrayRef<Expr *> VarList,
20449 const OMPVarListLocTy &Locs,
20450 OpenMPVarListDataTy &Data) {
20451 SourceLocation StartLoc = Locs.StartLoc;
20452 SourceLocation LParenLoc = Locs.LParenLoc;
20453 SourceLocation EndLoc = Locs.EndLoc;
20454 OMPClause *Res = nullptr;
20455 int ExtraModifier = Data.ExtraModifier;
20456 int OriginalSharingModifier = Data.OriginalSharingModifier;
20457 Expr *ExtraModifierExpr = Data.ExtraModifierExpr;
20458 SourceLocation ExtraModifierLoc = Data.ExtraModifierLoc;
20459 SourceLocation ColonLoc = Data.ColonLoc;
20460 switch (Kind) {
20461 case OMPC_private:
20462 Res = ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc, EndLoc);
20463 break;
20464 case OMPC_firstprivate:
20465 Res = ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
20466 break;
20467 case OMPC_lastprivate:
20468 assert(0 <= ExtraModifier && ExtraModifier <= OMPC_LASTPRIVATE_unknown &&
20469 "Unexpected lastprivate modifier.");
20470 Res = ActOnOpenMPLastprivateClause(
20471 VarList, LPKind: static_cast<OpenMPLastprivateModifier>(ExtraModifier),
20472 LPKindLoc: ExtraModifierLoc, ColonLoc, StartLoc, LParenLoc, EndLoc);
20473 break;
20474 case OMPC_shared:
20475 Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);
20476 break;
20477 case OMPC_reduction:
20478 assert(0 <= ExtraModifier && ExtraModifier <= OMPC_REDUCTION_unknown &&
20479 "Unexpected lastprivate modifier.");
20480 Res = ActOnOpenMPReductionClause(
20481 VarList,
20482 Modifiers: OpenMPVarListDataTy::OpenMPReductionClauseModifiers(
20483 ExtraModifier, OriginalSharingModifier),
20484 StartLoc, LParenLoc, ModifierLoc: ExtraModifierLoc, ColonLoc, EndLoc,
20485 ReductionIdScopeSpec&: Data.ReductionOrMapperIdScopeSpec, ReductionId: Data.ReductionOrMapperId);
20486 break;
20487 case OMPC_task_reduction:
20488 Res = ActOnOpenMPTaskReductionClause(
20489 VarList, StartLoc, LParenLoc, ColonLoc, EndLoc,
20490 ReductionIdScopeSpec&: Data.ReductionOrMapperIdScopeSpec, ReductionId: Data.ReductionOrMapperId);
20491 break;
20492 case OMPC_in_reduction:
20493 Res = ActOnOpenMPInReductionClause(
20494 VarList, StartLoc, LParenLoc, ColonLoc, EndLoc,
20495 ReductionIdScopeSpec&: Data.ReductionOrMapperIdScopeSpec, ReductionId: Data.ReductionOrMapperId);
20496 break;
20497 case OMPC_linear:
20498 assert(0 <= ExtraModifier && ExtraModifier <= OMPC_LINEAR_unknown &&
20499 "Unexpected linear modifier.");
20500 Res = ActOnOpenMPLinearClause(
20501 VarList, Step: Data.DepModOrTailExpr, StartLoc, LParenLoc,
20502 LinKind: static_cast<OpenMPLinearClauseKind>(ExtraModifier), LinLoc: ExtraModifierLoc,
20503 ColonLoc, StepModifierLoc: Data.StepModifierLoc, EndLoc);
20504 break;
20505 case OMPC_aligned:
20506 Res = ActOnOpenMPAlignedClause(VarList, Alignment: Data.DepModOrTailExpr, StartLoc,
20507 LParenLoc, ColonLoc, EndLoc);
20508 break;
20509 case OMPC_copyin:
20510 Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc);
20511 break;
20512 case OMPC_copyprivate:
20513 Res = ActOnOpenMPCopyprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
20514 break;
20515 case OMPC_flush:
20516 Res = ActOnOpenMPFlushClause(VarList, StartLoc, LParenLoc, EndLoc);
20517 break;
20518 case OMPC_depend:
20519 assert(0 <= ExtraModifier && ExtraModifier <= OMPC_DEPEND_unknown &&
20520 "Unexpected depend modifier.");
20521 Res = ActOnOpenMPDependClause(
20522 Data: {.DepKind: static_cast<OpenMPDependClauseKind>(ExtraModifier), .DepLoc: ExtraModifierLoc,
20523 .ColonLoc: ColonLoc, .OmpAllMemoryLoc: Data.OmpAllMemoryLoc},
20524 DepModifier: Data.DepModOrTailExpr, VarList, StartLoc, LParenLoc, EndLoc);
20525 break;
20526 case OMPC_map:
20527 assert(0 <= ExtraModifier && ExtraModifier <= OMPC_MAP_unknown &&
20528 "Unexpected map modifier.");
20529 Res = ActOnOpenMPMapClause(
20530 IteratorModifier: Data.IteratorExpr, MapTypeModifiers: Data.MapTypeModifiers, MapTypeModifiersLoc: Data.MapTypeModifiersLoc,
20531 MapperIdScopeSpec&: Data.ReductionOrMapperIdScopeSpec, MapperId&: Data.ReductionOrMapperId,
20532 MapType: static_cast<OpenMPMapClauseKind>(ExtraModifier), IsMapTypeImplicit: Data.IsMapTypeImplicit,
20533 MapLoc: ExtraModifierLoc, ColonLoc, VarList, Locs);
20534 break;
20535 case OMPC_to:
20536 Res = ActOnOpenMPToClause(
20537 MotionModifiers: Data.MotionModifiers, MotionModifiersLoc: Data.MotionModifiersLoc, IteratorModifier: Data.IteratorExpr,
20538 MapperIdScopeSpec&: Data.ReductionOrMapperIdScopeSpec, MapperId&: Data.ReductionOrMapperId, ColonLoc,
20539 VarList, Locs);
20540 break;
20541 case OMPC_from:
20542 Res = ActOnOpenMPFromClause(
20543 MotionModifiers: Data.MotionModifiers, MotionModifiersLoc: Data.MotionModifiersLoc, IteratorModifier: Data.IteratorExpr,
20544 MapperIdScopeSpec&: Data.ReductionOrMapperIdScopeSpec, MapperId&: Data.ReductionOrMapperId, ColonLoc,
20545 VarList, Locs);
20546 break;
20547 case OMPC_use_device_ptr:
20548 assert(0 <= Data.ExtraModifier &&
20549 Data.ExtraModifier <= OMPC_USE_DEVICE_PTR_FALLBACK_unknown &&
20550 "Unexpected use_device_ptr fallback modifier.");
20551 Res = ActOnOpenMPUseDevicePtrClause(
20552 VarList, Locs,
20553 FallbackModifier: static_cast<OpenMPUseDevicePtrFallbackModifier>(Data.ExtraModifier),
20554 FallbackModifierLoc: Data.ExtraModifierLoc);
20555 break;
20556 case OMPC_use_device_addr:
20557 Res = ActOnOpenMPUseDeviceAddrClause(VarList, Locs);
20558 break;
20559 case OMPC_is_device_ptr:
20560 Res = ActOnOpenMPIsDevicePtrClause(VarList, Locs);
20561 break;
20562 case OMPC_has_device_addr:
20563 Res = ActOnOpenMPHasDeviceAddrClause(VarList, Locs);
20564 break;
20565 case OMPC_allocate: {
20566 OpenMPAllocateClauseModifier Modifier1 = OMPC_ALLOCATE_unknown;
20567 OpenMPAllocateClauseModifier Modifier2 = OMPC_ALLOCATE_unknown;
20568 SourceLocation Modifier1Loc, Modifier2Loc;
20569 if (!Data.AllocClauseModifiers.empty()) {
20570 assert(Data.AllocClauseModifiers.size() <= 2 &&
20571 "More allocate modifiers than expected");
20572 Modifier1 = Data.AllocClauseModifiers[0];
20573 Modifier1Loc = Data.AllocClauseModifiersLoc[0];
20574 if (Data.AllocClauseModifiers.size() == 2) {
20575 Modifier2 = Data.AllocClauseModifiers[1];
20576 Modifier2Loc = Data.AllocClauseModifiersLoc[1];
20577 }
20578 }
20579 Res = ActOnOpenMPAllocateClause(
20580 Allocator: Data.DepModOrTailExpr, Alignment: Data.AllocateAlignment, FirstModifier: Modifier1, FirstModifierLoc: Modifier1Loc,
20581 SecondModifier: Modifier2, SecondModifierLoc: Modifier2Loc, VarList, StartLoc, ColonLoc: LParenLoc, LParenLoc: ColonLoc,
20582 EndLoc);
20583 break;
20584 }
20585 case OMPC_nontemporal:
20586 Res = ActOnOpenMPNontemporalClause(VarList, StartLoc, LParenLoc, EndLoc);
20587 break;
20588 case OMPC_inclusive:
20589 Res = ActOnOpenMPInclusiveClause(VarList, StartLoc, LParenLoc, EndLoc);
20590 break;
20591 case OMPC_exclusive:
20592 Res = ActOnOpenMPExclusiveClause(VarList, StartLoc, LParenLoc, EndLoc);
20593 break;
20594 case OMPC_affinity:
20595 Res = ActOnOpenMPAffinityClause(StartLoc, LParenLoc, ColonLoc, EndLoc,
20596 Modifier: Data.DepModOrTailExpr, Locators: VarList);
20597 break;
20598 case OMPC_doacross:
20599 Res = ActOnOpenMPDoacrossClause(
20600 DepType: static_cast<OpenMPDoacrossClauseModifier>(ExtraModifier),
20601 DepLoc: ExtraModifierLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc);
20602 break;
20603 case OMPC_num_teams:
20604 assert(0 <= ExtraModifier && ExtraModifier <= OMPC_NUMTEAMS_unknown &&
20605 "Unexpected num_teams modifier.");
20606 Res = ActOnOpenMPNumTeamsClause(
20607 VarList,
20608 Modifier: static_cast<OpenMPNumTeamsClauseModifier>(Data.ExtraModifierArray[0]),
20609 ModifierExpr: Data.ExtraModifierExprArray[0], ModifierLoc: Data.ExtraModifierLocArray[0],
20610 ModifierExtra: static_cast<OpenMPNumTeamsClauseModifier>(Data.ExtraModifierArray[1]),
20611 ModifierExtraExpr: Data.ExtraModifierExprArray[1], ModifierExtraLoc: Data.ExtraModifierLocArray[1], StartLoc,
20612 LParenLoc, EndLoc);
20613 break;
20614 case OMPC_thread_limit:
20615 assert(0 <= ExtraModifier && ExtraModifier <= OMPC_THREADLIMIT_unknown &&
20616 "Unexpected thread_limit modifier.");
20617 Res = ActOnOpenMPThreadLimitClause(
20618 VarList, Modifier: static_cast<OpenMPThreadLimitClauseModifier>(ExtraModifier),
20619 ModifierExpr: ExtraModifierExpr, ModifierLoc: ExtraModifierLoc, StartLoc, LParenLoc, EndLoc);
20620 break;
20621 case OMPC_num_threads:
20622 assert(0 <= Data.ExtraModifierArray[0] &&
20623 Data.ExtraModifierArray[0] <= OMPC_NUMTHREADS_unknown &&
20624 0 <= Data.ExtraModifierArray[1] &&
20625 Data.ExtraModifierArray[1] <= OMPC_NUMTHREADS_unknown &&
20626 "Unexpected num_threads modifier.");
20627 Res = ActOnOpenMPNumThreadsClause(
20628 VarList,
20629 SimpleModifier: static_cast<OpenMPNumThreadsClauseModifier>(Data.ExtraModifierArray[0]),
20630 SimpleModifierLoc: Data.ExtraModifierLocArray[0],
20631 ComplexModifier: static_cast<OpenMPNumThreadsClauseModifier>(Data.ExtraModifierArray[1]),
20632 ComplexModifierExpr: Data.ExtraModifierExprArray[1], ComplexModifierLoc: Data.ExtraModifierLocArray[1], StartLoc,
20633 LParenLoc, EndLoc);
20634 break;
20635 case OMPC_if:
20636 case OMPC_depobj:
20637 case OMPC_final:
20638 case OMPC_safelen:
20639 case OMPC_simdlen:
20640 case OMPC_sizes:
20641 case OMPC_depth:
20642 case OMPC_allocator:
20643 case OMPC_collapse:
20644 case OMPC_default:
20645 case OMPC_proc_bind:
20646 case OMPC_schedule:
20647 case OMPC_ordered:
20648 case OMPC_nowait:
20649 case OMPC_untied:
20650 case OMPC_mergeable:
20651 case OMPC_threadprivate:
20652 case OMPC_groupprivate:
20653 case OMPC_read:
20654 case OMPC_write:
20655 case OMPC_update:
20656 case OMPC_capture:
20657 case OMPC_compare:
20658 case OMPC_seq_cst:
20659 case OMPC_acq_rel:
20660 case OMPC_acquire:
20661 case OMPC_release:
20662 case OMPC_relaxed:
20663 case OMPC_device:
20664 case OMPC_threads:
20665 case OMPC_simd:
20666 case OMPC_priority:
20667 case OMPC_grainsize:
20668 case OMPC_nogroup:
20669 case OMPC_num_tasks:
20670 case OMPC_hint:
20671 case OMPC_dist_schedule:
20672 case OMPC_defaultmap:
20673 case OMPC_unknown:
20674 case OMPC_uniform:
20675 case OMPC_unified_address:
20676 case OMPC_unified_shared_memory:
20677 case OMPC_reverse_offload:
20678 case OMPC_dynamic_allocators:
20679 case OMPC_atomic_default_mem_order:
20680 case OMPC_self_maps:
20681 case OMPC_device_type:
20682 case OMPC_match:
20683 case OMPC_order:
20684 case OMPC_at:
20685 case OMPC_severity:
20686 case OMPC_message:
20687 case OMPC_destroy:
20688 case OMPC_novariants:
20689 case OMPC_nocontext:
20690 case OMPC_detach:
20691 case OMPC_uses_allocators:
20692 case OMPC_when:
20693 case OMPC_bind:
20694 default:
20695 llvm_unreachable("Clause is not allowed.");
20696 }
20697 return Res;
20698}
20699
20700ExprResult SemaOpenMP::getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK,
20701 ExprObjectKind OK,
20702 SourceLocation Loc) {
20703 ExprResult Res = SemaRef.BuildDeclRefExpr(
20704 D: Capture, Ty: Capture->getType().getNonReferenceType(), VK: VK_LValue, Loc);
20705 if (!Res.isUsable())
20706 return ExprError();
20707 if (OK == OK_Ordinary && !getLangOpts().CPlusPlus) {
20708 Res = SemaRef.CreateBuiltinUnaryOp(OpLoc: Loc, Opc: UO_Deref, InputExpr: Res.get());
20709 if (!Res.isUsable())
20710 return ExprError();
20711 }
20712 if (VK != VK_LValue && Res.get()->isGLValue()) {
20713 Res = SemaRef.DefaultLvalueConversion(E: Res.get());
20714 if (!Res.isUsable())
20715 return ExprError();
20716 }
20717 return Res;
20718}
20719
20720OMPClause *SemaOpenMP::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
20721 SourceLocation StartLoc,
20722 SourceLocation LParenLoc,
20723 SourceLocation EndLoc) {
20724 SmallVector<Expr *, 8> Vars;
20725 SmallVector<Expr *, 8> PrivateCopies;
20726 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
20727 bool IsImplicitClause =
20728 StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid();
20729 for (Expr *RefExpr : VarList) {
20730 assert(RefExpr && "NULL expr in OpenMP private clause.");
20731 SourceLocation ELoc;
20732 SourceRange ERange;
20733 Expr *SimpleRefExpr = RefExpr;
20734 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange);
20735 if (Res.second) {
20736 // It will be analyzed later.
20737 Vars.push_back(Elt: RefExpr);
20738 PrivateCopies.push_back(Elt: nullptr);
20739 }
20740 ValueDecl *D = Res.first;
20741 if (!D)
20742 continue;
20743
20744 QualType Type = D->getType();
20745 auto *VD = dyn_cast<VarDecl>(Val: D);
20746
20747 // OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
20748 // A variable that appears in a private clause must not have an incomplete
20749 // type or a reference type.
20750 if (SemaRef.RequireCompleteType(Loc: ELoc, T: Type,
20751 DiagID: diag::err_omp_private_incomplete_type))
20752 continue;
20753 Type = Type.getNonReferenceType();
20754
20755 // OpenMP 5.0 [2.19.3, List Item Privatization, Restrictions]
20756 // A variable that is privatized must not have a const-qualified type
20757 // unless it is of class type with a mutable member. This restriction does
20758 // not apply to the firstprivate clause.
20759 //
20760 // OpenMP 3.1 [2.9.3.3, private clause, Restrictions]
20761 // A variable that appears in a private clause must not have a
20762 // const-qualified type unless it is of class type with a mutable member.
20763 if (rejectConstNotMutableType(SemaRef, D, Type, CKind: OMPC_private, ELoc))
20764 continue;
20765
20766 // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
20767 // in a Construct]
20768 // Variables with the predetermined data-sharing attributes may not be
20769 // listed in data-sharing attributes clauses, except for the cases
20770 // listed below. For these exceptions only, listing a predetermined
20771 // variable in a data-sharing attribute clause is allowed and overrides
20772 // the variable's predetermined data-sharing attributes.
20773 DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false);
20774 if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private) {
20775 Diag(Loc: ELoc, DiagID: diag::err_omp_wrong_dsa)
20776 << getOpenMPClauseNameForDiag(C: DVar.CKind)
20777 << getOpenMPClauseNameForDiag(C: OMPC_private);
20778 reportOriginalDsa(SemaRef, DSAStack, D, DVar);
20779 continue;
20780 }
20781
20782 OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
20783 // Variably modified types are not supported for tasks.
20784 if (!Type->isAnyPointerType() && Type->isVariablyModifiedType() &&
20785 isOpenMPTaskingDirective(Kind: CurrDir)) {
20786 Diag(Loc: ELoc, DiagID: diag::err_omp_variably_modified_type_not_supported)
20787 << getOpenMPClauseNameForDiag(C: OMPC_private) << Type
20788 << getOpenMPDirectiveName(D: CurrDir, V: OMPVersion);
20789 bool IsDecl = !VD || VD->isThisDeclarationADefinition(getASTContext()) ==
20790 VarDecl::DeclarationOnly;
20791 Diag(Loc: D->getLocation(),
20792 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
20793 << D;
20794 continue;
20795 }
20796
20797 // OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
20798 // A list item cannot appear in both a map clause and a data-sharing
20799 // attribute clause on the same construct
20800 //
20801 // OpenMP 5.0 [2.19.7.1, Restrictions, p.7]
20802 // A list item cannot appear in both a map clause and a data-sharing
20803 // attribute clause on the same construct unless the construct is a
20804 // combined construct.
20805 if ((getLangOpts().OpenMP <= 45 &&
20806 isOpenMPTargetExecutionDirective(DKind: CurrDir)) ||
20807 CurrDir == OMPD_target) {
20808 OpenMPClauseKind ConflictKind;
20809 if (DSAStack->checkMappableExprComponentListsForDecl(
20810 VD, /*CurrentRegionOnly=*/true,
20811 Check: [&](OMPClauseMappableExprCommon::MappableExprComponentListRef,
20812 OpenMPClauseKind WhereFoundClauseKind) -> bool {
20813 ConflictKind = WhereFoundClauseKind;
20814 return true;
20815 })) {
20816 Diag(Loc: ELoc, DiagID: diag::err_omp_variable_in_given_clause_and_dsa)
20817 << getOpenMPClauseNameForDiag(C: OMPC_private)
20818 << getOpenMPClauseNameForDiag(C: ConflictKind)
20819 << getOpenMPDirectiveName(D: CurrDir, V: OMPVersion);
20820 reportOriginalDsa(SemaRef, DSAStack, D, DVar);
20821 continue;
20822 }
20823 }
20824
20825 // OpenMP [2.9.3.3, Restrictions, C/C++, p.1]
20826 // A variable of class type (or array thereof) that appears in a private
20827 // clause requires an accessible, unambiguous default constructor for the
20828 // class type.
20829 // Generate helper private variable and initialize it with the default
20830 // value. The address of the original variable is replaced by the address of
20831 // the new private variable in CodeGen. This new variable is not added to
20832 // IdResolver, so the code in the OpenMP region uses original variable for
20833 // proper diagnostics.
20834 Type = Type.getUnqualifiedType();
20835 VarDecl *VDPrivate =
20836 buildVarDecl(SemaRef, Loc: ELoc, Type, Name: D->getName(),
20837 Attrs: D->hasAttrs() ? &D->getAttrs() : nullptr,
20838 OrigRef: VD ? cast<DeclRefExpr>(Val: SimpleRefExpr) : nullptr);
20839 SemaRef.ActOnUninitializedDecl(dcl: VDPrivate);
20840 if (VDPrivate->isInvalidDecl())
20841 continue;
20842 DeclRefExpr *VDPrivateRefExpr = buildDeclRefExpr(
20843 S&: SemaRef, D: VDPrivate, Ty: RefExpr->getType().getUnqualifiedType(), Loc: ELoc);
20844
20845 DeclRefExpr *Ref = nullptr;
20846 bool IsBindingDecl = isa<BindingDecl>(Val: D);
20847 if (!VD && !IsBindingDecl && !SemaRef.CurContext->isDependentContext()) {
20848 auto *FD = dyn_cast<FieldDecl>(Val: D);
20849 VarDecl *VD = FD ? DSAStack->getImplicitFDCapExprDecl(FD) : nullptr;
20850 if (VD)
20851 Ref = buildDeclRefExpr(S&: SemaRef, D: VD, Ty: VD->getType().getNonReferenceType(),
20852 Loc: RefExpr->getExprLoc());
20853 else
20854 Ref = buildCapture(S&: SemaRef, D, CaptureExpr: SimpleRefExpr, /*WithInit=*/false);
20855 }
20856 if (!IsImplicitClause) {
20857 DSAStack->addDSA(D, E: RefExpr->IgnoreParens(), A: OMPC_private, PrivateCopy: Ref);
20858 }
20859 Vars.push_back(
20860 Elt: (VD || IsBindingDecl || SemaRef.CurContext->isDependentContext())
20861 ? RefExpr->IgnoreParens()
20862 : Ref);
20863 PrivateCopies.push_back(Elt: VDPrivateRefExpr);
20864 }
20865
20866 if (Vars.empty())
20867 return nullptr;
20868
20869 return OMPPrivateClause::Create(C: getASTContext(), StartLoc, LParenLoc, EndLoc,
20870 VL: Vars, PrivateVL: PrivateCopies);
20871}
20872
20873OMPClause *SemaOpenMP::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
20874 SourceLocation StartLoc,
20875 SourceLocation LParenLoc,
20876 SourceLocation EndLoc) {
20877 SmallVector<Expr *, 8> Vars;
20878 SmallVector<Expr *, 8> PrivateCopies;
20879 SmallVector<Expr *, 8> Inits;
20880 SmallVector<Decl *, 4> ExprCaptures;
20881 bool IsImplicitClause =
20882 StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid();
20883 SourceLocation ImplicitClauseLoc = DSAStack->getConstructLoc();
20884 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
20885
20886 for (Expr *RefExpr : VarList) {
20887 assert(RefExpr && "NULL expr in OpenMP firstprivate clause.");
20888 SourceLocation ELoc;
20889 SourceRange ERange;
20890 Expr *SimpleRefExpr = RefExpr;
20891 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange);
20892 if (Res.second) {
20893 // It will be analyzed later.
20894 Vars.push_back(Elt: RefExpr);
20895 PrivateCopies.push_back(Elt: nullptr);
20896 Inits.push_back(Elt: nullptr);
20897 }
20898 ValueDecl *D = Res.first;
20899 if (!D)
20900 continue;
20901
20902 ELoc = IsImplicitClause ? ImplicitClauseLoc : ELoc;
20903 QualType Type = D->getType();
20904 auto *VD = dyn_cast<VarDecl>(Val: D);
20905
20906 // OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
20907 // A variable that appears in a private clause must not have an incomplete
20908 // type or a reference type.
20909 if (SemaRef.RequireCompleteType(Loc: ELoc, T: Type,
20910 DiagID: diag::err_omp_firstprivate_incomplete_type))
20911 continue;
20912 Type = Type.getNonReferenceType();
20913
20914 // OpenMP [2.9.3.4, Restrictions, C/C++, p.1]
20915 // A variable of class type (or array thereof) that appears in a private
20916 // clause requires an accessible, unambiguous copy constructor for the
20917 // class type.
20918 QualType ElemType =
20919 getASTContext().getBaseElementType(QT: Type).getNonReferenceType();
20920
20921 // If an implicit firstprivate variable found it was checked already.
20922 DSAStackTy::DSAVarData TopDVar;
20923 if (!IsImplicitClause) {
20924 DSAStackTy::DSAVarData DVar =
20925 DSAStack->getTopDSA(D, /*FromParent=*/false);
20926 TopDVar = DVar;
20927 OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
20928 bool IsConstant = ElemType.isConstant(Ctx: getASTContext());
20929 // OpenMP [2.4.13, Data-sharing Attribute Clauses]
20930 // A list item that specifies a given variable may not appear in more
20931 // than one clause on the same directive, except that a variable may be
20932 // specified in both firstprivate and lastprivate clauses.
20933 // OpenMP 4.5 [2.10.8, Distribute Construct, p.3]
20934 // A list item may appear in a firstprivate or lastprivate clause but not
20935 // both.
20936 if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate &&
20937 (isOpenMPDistributeDirective(DKind: CurrDir) ||
20938 DVar.CKind != OMPC_lastprivate) &&
20939 DVar.RefExpr) {
20940 Diag(Loc: ELoc, DiagID: diag::err_omp_wrong_dsa)
20941 << getOpenMPClauseNameForDiag(C: DVar.CKind)
20942 << getOpenMPClauseNameForDiag(C: OMPC_firstprivate);
20943 reportOriginalDsa(SemaRef, DSAStack, D, DVar);
20944 continue;
20945 }
20946
20947 // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
20948 // in a Construct]
20949 // Variables with the predetermined data-sharing attributes may not be
20950 // listed in data-sharing attributes clauses, except for the cases
20951 // listed below. For these exceptions only, listing a predetermined
20952 // variable in a data-sharing attribute clause is allowed and overrides
20953 // the variable's predetermined data-sharing attributes.
20954 // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
20955 // in a Construct, C/C++, p.2]
20956 // Variables with const-qualified type having no mutable member may be
20957 // listed in a firstprivate clause, even if they are static data members.
20958 if (!(IsConstant || (VD && VD->isStaticDataMember())) && !DVar.RefExpr &&
20959 DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared) {
20960 Diag(Loc: ELoc, DiagID: diag::err_omp_wrong_dsa)
20961 << getOpenMPClauseNameForDiag(C: DVar.CKind)
20962 << getOpenMPClauseNameForDiag(C: OMPC_firstprivate);
20963 reportOriginalDsa(SemaRef, DSAStack, D, DVar);
20964 continue;
20965 }
20966
20967 // OpenMP [2.9.3.4, Restrictions, p.2]
20968 // A list item that is private within a parallel region must not appear
20969 // in a firstprivate clause on a worksharing construct if any of the
20970 // worksharing regions arising from the worksharing construct ever bind
20971 // to any of the parallel regions arising from the parallel construct.
20972 // OpenMP 4.5 [2.15.3.4, Restrictions, p.3]
20973 // A list item that is private within a teams region must not appear in a
20974 // firstprivate clause on a distribute construct if any of the distribute
20975 // regions arising from the distribute construct ever bind to any of the
20976 // teams regions arising from the teams construct.
20977 // OpenMP 4.5 [2.15.3.4, Restrictions, p.3]
20978 // A list item that appears in a reduction clause of a teams construct
20979 // must not appear in a firstprivate clause on a distribute construct if
20980 // any of the distribute regions arising from the distribute construct
20981 // ever bind to any of the teams regions arising from the teams construct.
20982 if ((isOpenMPWorksharingDirective(DKind: CurrDir) ||
20983 isOpenMPDistributeDirective(DKind: CurrDir)) &&
20984 !isOpenMPParallelDirective(DKind: CurrDir) &&
20985 !isOpenMPTeamsDirective(DKind: CurrDir)) {
20986 DVar = DSAStack->getImplicitDSA(D, FromParent: true);
20987 if (DVar.CKind != OMPC_shared &&
20988 (isOpenMPParallelDirective(DKind: DVar.DKind) ||
20989 isOpenMPTeamsDirective(DKind: DVar.DKind) ||
20990 DVar.DKind == OMPD_unknown)) {
20991 Diag(Loc: ELoc, DiagID: diag::err_omp_required_access)
20992 << getOpenMPClauseNameForDiag(C: OMPC_firstprivate)
20993 << getOpenMPClauseNameForDiag(C: OMPC_shared);
20994 reportOriginalDsa(SemaRef, DSAStack, D, DVar);
20995 continue;
20996 }
20997 }
20998 // OpenMP [2.9.3.4, Restrictions, p.3]
20999 // A list item that appears in a reduction clause of a parallel construct
21000 // must not appear in a firstprivate clause on a worksharing or task
21001 // construct if any of the worksharing or task regions arising from the
21002 // worksharing or task construct ever bind to any of the parallel regions
21003 // arising from the parallel construct.
21004 // OpenMP [2.9.3.4, Restrictions, p.4]
21005 // A list item that appears in a reduction clause in worksharing
21006 // construct must not appear in a firstprivate clause in a task construct
21007 // encountered during execution of any of the worksharing regions arising
21008 // from the worksharing construct.
21009 if (isOpenMPTaskingDirective(Kind: CurrDir)) {
21010 DVar = DSAStack->hasInnermostDSA(
21011 D,
21012 CPred: [](OpenMPClauseKind C, bool AppliedToPointee) {
21013 return C == OMPC_reduction && !AppliedToPointee;
21014 },
21015 DPred: [](OpenMPDirectiveKind K) {
21016 return isOpenMPParallelDirective(DKind: K) ||
21017 isOpenMPWorksharingDirective(DKind: K) ||
21018 isOpenMPTeamsDirective(DKind: K);
21019 },
21020 /*FromParent=*/true);
21021 if (DVar.CKind == OMPC_reduction &&
21022 (isOpenMPParallelDirective(DKind: DVar.DKind) ||
21023 isOpenMPWorksharingDirective(DKind: DVar.DKind) ||
21024 isOpenMPTeamsDirective(DKind: DVar.DKind))) {
21025 Diag(Loc: ELoc, DiagID: diag::err_omp_parallel_reduction_in_task_firstprivate)
21026 << getOpenMPDirectiveName(D: DVar.DKind, V: OMPVersion);
21027 reportOriginalDsa(SemaRef, DSAStack, D, DVar);
21028 continue;
21029 }
21030 }
21031
21032 // OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
21033 // A list item cannot appear in both a map clause and a data-sharing
21034 // attribute clause on the same construct
21035 //
21036 // OpenMP 5.0 [2.19.7.1, Restrictions, p.7]
21037 // A list item cannot appear in both a map clause and a data-sharing
21038 // attribute clause on the same construct unless the construct is a
21039 // combined construct.
21040 if ((getLangOpts().OpenMP <= 45 &&
21041 isOpenMPTargetExecutionDirective(DKind: CurrDir)) ||
21042 CurrDir == OMPD_target) {
21043 OpenMPClauseKind ConflictKind;
21044 if (DSAStack->checkMappableExprComponentListsForDecl(
21045 VD, /*CurrentRegionOnly=*/true,
21046 Check: [&ConflictKind](
21047 OMPClauseMappableExprCommon::MappableExprComponentListRef,
21048 OpenMPClauseKind WhereFoundClauseKind) {
21049 ConflictKind = WhereFoundClauseKind;
21050 return true;
21051 })) {
21052 Diag(Loc: ELoc, DiagID: diag::err_omp_variable_in_given_clause_and_dsa)
21053 << getOpenMPClauseNameForDiag(C: OMPC_firstprivate)
21054 << getOpenMPClauseNameForDiag(C: ConflictKind)
21055 << getOpenMPDirectiveName(DSAStack->getCurrentDirective(),
21056 V: OMPVersion);
21057 reportOriginalDsa(SemaRef, DSAStack, D, DVar);
21058 continue;
21059 }
21060 }
21061 }
21062
21063 // Variably modified types are not supported for tasks.
21064 if (!Type->isAnyPointerType() && Type->isVariablyModifiedType() &&
21065 isOpenMPTaskingDirective(DSAStack->getCurrentDirective())) {
21066 Diag(Loc: ELoc, DiagID: diag::err_omp_variably_modified_type_not_supported)
21067 << getOpenMPClauseNameForDiag(C: OMPC_firstprivate) << Type
21068 << getOpenMPDirectiveName(DSAStack->getCurrentDirective(),
21069 V: OMPVersion);
21070 bool IsDecl = !VD || VD->isThisDeclarationADefinition(getASTContext()) ==
21071 VarDecl::DeclarationOnly;
21072 Diag(Loc: D->getLocation(),
21073 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
21074 << D;
21075 continue;
21076 }
21077
21078 Type = Type.getUnqualifiedType();
21079
21080 // For BindingDecls, use the DecompositionDecl's type so all bindings from
21081 // the same decomposition are accessible in the privatized region. We do
21082 // this after conflict checking to preserve diagnostic errors. Don't modify
21083 // RefExpr/SimpleRefExpr to keep diagnostics working.
21084 bool IsBindingDecl = isa<BindingDecl>(Val: D);
21085 VarDecl *PrivateVD = VD;
21086 QualType PrivateType = Type;
21087 if (IsBindingDecl) {
21088 const auto *BD = cast<BindingDecl>(Val: D);
21089 PrivateVD = cast<VarDecl>(Val: BD->getDecomposedDecl());
21090 // PrivateType stays as the BindingDecl's type (Type), not the
21091 // DecompositionDecl's type.
21092 }
21093
21094 // For regular arrays, pass the original var ref. For BindingDecls, don't
21095 // pass the DecompositionDecl ref since VDPrivate has the binding's type,
21096 // not the decomposition type.
21097 VarDecl *VDPrivate = buildVarDecl(SemaRef, Loc: ELoc, Type: PrivateType, Name: D->getName(),
21098 Attrs: D->hasAttrs() ? &D->getAttrs() : nullptr,
21099 OrigRef: (PrivateVD && !IsBindingDecl)
21100 ? cast<DeclRefExpr>(Val: SimpleRefExpr)
21101 : nullptr);
21102
21103 // Generate helper private variable and initialize it with the value of the
21104 // original variable. The address of the original variable is replaced by
21105 // the address of the new private variable in the CodeGen. This new variable
21106 // is not added to IdResolver, so the code in the OpenMP region uses
21107 // original variable for proper diagnostics and variable capturing.
21108 Expr *VDInitRefExpr = nullptr;
21109
21110 // For BindingDecls, VDPrivate should have the binding's type (not the
21111 // DecompositionDecl's type), and will be initialized from the binding's
21112 // field in the original DecompositionDecl.
21113 if (IsBindingDecl && !PrivateType->isArrayType()) {
21114 // For non-array bindings, create a simple copy initialization.
21115 VarDecl *VDInit = buildVarDecl(SemaRef, Loc: RefExpr->getExprLoc(),
21116 Type: PrivateType, Name: ".firstprivate.temp");
21117 VDInitRefExpr =
21118 buildDeclRefExpr(S&: SemaRef, D: VDInit, Ty: PrivateType, Loc: RefExpr->getExprLoc());
21119
21120 // Initialize VDPrivate from VDInit (which will point to the field).
21121 SemaRef.AddInitializerToDecl(
21122 dcl: VDPrivate, init: SemaRef.DefaultLvalueConversion(E: VDInitRefExpr).get(),
21123 /*DirectInit=*/false);
21124 } else if (Type->isArrayType()) {
21125 // For arrays generate initializer for single element and replace it by
21126 // the original array element in CodeGen.
21127 VarDecl *VDInit =
21128 buildVarDecl(SemaRef, Loc: RefExpr->getExprLoc(), Type: ElemType, Name: D->getName());
21129 VDInitRefExpr = buildDeclRefExpr(S&: SemaRef, D: VDInit, Ty: ElemType, Loc: ELoc);
21130 Expr *Init = SemaRef.DefaultLvalueConversion(E: VDInitRefExpr).get();
21131 ElemType = ElemType.getUnqualifiedType();
21132 VarDecl *VDInitTemp = buildVarDecl(SemaRef, Loc: RefExpr->getExprLoc(),
21133 Type: ElemType, Name: ".firstprivate.temp");
21134 InitializedEntity Entity =
21135 InitializedEntity::InitializeVariable(Var: VDInitTemp);
21136 InitializationKind Kind = InitializationKind::CreateCopy(InitLoc: ELoc, EqualLoc: ELoc);
21137
21138 InitializationSequence InitSeq(SemaRef, Entity, Kind, Init);
21139 ExprResult Result = InitSeq.Perform(S&: SemaRef, Entity, Kind, Args: Init);
21140 if (Result.isInvalid())
21141 VDPrivate->setInvalidDecl();
21142 else
21143 VDPrivate->setInit(Result.getAs<Expr>());
21144 // Remove temp variable declaration.
21145 getASTContext().Deallocate(Ptr: VDInitTemp);
21146 } else {
21147 VarDecl *VDInit = buildVarDecl(SemaRef, Loc: RefExpr->getExprLoc(), Type,
21148 Name: ".firstprivate.temp");
21149 VDInitRefExpr = buildDeclRefExpr(S&: SemaRef, D: VDInit, Ty: RefExpr->getType(),
21150 Loc: RefExpr->getExprLoc());
21151 SemaRef.AddInitializerToDecl(
21152 dcl: VDPrivate, init: SemaRef.DefaultLvalueConversion(E: VDInitRefExpr).get(),
21153 /*DirectInit=*/false);
21154 }
21155 if (VDPrivate->isInvalidDecl()) {
21156 if (IsImplicitClause) {
21157 Diag(Loc: RefExpr->getExprLoc(),
21158 DiagID: diag::note_omp_task_predetermined_firstprivate_here);
21159 }
21160 continue;
21161 }
21162 SemaRef.CurContext->addDecl(D: VDPrivate);
21163 DeclRefExpr *VDPrivateRefExpr = buildDeclRefExpr(
21164 S&: SemaRef, D: VDPrivate, Ty: RefExpr->getType().getUnqualifiedType(),
21165 Loc: RefExpr->getExprLoc());
21166 DeclRefExpr *Ref = nullptr;
21167 if (!VD && !SemaRef.CurContext->isDependentContext()) {
21168 if (TopDVar.CKind == OMPC_lastprivate) {
21169 Ref = TopDVar.PrivateCopy;
21170 } else if (!IsBindingDecl) {
21171 auto *FD = dyn_cast<FieldDecl>(Val: D);
21172 VarDecl *VD = FD ? DSAStack->getImplicitFDCapExprDecl(FD) : nullptr;
21173 if (VD)
21174 Ref =
21175 buildDeclRefExpr(S&: SemaRef, D: VD, Ty: VD->getType().getNonReferenceType(),
21176 Loc: RefExpr->getExprLoc());
21177 else
21178 Ref = buildCapture(S&: SemaRef, D, CaptureExpr: SimpleRefExpr, /*WithInit=*/true);
21179 if (VD || !isOpenMPCapturedDecl(D))
21180 ExprCaptures.push_back(Elt: Ref->getDecl());
21181 }
21182 }
21183 if (!IsImplicitClause)
21184 DSAStack->addDSA(D, E: RefExpr->IgnoreParens(), A: OMPC_firstprivate, PrivateCopy: Ref);
21185 Vars.push_back(
21186 Elt: (VD || IsBindingDecl || SemaRef.CurContext->isDependentContext())
21187 ? RefExpr->IgnoreParens()
21188 : Ref);
21189 PrivateCopies.push_back(Elt: VDPrivateRefExpr);
21190 Inits.push_back(Elt: VDInitRefExpr);
21191 }
21192
21193 if (Vars.empty())
21194 return nullptr;
21195
21196 return OMPFirstprivateClause::Create(
21197 C: getASTContext(), StartLoc, LParenLoc, EndLoc, VL: Vars, PrivateVL: PrivateCopies, InitVL: Inits,
21198 PreInit: buildPreInits(Context&: getASTContext(), PreInits: ExprCaptures));
21199}
21200
21201OMPClause *SemaOpenMP::ActOnOpenMPLastprivateClause(
21202 ArrayRef<Expr *> VarList, OpenMPLastprivateModifier LPKind,
21203 SourceLocation LPKindLoc, SourceLocation ColonLoc, SourceLocation StartLoc,
21204 SourceLocation LParenLoc, SourceLocation EndLoc) {
21205 if (LPKind == OMPC_LASTPRIVATE_unknown && LPKindLoc.isValid()) {
21206 assert(ColonLoc.isValid() && "Colon location must be valid.");
21207 Diag(Loc: LPKindLoc, DiagID: diag::err_omp_unexpected_clause_value)
21208 << getListOfPossibleValues(K: OMPC_lastprivate, /*First=*/0,
21209 /*Last=*/OMPC_LASTPRIVATE_unknown)
21210 << getOpenMPClauseNameForDiag(C: OMPC_lastprivate);
21211 return nullptr;
21212 }
21213
21214 SmallVector<Expr *, 8> Vars;
21215 SmallVector<Expr *, 8> SrcExprs;
21216 SmallVector<Expr *, 8> DstExprs;
21217 SmallVector<Expr *, 8> AssignmentOps;
21218 SmallVector<Decl *, 4> ExprCaptures;
21219 SmallVector<Expr *, 4> ExprPostUpdates;
21220 for (Expr *RefExpr : VarList) {
21221 assert(RefExpr && "NULL expr in OpenMP lastprivate clause.");
21222 SourceLocation ELoc;
21223 SourceRange ERange;
21224 Expr *SimpleRefExpr = RefExpr;
21225 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange);
21226 if (Res.second) {
21227 // It will be analyzed later.
21228 Vars.push_back(Elt: RefExpr);
21229 SrcExprs.push_back(Elt: nullptr);
21230 DstExprs.push_back(Elt: nullptr);
21231 AssignmentOps.push_back(Elt: nullptr);
21232 }
21233 ValueDecl *D = Res.first;
21234 if (!D)
21235 continue;
21236
21237 QualType Type = D->getType();
21238 auto *VD = dyn_cast<VarDecl>(Val: D);
21239
21240 // Structured bindings with conditional modifier are currently not
21241 // supported.
21242 if (LPKind == OMPC_LASTPRIVATE_conditional && isa<BindingDecl>(Val: D)) {
21243 Diag(Loc: ELoc, DiagID: diag::err_omp_unsupported_on_binding) << 1;
21244 Diag(Loc: D->getLocation(), DiagID: diag::note_defined_here) << D;
21245 continue;
21246 }
21247
21248 // OpenMP [2.14.3.5, Restrictions, C/C++, p.2]
21249 // A variable that appears in a lastprivate clause must not have an
21250 // incomplete type or a reference type.
21251 if (SemaRef.RequireCompleteType(Loc: ELoc, T: Type,
21252 DiagID: diag::err_omp_lastprivate_incomplete_type))
21253 continue;
21254 Type = Type.getNonReferenceType();
21255
21256 // OpenMP 5.0 [2.19.3, List Item Privatization, Restrictions]
21257 // A variable that is privatized must not have a const-qualified type
21258 // unless it is of class type with a mutable member. This restriction does
21259 // not apply to the firstprivate clause.
21260 //
21261 // OpenMP 3.1 [2.9.3.5, lastprivate clause, Restrictions]
21262 // A variable that appears in a lastprivate clause must not have a
21263 // const-qualified type unless it is of class type with a mutable member.
21264 if (rejectConstNotMutableType(SemaRef, D, Type, CKind: OMPC_lastprivate, ELoc))
21265 continue;
21266
21267 // OpenMP 5.0 [2.19.4.5 lastprivate Clause, Restrictions]
21268 // A list item that appears in a lastprivate clause with the conditional
21269 // modifier must be a scalar variable.
21270 if (LPKind == OMPC_LASTPRIVATE_conditional && !Type->isScalarType()) {
21271 Diag(Loc: ELoc, DiagID: diag::err_omp_lastprivate_conditional_non_scalar);
21272 bool IsDecl = !VD || VD->isThisDeclarationADefinition(getASTContext()) ==
21273 VarDecl::DeclarationOnly;
21274 Diag(Loc: D->getLocation(),
21275 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
21276 << D;
21277 continue;
21278 }
21279
21280 OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
21281 // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
21282 // in a Construct]
21283 // Variables with the predetermined data-sharing attributes may not be
21284 // listed in data-sharing attributes clauses, except for the cases
21285 // listed below.
21286 // OpenMP 4.5 [2.10.8, Distribute Construct, p.3]
21287 // A list item may appear in a firstprivate or lastprivate clause but not
21288 // both.
21289 DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false);
21290 if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_lastprivate &&
21291 (isOpenMPDistributeDirective(DKind: CurrDir) ||
21292 DVar.CKind != OMPC_firstprivate) &&
21293 (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
21294 Diag(Loc: ELoc, DiagID: diag::err_omp_wrong_dsa)
21295 << getOpenMPClauseNameForDiag(C: DVar.CKind)
21296 << getOpenMPClauseNameForDiag(C: OMPC_lastprivate);
21297 reportOriginalDsa(SemaRef, DSAStack, D, DVar);
21298 continue;
21299 }
21300
21301 // OpenMP [2.14.3.5, Restrictions, p.2]
21302 // A list item that is private within a parallel region, or that appears in
21303 // the reduction clause of a parallel construct, must not appear in a
21304 // lastprivate clause on a worksharing construct if any of the corresponding
21305 // worksharing regions ever binds to any of the corresponding parallel
21306 // regions.
21307 DSAStackTy::DSAVarData TopDVar = DVar;
21308 if (isOpenMPWorksharingDirective(DKind: CurrDir) &&
21309 !isOpenMPParallelDirective(DKind: CurrDir) &&
21310 !isOpenMPTeamsDirective(DKind: CurrDir)) {
21311 DVar = DSAStack->getImplicitDSA(D, FromParent: true);
21312 if (DVar.CKind != OMPC_shared) {
21313 Diag(Loc: ELoc, DiagID: diag::err_omp_required_access)
21314 << getOpenMPClauseNameForDiag(C: OMPC_lastprivate)
21315 << getOpenMPClauseNameForDiag(C: OMPC_shared);
21316 reportOriginalDsa(SemaRef, DSAStack, D, DVar);
21317 continue;
21318 }
21319 }
21320
21321 // OpenMP [2.14.3.5, Restrictions, C++, p.1,2]
21322 // A variable of class type (or array thereof) that appears in a
21323 // lastprivate clause requires an accessible, unambiguous default
21324 // constructor for the class type, unless the list item is also specified
21325 // in a firstprivate clause.
21326 // A variable of class type (or array thereof) that appears in a
21327 // lastprivate clause requires an accessible, unambiguous copy assignment
21328 // operator for the class type.
21329 Type = getASTContext().getBaseElementType(QT: Type).getNonReferenceType();
21330 VarDecl *SrcVD = buildVarDecl(SemaRef, Loc: ERange.getBegin(),
21331 Type: Type.getUnqualifiedType(), Name: ".lastprivate.src",
21332 Attrs: D->hasAttrs() ? &D->getAttrs() : nullptr);
21333 DeclRefExpr *PseudoSrcExpr =
21334 buildDeclRefExpr(S&: SemaRef, D: SrcVD, Ty: Type.getUnqualifiedType(), Loc: ELoc);
21335 VarDecl *DstVD =
21336 buildVarDecl(SemaRef, Loc: ERange.getBegin(), Type, Name: ".lastprivate.dst",
21337 Attrs: D->hasAttrs() ? &D->getAttrs() : nullptr);
21338 DeclRefExpr *PseudoDstExpr = buildDeclRefExpr(S&: SemaRef, D: DstVD, Ty: Type, Loc: ELoc);
21339 // For arrays generate assignment operation for single element and replace
21340 // it by the original array element in CodeGen.
21341 ExprResult AssignmentOp = SemaRef.BuildBinOp(/*S=*/nullptr, OpLoc: ELoc, Opc: BO_Assign,
21342 LHSExpr: PseudoDstExpr, RHSExpr: PseudoSrcExpr);
21343 if (AssignmentOp.isInvalid())
21344 continue;
21345 AssignmentOp = SemaRef.ActOnFinishFullExpr(Expr: AssignmentOp.get(), CC: ELoc,
21346 /*DiscardedValue=*/false);
21347 if (AssignmentOp.isInvalid())
21348 continue;
21349
21350 DeclRefExpr *Ref = nullptr;
21351 if (!VD && !SemaRef.CurContext->isDependentContext()) {
21352 if (TopDVar.CKind == OMPC_firstprivate) {
21353 Ref = TopDVar.PrivateCopy;
21354 } else {
21355 Ref = buildCapture(S&: SemaRef, D, CaptureExpr: SimpleRefExpr, /*WithInit=*/false);
21356 if (!isOpenMPCapturedDecl(D))
21357 ExprCaptures.push_back(Elt: Ref->getDecl());
21358 }
21359 if (Ref &&
21360 ((TopDVar.CKind == OMPC_firstprivate && !TopDVar.PrivateCopy) ||
21361 (!isOpenMPCapturedDecl(D) &&
21362 Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()))) {
21363 ExprResult RefRes = SemaRef.DefaultLvalueConversion(E: Ref);
21364 if (!RefRes.isUsable())
21365 continue;
21366 ExprResult PostUpdateRes =
21367 SemaRef.BuildBinOp(DSAStack->getCurScope(), OpLoc: ELoc, Opc: BO_Assign,
21368 LHSExpr: SimpleRefExpr, RHSExpr: RefRes.get());
21369 if (!PostUpdateRes.isUsable())
21370 continue;
21371 ExprPostUpdates.push_back(
21372 Elt: SemaRef.IgnoredValueConversions(E: PostUpdateRes.get()).get());
21373 }
21374 }
21375 DSAStack->addDSA(D, E: RefExpr->IgnoreParens(), A: OMPC_lastprivate, PrivateCopy: Ref);
21376 bool IsBindingDecl = isa<BindingDecl>(Val: D);
21377 Vars.push_back(
21378 Elt: (VD || IsBindingDecl || SemaRef.CurContext->isDependentContext())
21379 ? RefExpr->IgnoreParens()
21380 : Ref);
21381 SrcExprs.push_back(Elt: PseudoSrcExpr);
21382 DstExprs.push_back(Elt: PseudoDstExpr);
21383 AssignmentOps.push_back(Elt: AssignmentOp.get());
21384 }
21385
21386 if (Vars.empty())
21387 return nullptr;
21388
21389 return OMPLastprivateClause::Create(
21390 C: getASTContext(), StartLoc, LParenLoc, EndLoc, VL: Vars, SrcExprs, DstExprs,
21391 AssignmentOps, LPKind, LPKindLoc, ColonLoc,
21392 PreInit: buildPreInits(Context&: getASTContext(), PreInits: ExprCaptures),
21393 PostUpdate: buildPostUpdate(S&: SemaRef, PostUpdates: ExprPostUpdates));
21394}
21395
21396OMPClause *SemaOpenMP::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
21397 SourceLocation StartLoc,
21398 SourceLocation LParenLoc,
21399 SourceLocation EndLoc) {
21400 SmallVector<Expr *, 8> Vars;
21401 for (Expr *RefExpr : VarList) {
21402 assert(RefExpr && "NULL expr in OpenMP shared clause.");
21403 SourceLocation ELoc;
21404 SourceRange ERange;
21405 Expr *SimpleRefExpr = RefExpr;
21406 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange);
21407 if (Res.second) {
21408 // It will be analyzed later.
21409 Vars.push_back(Elt: RefExpr);
21410 }
21411 ValueDecl *D = Res.first;
21412 if (!D)
21413 continue;
21414
21415 auto *VD = dyn_cast<VarDecl>(Val: D);
21416 // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
21417 // in a Construct]
21418 // Variables with the predetermined data-sharing attributes may not be
21419 // listed in data-sharing attributes clauses, except for the cases
21420 // listed below. For these exceptions only, listing a predetermined
21421 // variable in a data-sharing attribute clause is allowed and overrides
21422 // the variable's predetermined data-sharing attributes.
21423 DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false);
21424 if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared &&
21425 DVar.RefExpr) {
21426 Diag(Loc: ELoc, DiagID: diag::err_omp_wrong_dsa)
21427 << getOpenMPClauseNameForDiag(C: DVar.CKind)
21428 << getOpenMPClauseNameForDiag(C: OMPC_shared);
21429 reportOriginalDsa(SemaRef, DSAStack, D, DVar);
21430 continue;
21431 }
21432
21433 DeclRefExpr *Ref = nullptr;
21434 if (!VD && isOpenMPCapturedDecl(D) &&
21435 !SemaRef.CurContext->isDependentContext())
21436 Ref = buildCapture(S&: SemaRef, D, CaptureExpr: SimpleRefExpr, /*WithInit=*/true);
21437 DSAStack->addDSA(D, E: RefExpr->IgnoreParens(), A: OMPC_shared, PrivateCopy: Ref);
21438 Vars.push_back(Elt: (VD || !Ref || SemaRef.CurContext->isDependentContext())
21439 ? RefExpr->IgnoreParens()
21440 : Ref);
21441 }
21442
21443 if (Vars.empty())
21444 return nullptr;
21445
21446 return OMPSharedClause::Create(C: getASTContext(), StartLoc, LParenLoc, EndLoc,
21447 VL: Vars);
21448}
21449
21450namespace {
21451class DSARefChecker : public StmtVisitor<DSARefChecker, bool> {
21452 DSAStackTy *Stack;
21453
21454public:
21455 bool VisitDeclRefExpr(DeclRefExpr *E) {
21456 if (auto *VD = dyn_cast<VarDecl>(Val: E->getDecl())) {
21457 DSAStackTy::DSAVarData DVar = Stack->getTopDSA(D: VD, /*FromParent=*/false);
21458 if (DVar.CKind == OMPC_shared && !DVar.RefExpr)
21459 return false;
21460 if (DVar.CKind != OMPC_unknown)
21461 return true;
21462 DSAStackTy::DSAVarData DVarPrivate = Stack->hasDSA(
21463 D: VD,
21464 CPred: [](OpenMPClauseKind C, bool AppliedToPointee, bool) {
21465 return isOpenMPPrivate(Kind: C) && !AppliedToPointee;
21466 },
21467 DPred: [](OpenMPDirectiveKind) { return true; },
21468 /*FromParent=*/true);
21469 return DVarPrivate.CKind != OMPC_unknown;
21470 }
21471 return false;
21472 }
21473 bool VisitStmt(Stmt *S) {
21474 for (Stmt *Child : S->children()) {
21475 if (Child && Visit(S: Child))
21476 return true;
21477 }
21478 return false;
21479 }
21480 explicit DSARefChecker(DSAStackTy *S) : Stack(S) {}
21481};
21482} // namespace
21483
21484namespace {
21485// Transform MemberExpression for specified FieldDecl of current class to
21486// DeclRefExpr to specified OMPCapturedExprDecl.
21487class TransformExprToCaptures : public TreeTransform<TransformExprToCaptures> {
21488 typedef TreeTransform<TransformExprToCaptures> BaseTransform;
21489 ValueDecl *Field = nullptr;
21490 DeclRefExpr *CapturedExpr = nullptr;
21491
21492public:
21493 TransformExprToCaptures(Sema &SemaRef, ValueDecl *FieldDecl)
21494 : BaseTransform(SemaRef), Field(FieldDecl), CapturedExpr(nullptr) {}
21495
21496 ExprResult TransformMemberExpr(MemberExpr *E) {
21497 if (isa<CXXThisExpr>(Val: E->getBase()->IgnoreParenImpCasts()) &&
21498 E->getMemberDecl() == Field) {
21499 CapturedExpr = buildCapture(S&: SemaRef, D: Field, CaptureExpr: E, /*WithInit=*/false);
21500 return CapturedExpr;
21501 }
21502 return BaseTransform::TransformMemberExpr(E);
21503 }
21504 DeclRefExpr *getCapturedExpr() { return CapturedExpr; }
21505};
21506} // namespace
21507
21508template <typename T, typename U>
21509static T filterLookupForUDReductionAndMapper(
21510 SmallVectorImpl<U> &Lookups, const llvm::function_ref<T(ValueDecl *)> Gen) {
21511 for (U &Set : Lookups) {
21512 for (auto *D : Set) {
21513 if (T Res = Gen(cast<ValueDecl>(D)))
21514 return Res;
21515 }
21516 }
21517 return T();
21518}
21519
21520static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) {
21521 assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case");
21522
21523 for (auto *RD : D->redecls()) {
21524 // Don't bother with extra checks if we already know this one isn't visible.
21525 if (RD == D)
21526 continue;
21527
21528 auto ND = cast<NamedDecl>(Val: RD);
21529 if (LookupResult::isVisible(SemaRef, D: ND))
21530 return ND;
21531 }
21532
21533 return nullptr;
21534}
21535
21536static void
21537argumentDependentLookup(Sema &SemaRef, const DeclarationNameInfo &Id,
21538 SourceLocation Loc, QualType Ty,
21539 SmallVectorImpl<UnresolvedSet<8>> &Lookups) {
21540 // Find all of the associated namespaces and classes based on the
21541 // arguments we have.
21542 Sema::AssociatedNamespaceSet AssociatedNamespaces;
21543 Sema::AssociatedClassSet AssociatedClasses;
21544 OpaqueValueExpr OVE(Loc, Ty, VK_LValue);
21545 SemaRef.FindAssociatedClassesAndNamespaces(InstantiationLoc: Loc, Args: &OVE, AssociatedNamespaces,
21546 AssociatedClasses);
21547
21548 // C++ [basic.lookup.argdep]p3:
21549 // Let X be the lookup set produced by unqualified lookup (3.4.1)
21550 // and let Y be the lookup set produced by argument dependent
21551 // lookup (defined as follows). If X contains [...] then Y is
21552 // empty. Otherwise Y is the set of declarations found in the
21553 // namespaces associated with the argument types as described
21554 // below. The set of declarations found by the lookup of the name
21555 // is the union of X and Y.
21556 //
21557 // Here, we compute Y and add its members to the overloaded
21558 // candidate set.
21559 for (auto *NS : AssociatedNamespaces) {
21560 // When considering an associated namespace, the lookup is the
21561 // same as the lookup performed when the associated namespace is
21562 // used as a qualifier (3.4.3.2) except that:
21563 //
21564 // -- Any using-directives in the associated namespace are
21565 // ignored.
21566 //
21567 // -- Any namespace-scope friend functions declared in
21568 // associated classes are visible within their respective
21569 // namespaces even if they are not visible during an ordinary
21570 // lookup (11.4).
21571 DeclContext::lookup_result R = NS->lookup(Name: Id.getName());
21572 for (auto *D : R) {
21573 auto *Underlying = D;
21574 if (auto *USD = dyn_cast<UsingShadowDecl>(Val: D))
21575 Underlying = USD->getTargetDecl();
21576
21577 if (!isa<OMPDeclareReductionDecl>(Val: Underlying) &&
21578 !isa<OMPDeclareMapperDecl>(Val: Underlying))
21579 continue;
21580
21581 if (!SemaRef.isVisible(D)) {
21582 D = findAcceptableDecl(SemaRef, D);
21583 if (!D)
21584 continue;
21585 if (auto *USD = dyn_cast<UsingShadowDecl>(Val: D))
21586 Underlying = USD->getTargetDecl();
21587 }
21588 Lookups.emplace_back();
21589 Lookups.back().addDecl(D: Underlying);
21590 }
21591 }
21592}
21593
21594static ExprResult
21595buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
21596 Scope *S, CXXScopeSpec &ReductionIdScopeSpec,
21597 const DeclarationNameInfo &ReductionId, QualType Ty,
21598 CXXCastPath &BasePath, Expr *UnresolvedReduction) {
21599 if (ReductionIdScopeSpec.isInvalid())
21600 return ExprError();
21601 SmallVector<UnresolvedSet<8>, 4> Lookups;
21602 if (S) {
21603 LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName);
21604 Lookup.suppressDiagnostics();
21605 while (S && SemaRef.LookupParsedName(R&: Lookup, S, SS: &ReductionIdScopeSpec,
21606 /*ObjectType=*/QualType())) {
21607 NamedDecl *D = Lookup.getRepresentativeDecl();
21608 do {
21609 S = S->getParent();
21610 } while (S && !S->isDeclScope(D));
21611 if (S)
21612 S = S->getParent();
21613 Lookups.emplace_back();
21614 Lookups.back().append(I: Lookup.begin(), E: Lookup.end());
21615 Lookup.clear();
21616 }
21617 } else if (auto *ULE =
21618 cast_or_null<UnresolvedLookupExpr>(Val: UnresolvedReduction)) {
21619 Lookups.push_back(Elt: UnresolvedSet<8>());
21620 Decl *PrevD = nullptr;
21621 for (NamedDecl *D : ULE->decls()) {
21622 if (D == PrevD)
21623 Lookups.push_back(Elt: UnresolvedSet<8>());
21624 else if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(Val: D))
21625 Lookups.back().addDecl(D: DRD);
21626 PrevD = D;
21627 }
21628 }
21629 if (SemaRef.CurContext->isDependentContext() || Ty->isDependentType() ||
21630 Ty->isInstantiationDependentType() ||
21631 Ty->containsUnexpandedParameterPack() ||
21632 filterLookupForUDReductionAndMapper<bool>(Lookups, Gen: [](ValueDecl *D) {
21633 return !D->isInvalidDecl() &&
21634 (D->getType()->isDependentType() ||
21635 D->getType()->isInstantiationDependentType() ||
21636 D->getType()->containsUnexpandedParameterPack());
21637 })) {
21638 UnresolvedSet<8> ResSet;
21639 for (const UnresolvedSet<8> &Set : Lookups) {
21640 if (Set.empty())
21641 continue;
21642 ResSet.append(I: Set.begin(), E: Set.end());
21643 // The last item marks the end of all declarations at the specified scope.
21644 ResSet.addDecl(D: Set[Set.size() - 1]);
21645 }
21646 return UnresolvedLookupExpr::Create(
21647 Context: SemaRef.Context, /*NamingClass=*/nullptr,
21648 QualifierLoc: ReductionIdScopeSpec.getWithLocInContext(Context&: SemaRef.Context), NameInfo: ReductionId,
21649 /*ADL=*/RequiresADL: true, Begin: ResSet.begin(), End: ResSet.end(), /*KnownDependent=*/false,
21650 /*KnownInstantiationDependent=*/false);
21651 }
21652 // Lookup inside the classes.
21653 // C++ [over.match.oper]p3:
21654 // For a unary operator @ with an operand of a type whose
21655 // cv-unqualified version is T1, and for a binary operator @ with
21656 // a left operand of a type whose cv-unqualified version is T1 and
21657 // a right operand of a type whose cv-unqualified version is T2,
21658 // three sets of candidate functions, designated member
21659 // candidates, non-member candidates and built-in candidates, are
21660 // constructed as follows:
21661 // -- If T1 is a complete class type or a class currently being
21662 // defined, the set of member candidates is the result of the
21663 // qualified lookup of T1::operator@ (13.3.1.1.1); otherwise,
21664 // the set of member candidates is empty.
21665 LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName);
21666 Lookup.suppressDiagnostics();
21667 if (Ty->isRecordType()) {
21668 // Complete the type if it can be completed.
21669 // If the type is neither complete nor being defined, bail out now.
21670 bool IsComplete = SemaRef.isCompleteType(Loc, T: Ty);
21671 auto *RD = Ty->castAsRecordDecl();
21672 if (IsComplete || RD->isBeingDefined()) {
21673 Lookup.clear();
21674 SemaRef.LookupQualifiedName(R&: Lookup, LookupCtx: RD);
21675 if (Lookup.empty()) {
21676 Lookups.emplace_back();
21677 Lookups.back().append(I: Lookup.begin(), E: Lookup.end());
21678 }
21679 }
21680 }
21681 // Perform ADL.
21682 if (SemaRef.getLangOpts().CPlusPlus)
21683 argumentDependentLookup(SemaRef, Id: ReductionId, Loc, Ty, Lookups);
21684 if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>(
21685 Lookups, Gen: [&SemaRef, Ty](ValueDecl *D) -> ValueDecl * {
21686 if (!D->isInvalidDecl() &&
21687 SemaRef.Context.hasSameType(T1: D->getType(), T2: Ty))
21688 return D;
21689 return nullptr;
21690 }))
21691 return SemaRef.BuildDeclRefExpr(D: VD, Ty: VD->getType().getNonReferenceType(),
21692 VK: VK_LValue, Loc);
21693 if (SemaRef.getLangOpts().CPlusPlus) {
21694 if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>(
21695 Lookups, Gen: [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * {
21696 if (!D->isInvalidDecl() &&
21697 SemaRef.IsDerivedFrom(Loc, Derived: Ty, Base: D->getType()) &&
21698 !Ty.isMoreQualifiedThan(other: D->getType(),
21699 Ctx: SemaRef.getASTContext()))
21700 return D;
21701 return nullptr;
21702 })) {
21703 CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
21704 /*DetectVirtual=*/false);
21705 if (SemaRef.IsDerivedFrom(Loc, Derived: Ty, Base: VD->getType(), Paths)) {
21706 if (!Paths.isAmbiguous(BaseType: SemaRef.Context.getCanonicalType(
21707 T: VD->getType().getUnqualifiedType()))) {
21708 if (SemaRef.CheckBaseClassAccess(
21709 AccessLoc: Loc, Base: VD->getType(), Derived: Ty, Path: Paths.front(),
21710 /*DiagID=*/0) != Sema::AR_inaccessible) {
21711 SemaRef.BuildBasePathArray(Paths, BasePath);
21712 return SemaRef.BuildDeclRefExpr(
21713 D: VD, Ty: VD->getType().getNonReferenceType(), VK: VK_LValue, Loc);
21714 }
21715 }
21716 }
21717 }
21718 }
21719 if (ReductionIdScopeSpec.isSet()) {
21720 SemaRef.Diag(Loc, DiagID: diag::err_omp_not_resolved_reduction_identifier)
21721 << Ty << Range;
21722 return ExprError();
21723 }
21724 return ExprEmpty();
21725}
21726
21727namespace {
21728/// Data for the reduction-based clauses.
21729struct ReductionData {
21730 /// List of original reduction items.
21731 SmallVector<Expr *, 8> Vars;
21732 /// List of private copies of the reduction items.
21733 SmallVector<Expr *, 8> Privates;
21734 /// LHS expressions for the reduction_op expressions.
21735 SmallVector<Expr *, 8> LHSs;
21736 /// RHS expressions for the reduction_op expressions.
21737 SmallVector<Expr *, 8> RHSs;
21738 /// Reduction operation expression.
21739 SmallVector<Expr *, 8> ReductionOps;
21740 /// inscan copy operation expressions.
21741 SmallVector<Expr *, 8> InscanCopyOps;
21742 /// inscan copy temp array expressions for prefix sums.
21743 SmallVector<Expr *, 8> InscanCopyArrayTemps;
21744 /// inscan copy temp array element expressions for prefix sums.
21745 SmallVector<Expr *, 8> InscanCopyArrayElems;
21746 /// Taskgroup descriptors for the corresponding reduction items in
21747 /// in_reduction clauses.
21748 SmallVector<Expr *, 8> TaskgroupDescriptors;
21749 /// List of captures for clause.
21750 SmallVector<Decl *, 4> ExprCaptures;
21751 /// List of postupdate expressions.
21752 SmallVector<Expr *, 4> ExprPostUpdates;
21753 /// Reduction modifier.
21754 unsigned RedModifier = 0;
21755 /// Original modifier.
21756 unsigned OrigSharingModifier = 0;
21757 /// Private Variable Reduction
21758 SmallVector<bool, 8> IsPrivateVarReduction;
21759 ReductionData() = delete;
21760 /// Reserves required memory for the reduction data.
21761 ReductionData(unsigned Size, unsigned Modifier = 0, unsigned OrgModifier = 0)
21762 : RedModifier(Modifier), OrigSharingModifier(OrgModifier) {
21763 Vars.reserve(N: Size);
21764 Privates.reserve(N: Size);
21765 LHSs.reserve(N: Size);
21766 RHSs.reserve(N: Size);
21767 ReductionOps.reserve(N: Size);
21768 IsPrivateVarReduction.reserve(N: Size);
21769 if (RedModifier == OMPC_REDUCTION_inscan) {
21770 InscanCopyOps.reserve(N: Size);
21771 InscanCopyArrayTemps.reserve(N: Size);
21772 InscanCopyArrayElems.reserve(N: Size);
21773 }
21774 TaskgroupDescriptors.reserve(N: Size);
21775 ExprCaptures.reserve(N: Size);
21776 ExprPostUpdates.reserve(N: Size);
21777 }
21778 /// Stores reduction item and reduction operation only (required for dependent
21779 /// reduction item).
21780 void push(Expr *Item, Expr *ReductionOp) {
21781 Vars.emplace_back(Args&: Item);
21782 Privates.emplace_back(Args: nullptr);
21783 LHSs.emplace_back(Args: nullptr);
21784 RHSs.emplace_back(Args: nullptr);
21785 ReductionOps.emplace_back(Args&: ReductionOp);
21786 IsPrivateVarReduction.emplace_back(Args: false);
21787 TaskgroupDescriptors.emplace_back(Args: nullptr);
21788 if (RedModifier == OMPC_REDUCTION_inscan) {
21789 InscanCopyOps.push_back(Elt: nullptr);
21790 InscanCopyArrayTemps.push_back(Elt: nullptr);
21791 InscanCopyArrayElems.push_back(Elt: nullptr);
21792 }
21793 }
21794 /// Stores reduction data.
21795 void push(Expr *Item, Expr *Private, Expr *LHS, Expr *RHS, Expr *ReductionOp,
21796 Expr *TaskgroupDescriptor, Expr *CopyOp, Expr *CopyArrayTemp,
21797 Expr *CopyArrayElem, bool IsPrivate) {
21798 Vars.emplace_back(Args&: Item);
21799 Privates.emplace_back(Args&: Private);
21800 LHSs.emplace_back(Args&: LHS);
21801 RHSs.emplace_back(Args&: RHS);
21802 ReductionOps.emplace_back(Args&: ReductionOp);
21803 TaskgroupDescriptors.emplace_back(Args&: TaskgroupDescriptor);
21804 if (RedModifier == OMPC_REDUCTION_inscan) {
21805 InscanCopyOps.push_back(Elt: CopyOp);
21806 InscanCopyArrayTemps.push_back(Elt: CopyArrayTemp);
21807 InscanCopyArrayElems.push_back(Elt: CopyArrayElem);
21808 } else {
21809 assert(CopyOp == nullptr && CopyArrayTemp == nullptr &&
21810 CopyArrayElem == nullptr &&
21811 "Copy operation must be used for inscan reductions only.");
21812 }
21813 IsPrivateVarReduction.emplace_back(Args&: IsPrivate);
21814 }
21815};
21816} // namespace
21817
21818static bool checkOMPArraySectionConstantForReduction(
21819 ASTContext &Context, const ArraySectionExpr *OASE, bool &SingleElement,
21820 SmallVectorImpl<llvm::APSInt> &ArraySizes) {
21821 const Expr *Length = OASE->getLength();
21822 if (Length == nullptr) {
21823 // For array sections of the form [1:] or [:], we would need to analyze
21824 // the lower bound...
21825 if (OASE->getColonLocFirst().isValid())
21826 return false;
21827
21828 // This is an array subscript which has implicit length 1!
21829 SingleElement = true;
21830 ArraySizes.push_back(Elt: llvm::APSInt::get(X: 1));
21831 } else {
21832 Expr::EvalResult Result;
21833 if (!Length->EvaluateAsInt(Result, Ctx: Context))
21834 return false;
21835
21836 llvm::APSInt ConstantLengthValue = Result.Val.getInt();
21837 SingleElement = (ConstantLengthValue.getSExtValue() == 1);
21838 ArraySizes.push_back(Elt: ConstantLengthValue);
21839 }
21840
21841 // Get the base of this array section and walk up from there.
21842 const Expr *Base = OASE->getBase()->IgnoreParenImpCasts();
21843
21844 // We require length = 1 for all array sections except the right-most to
21845 // guarantee that the memory region is contiguous and has no holes in it.
21846 while (const auto *TempOASE = dyn_cast<ArraySectionExpr>(Val: Base)) {
21847 Length = TempOASE->getLength();
21848 if (Length == nullptr) {
21849 // For array sections of the form [1:] or [:], we would need to analyze
21850 // the lower bound...
21851 if (OASE->getColonLocFirst().isValid())
21852 return false;
21853
21854 // This is an array subscript which has implicit length 1!
21855 llvm::APSInt ConstantOne = llvm::APSInt::get(X: 1);
21856 ArraySizes.push_back(Elt: ConstantOne);
21857 } else {
21858 Expr::EvalResult Result;
21859 if (!Length->EvaluateAsInt(Result, Ctx: Context))
21860 return false;
21861
21862 llvm::APSInt ConstantLengthValue = Result.Val.getInt();
21863 if (ConstantLengthValue.getSExtValue() != 1)
21864 return false;
21865
21866 ArraySizes.push_back(Elt: ConstantLengthValue);
21867 }
21868 Base = TempOASE->getBase()->IgnoreParenImpCasts();
21869 }
21870
21871 // If we have a single element, we don't need to add the implicit lengths.
21872 if (!SingleElement) {
21873 while (const auto *TempASE = dyn_cast<ArraySubscriptExpr>(Val: Base)) {
21874 // Has implicit length 1!
21875 llvm::APSInt ConstantOne = llvm::APSInt::get(X: 1);
21876 ArraySizes.push_back(Elt: ConstantOne);
21877 Base = TempASE->getBase()->IgnoreParenImpCasts();
21878 }
21879 }
21880
21881 // This array section can be privatized as a single value or as a constant
21882 // sized array.
21883 return true;
21884}
21885
21886static BinaryOperatorKind
21887getRelatedCompoundReductionOp(BinaryOperatorKind BOK) {
21888 if (BOK == BO_Add)
21889 return BO_AddAssign;
21890 if (BOK == BO_Mul)
21891 return BO_MulAssign;
21892 if (BOK == BO_And)
21893 return BO_AndAssign;
21894 if (BOK == BO_Or)
21895 return BO_OrAssign;
21896 if (BOK == BO_Xor)
21897 return BO_XorAssign;
21898 return BOK;
21899}
21900
21901static bool actOnOMPReductionKindClause(
21902 Sema &S, DSAStackTy *Stack, OpenMPClauseKind ClauseKind,
21903 ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
21904 SourceLocation ColonLoc, SourceLocation EndLoc,
21905 CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
21906 ArrayRef<Expr *> UnresolvedReductions, ReductionData &RD) {
21907 DeclarationName DN = ReductionId.getName();
21908 OverloadedOperatorKind OOK = DN.getCXXOverloadedOperator();
21909 BinaryOperatorKind BOK = BO_Comma;
21910
21911 ASTContext &Context = S.Context;
21912 // OpenMP [2.14.3.6, reduction clause]
21913 // C
21914 // reduction-identifier is either an identifier or one of the following
21915 // operators: +, -, *, &, |, ^, && and ||
21916 // C++
21917 // reduction-identifier is either an id-expression or one of the following
21918 // operators: +, -, *, &, |, ^, && and ||
21919 switch (OOK) {
21920 case OO_Plus:
21921 BOK = BO_Add;
21922 break;
21923 case OO_Minus:
21924 // Minus(-) operator is not supported in TR11 (OpenMP 6.0). Setting BOK to
21925 // BO_Comma will automatically diagnose it for OpenMP > 52 as not allowed
21926 // reduction identifier.
21927 if (S.LangOpts.OpenMP > 52)
21928 BOK = BO_Comma;
21929 else
21930 BOK = BO_Add;
21931 break;
21932 case OO_Star:
21933 BOK = BO_Mul;
21934 break;
21935 case OO_Amp:
21936 BOK = BO_And;
21937 break;
21938 case OO_Pipe:
21939 BOK = BO_Or;
21940 break;
21941 case OO_Caret:
21942 BOK = BO_Xor;
21943 break;
21944 case OO_AmpAmp:
21945 BOK = BO_LAnd;
21946 break;
21947 case OO_PipePipe:
21948 BOK = BO_LOr;
21949 break;
21950 case OO_New:
21951 case OO_Delete:
21952 case OO_Array_New:
21953 case OO_Array_Delete:
21954 case OO_Slash:
21955 case OO_Percent:
21956 case OO_Tilde:
21957 case OO_Exclaim:
21958 case OO_Equal:
21959 case OO_Less:
21960 case OO_Greater:
21961 case OO_LessEqual:
21962 case OO_GreaterEqual:
21963 case OO_PlusEqual:
21964 case OO_MinusEqual:
21965 case OO_StarEqual:
21966 case OO_SlashEqual:
21967 case OO_PercentEqual:
21968 case OO_CaretEqual:
21969 case OO_AmpEqual:
21970 case OO_PipeEqual:
21971 case OO_LessLess:
21972 case OO_GreaterGreater:
21973 case OO_LessLessEqual:
21974 case OO_GreaterGreaterEqual:
21975 case OO_EqualEqual:
21976 case OO_ExclaimEqual:
21977 case OO_Spaceship:
21978 case OO_PlusPlus:
21979 case OO_MinusMinus:
21980 case OO_Comma:
21981 case OO_ArrowStar:
21982 case OO_Arrow:
21983 case OO_Call:
21984 case OO_Subscript:
21985 case OO_Conditional:
21986 case OO_Coawait:
21987 case NUM_OVERLOADED_OPERATORS:
21988 llvm_unreachable("Unexpected reduction identifier");
21989 case OO_None:
21990 if (IdentifierInfo *II = DN.getAsIdentifierInfo()) {
21991 if (II->isStr(Str: "max"))
21992 BOK = BO_GT;
21993 else if (II->isStr(Str: "min"))
21994 BOK = BO_LT;
21995 }
21996 break;
21997 }
21998
21999 // OpenMP 5.2, 5.5.5 (see page 627, line 18) reduction Clause, Restrictions
22000 // A reduction clause with the minus (-) operator was deprecated
22001 if (OOK == OO_Minus && S.LangOpts.OpenMP == 52)
22002 S.Diag(Loc: ReductionId.getLoc(), DiagID: diag::warn_omp_minus_in_reduction_deprecated);
22003
22004 SourceRange ReductionIdRange;
22005 if (ReductionIdScopeSpec.isValid())
22006 ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc());
22007 else
22008 ReductionIdRange.setBegin(ReductionId.getBeginLoc());
22009 ReductionIdRange.setEnd(ReductionId.getEndLoc());
22010
22011 auto IR = UnresolvedReductions.begin(), ER = UnresolvedReductions.end();
22012 bool FirstIter = true;
22013 for (Expr *RefExpr : VarList) {
22014 assert(RefExpr && "nullptr expr in OpenMP reduction clause.");
22015 // OpenMP [2.1, C/C++]
22016 // A list item is a variable or array section, subject to the restrictions
22017 // specified in Section 2.4 on page 42 and in each of the sections
22018 // describing clauses and directives for which a list appears.
22019 // OpenMP [2.14.3.3, Restrictions, p.1]
22020 // A variable that is part of another variable (as an array or
22021 // structure element) cannot appear in a private clause.
22022 if (!FirstIter && IR != ER)
22023 ++IR;
22024 FirstIter = false;
22025 SourceLocation ELoc;
22026 SourceRange ERange;
22027 bool IsPrivate = false;
22028 Expr *SimpleRefExpr = RefExpr;
22029 auto Res = getPrivateItem(S, RefExpr&: SimpleRefExpr, ELoc, ERange,
22030 /*AllowArraySection=*/true);
22031 if (Res.second) {
22032 // Try to find 'declare reduction' corresponding construct before using
22033 // builtin/overloaded operators.
22034 QualType Type = Context.DependentTy;
22035 CXXCastPath BasePath;
22036 ExprResult DeclareReductionRef = buildDeclareReductionRef(
22037 SemaRef&: S, Loc: ELoc, Range: ERange, S: Stack->getCurScope(), ReductionIdScopeSpec,
22038 ReductionId, Ty: Type, BasePath, UnresolvedReduction: IR == ER ? nullptr : *IR);
22039 Expr *ReductionOp = nullptr;
22040 if (S.CurContext->isDependentContext() &&
22041 (DeclareReductionRef.isUnset() ||
22042 isa<UnresolvedLookupExpr>(Val: DeclareReductionRef.get())))
22043 ReductionOp = DeclareReductionRef.get();
22044 // It will be analyzed later.
22045 RD.push(Item: RefExpr, ReductionOp);
22046 }
22047 ValueDecl *D = Res.first;
22048 if (!D)
22049 continue;
22050
22051 Expr *TaskgroupDescriptor = nullptr;
22052 QualType Type;
22053 auto *ASE = dyn_cast<ArraySubscriptExpr>(Val: RefExpr->IgnoreParens());
22054 auto *OASE = dyn_cast<ArraySectionExpr>(Val: RefExpr->IgnoreParens());
22055 if (ASE) {
22056 Type = ASE->getType().getNonReferenceType();
22057 } else if (OASE) {
22058 QualType BaseType =
22059 ArraySectionExpr::getBaseOriginalType(Base: OASE->getBase());
22060 if (const auto *ATy = BaseType->getAsArrayTypeUnsafe())
22061 Type = ATy->getElementType();
22062 else
22063 Type = BaseType->getPointeeType();
22064 Type = Type.getNonReferenceType();
22065 } else {
22066 Type = Context.getBaseElementType(QT: D->getType().getNonReferenceType());
22067 }
22068 auto *VD = dyn_cast<VarDecl>(Val: D);
22069
22070 auto *BD = dyn_cast<BindingDecl>(Val: D);
22071 if (BD) {
22072 // FIXME: reductions on bindings are rejected.
22073 S.Diag(Loc: ELoc, DiagID: diag::err_omp_unsupported_on_binding) << 0;
22074 continue;
22075 }
22076
22077 // OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
22078 // A variable that appears in a private clause must not have an incomplete
22079 // type or a reference type.
22080 if (S.RequireCompleteType(Loc: ELoc, T: D->getType(),
22081 DiagID: diag::err_omp_reduction_incomplete_type))
22082 continue;
22083 // OpenMP [2.14.3.6, reduction clause, Restrictions]
22084 // A list item that appears in a reduction clause must not be
22085 // const-qualified.
22086 if (rejectConstNotMutableType(SemaRef&: S, D, Type, CKind: ClauseKind, ELoc,
22087 /*AcceptIfMutable=*/false, ListItemNotVar: ASE || OASE))
22088 continue;
22089
22090 OpenMPDirectiveKind CurrDir = Stack->getCurrentDirective();
22091 // OpenMP [2.9.3.6, Restrictions, C/C++, p.4]
22092 // If a list-item is a reference type then it must bind to the same object
22093 // for all threads of the team.
22094 if (!ASE && !OASE) {
22095 if (VD) {
22096 VarDecl *VDDef = VD->getDefinition();
22097 if (VD->getType()->isReferenceType() && VDDef && VDDef->hasInit()) {
22098 DSARefChecker Check(Stack);
22099 if (Check.Visit(S: VDDef->getInit())) {
22100 S.Diag(Loc: ELoc, DiagID: diag::err_omp_reduction_ref_type_arg)
22101 << getOpenMPClauseNameForDiag(C: ClauseKind) << ERange;
22102 S.Diag(Loc: VDDef->getLocation(), DiagID: diag::note_defined_here) << VDDef;
22103 continue;
22104 }
22105 }
22106 }
22107
22108 // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
22109 // in a Construct]
22110 // Variables with the predetermined data-sharing attributes may not be
22111 // listed in data-sharing attributes clauses, except for the cases
22112 // listed below. For these exceptions only, listing a predetermined
22113 // variable in a data-sharing attribute clause is allowed and overrides
22114 // the variable's predetermined data-sharing attributes.
22115 // OpenMP [2.14.3.6, Restrictions, p.3]
22116 // Any number of reduction clauses can be specified on the directive,
22117 // but a list item can appear only once in the reduction clauses for that
22118 // directive.
22119 DSAStackTy::DSAVarData DVar = Stack->getTopDSA(D, /*FromParent=*/false);
22120 if (DVar.CKind == OMPC_reduction) {
22121 S.Diag(Loc: ELoc, DiagID: diag::err_omp_once_referenced)
22122 << getOpenMPClauseNameForDiag(C: ClauseKind);
22123 if (DVar.RefExpr)
22124 S.Diag(Loc: DVar.RefExpr->getExprLoc(), DiagID: diag::note_omp_referenced);
22125 continue;
22126 }
22127 if (DVar.CKind != OMPC_unknown) {
22128 S.Diag(Loc: ELoc, DiagID: diag::err_omp_wrong_dsa)
22129 << getOpenMPClauseNameForDiag(C: DVar.CKind)
22130 << getOpenMPClauseNameForDiag(C: OMPC_reduction);
22131 reportOriginalDsa(SemaRef&: S, Stack, D, DVar);
22132 continue;
22133 }
22134
22135 // OpenMP [2.14.3.6, Restrictions, p.1]
22136 // A list item that appears in a reduction clause of a worksharing
22137 // construct must be shared in the parallel regions to which any of the
22138 // worksharing regions arising from the worksharing construct bind.
22139
22140 if (S.getLangOpts().OpenMP <= 52 &&
22141 isOpenMPWorksharingDirective(DKind: CurrDir) &&
22142 !isOpenMPParallelDirective(DKind: CurrDir) &&
22143 !isOpenMPTeamsDirective(DKind: CurrDir)) {
22144 DVar = Stack->getImplicitDSA(D, FromParent: true);
22145 if (DVar.CKind != OMPC_shared) {
22146 S.Diag(Loc: ELoc, DiagID: diag::err_omp_required_access)
22147 << getOpenMPClauseNameForDiag(C: OMPC_reduction)
22148 << getOpenMPClauseNameForDiag(C: OMPC_shared);
22149 reportOriginalDsa(SemaRef&: S, Stack, D, DVar);
22150 continue;
22151 }
22152 } else if (isOpenMPWorksharingDirective(DKind: CurrDir) &&
22153 !isOpenMPParallelDirective(DKind: CurrDir) &&
22154 !isOpenMPTeamsDirective(DKind: CurrDir)) {
22155 // OpenMP 6.0 [ 7.6.10 ]
22156 // Support Reduction over private variables with reduction clause.
22157 // A list item in a reduction clause can now be private in the enclosing
22158 // context. For orphaned constructs it is assumed to be shared unless
22159 // the original(private) modifier appears in the clause.
22160 DVar = Stack->getImplicitDSA(D, FromParent: true);
22161 // Determine if the variable should be considered private
22162 IsPrivate = DVar.CKind != OMPC_shared;
22163 bool IsOrphaned = false;
22164 OpenMPDirectiveKind ParentDir = Stack->getParentDirective();
22165 IsOrphaned = ParentDir == OMPD_unknown;
22166 if ((IsOrphaned &&
22167 RD.OrigSharingModifier == OMPC_ORIGINAL_SHARING_private))
22168 IsPrivate = true;
22169 }
22170 } else {
22171 // Threadprivates cannot be shared between threads, so dignose if the base
22172 // is a threadprivate variable.
22173 DSAStackTy::DSAVarData DVar = Stack->getTopDSA(D, /*FromParent=*/false);
22174 if (DVar.CKind == OMPC_threadprivate) {
22175 S.Diag(Loc: ELoc, DiagID: diag::err_omp_wrong_dsa)
22176 << getOpenMPClauseNameForDiag(C: DVar.CKind)
22177 << getOpenMPClauseNameForDiag(C: OMPC_reduction);
22178 reportOriginalDsa(SemaRef&: S, Stack, D, DVar);
22179 continue;
22180 }
22181 }
22182
22183 // Try to find 'declare reduction' corresponding construct before using
22184 // builtin/overloaded operators.
22185 CXXCastPath BasePath;
22186 ExprResult DeclareReductionRef = buildDeclareReductionRef(
22187 SemaRef&: S, Loc: ELoc, Range: ERange, S: Stack->getCurScope(), ReductionIdScopeSpec,
22188 ReductionId, Ty: Type, BasePath, UnresolvedReduction: IR == ER ? nullptr : *IR);
22189 if (DeclareReductionRef.isInvalid())
22190 continue;
22191 if (S.CurContext->isDependentContext() &&
22192 (DeclareReductionRef.isUnset() ||
22193 isa<UnresolvedLookupExpr>(Val: DeclareReductionRef.get()))) {
22194 RD.push(Item: RefExpr, ReductionOp: DeclareReductionRef.get());
22195 // Handle non-dependent inscan reduction variables in dependent contexts.
22196 if (RD.RedModifier == OMPC_REDUCTION_inscan)
22197 Stack->addDSA(D, E: RefExpr->IgnoreParens(), A: OMPC_reduction, PrivateCopy: nullptr,
22198 Modifier: RD.RedModifier, AppliedToPointee: ASE || OASE);
22199 continue;
22200 }
22201 if (BOK == BO_Comma && DeclareReductionRef.isUnset()) {
22202 // Not allowed reduction identifier is found.
22203 if (S.LangOpts.OpenMP > 52)
22204 S.Diag(Loc: ReductionId.getBeginLoc(),
22205 DiagID: diag::err_omp_unknown_reduction_identifier_since_omp_6_0)
22206 << Type << ReductionIdRange;
22207 else
22208 S.Diag(Loc: ReductionId.getBeginLoc(),
22209 DiagID: diag::err_omp_unknown_reduction_identifier_prior_omp_6_0)
22210 << Type << ReductionIdRange;
22211 continue;
22212 }
22213
22214 // OpenMP [2.14.3.6, reduction clause, Restrictions]
22215 // The type of a list item that appears in a reduction clause must be valid
22216 // for the reduction-identifier. For a max or min reduction in C, the type
22217 // of the list item must be an allowed arithmetic data type: char, int,
22218 // float, double, or _Bool, possibly modified with long, short, signed, or
22219 // unsigned. For a max or min reduction in C++, the type of the list item
22220 // must be an allowed arithmetic data type: char, wchar_t, int, float,
22221 // double, or bool, possibly modified with long, short, signed, or unsigned.
22222 if (DeclareReductionRef.isUnset()) {
22223 if ((BOK == BO_GT || BOK == BO_LT) &&
22224 !(Type->isScalarType() ||
22225 (S.getLangOpts().CPlusPlus && Type->isArithmeticType()))) {
22226 S.Diag(Loc: ELoc, DiagID: diag::err_omp_clause_not_arithmetic_type_arg)
22227 << getOpenMPClauseNameForDiag(C: ClauseKind)
22228 << S.getLangOpts().CPlusPlus;
22229 if (!ASE && !OASE) {
22230 bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
22231 VarDecl::DeclarationOnly;
22232 S.Diag(Loc: D->getLocation(),
22233 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
22234 << D;
22235 }
22236 continue;
22237 }
22238 if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) &&
22239 !S.getLangOpts().CPlusPlus && Type->isFloatingType()) {
22240 S.Diag(Loc: ELoc, DiagID: diag::err_omp_clause_floating_type_arg)
22241 << getOpenMPClauseNameForDiag(C: ClauseKind);
22242 if (!ASE && !OASE) {
22243 bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
22244 VarDecl::DeclarationOnly;
22245 S.Diag(Loc: D->getLocation(),
22246 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
22247 << D;
22248 }
22249 continue;
22250 }
22251 }
22252
22253 Type = Type.getNonLValueExprType(Context).getUnqualifiedType();
22254 VarDecl *LHSVD = buildVarDecl(SemaRef&: S, Loc: ELoc, Type, Name: ".reduction.lhs",
22255 Attrs: D->hasAttrs() ? &D->getAttrs() : nullptr);
22256 VarDecl *RHSVD = buildVarDecl(SemaRef&: S, Loc: ELoc, Type, Name: D->getName(),
22257 Attrs: D->hasAttrs() ? &D->getAttrs() : nullptr);
22258 QualType PrivateTy = Type;
22259
22260 // Try if we can determine constant lengths for all array sections and avoid
22261 // the VLA.
22262 bool ConstantLengthOASE = false;
22263 if (OASE) {
22264 bool SingleElement;
22265 llvm::SmallVector<llvm::APSInt, 4> ArraySizes;
22266 ConstantLengthOASE = checkOMPArraySectionConstantForReduction(
22267 Context, OASE, SingleElement, ArraySizes);
22268
22269 // If we don't have a single element, we must emit a constant array type.
22270 if (ConstantLengthOASE && !SingleElement) {
22271 for (llvm::APSInt &Size : ArraySizes)
22272 PrivateTy = Context.getConstantArrayType(EltTy: PrivateTy, ArySize: Size, SizeExpr: nullptr,
22273 ASM: ArraySizeModifier::Normal,
22274 /*IndexTypeQuals=*/0);
22275 }
22276 }
22277
22278 if ((OASE && !ConstantLengthOASE) ||
22279 (!OASE && !ASE &&
22280 D->getType().getNonReferenceType()->isVariablyModifiedType())) {
22281 if (!Context.getTargetInfo().isVLASupported()) {
22282 if (isOpenMPTargetExecutionDirective(DKind: Stack->getCurrentDirective())) {
22283 S.Diag(Loc: ELoc, DiagID: diag::err_omp_reduction_vla_unsupported) << !!OASE;
22284 S.Diag(Loc: ELoc, DiagID: diag::note_vla_unsupported);
22285 continue;
22286 } else {
22287 S.targetDiag(Loc: ELoc, DiagID: diag::err_omp_reduction_vla_unsupported) << !!OASE;
22288 S.targetDiag(Loc: ELoc, DiagID: diag::note_vla_unsupported);
22289 }
22290 }
22291 // For arrays/array sections only:
22292 // Create pseudo array type for private copy. The size for this array will
22293 // be generated during codegen.
22294 // For array subscripts or single variables Private Ty is the same as Type
22295 // (type of the variable or single array element).
22296 PrivateTy = Context.getVariableArrayType(
22297 EltTy: Type,
22298 NumElts: new (Context)
22299 OpaqueValueExpr(ELoc, Context.getSizeType(), VK_PRValue),
22300 ASM: ArraySizeModifier::Normal, /*IndexTypeQuals=*/0);
22301 } else if (!ASE && !OASE &&
22302 Context.getAsArrayType(T: D->getType().getNonReferenceType())) {
22303 PrivateTy = D->getType().getNonReferenceType();
22304 }
22305 // Private copy.
22306 VarDecl *PrivateVD =
22307 buildVarDecl(SemaRef&: S, Loc: ELoc, Type: PrivateTy, Name: D->getName(),
22308 Attrs: D->hasAttrs() ? &D->getAttrs() : nullptr,
22309 OrigRef: VD ? cast<DeclRefExpr>(Val: SimpleRefExpr) : nullptr);
22310 // Add initializer for private variable.
22311 Expr *Init = nullptr;
22312 DeclRefExpr *LHSDRE = buildDeclRefExpr(S, D: LHSVD, Ty: Type, Loc: ELoc);
22313 DeclRefExpr *RHSDRE = buildDeclRefExpr(S, D: RHSVD, Ty: Type, Loc: ELoc);
22314 if (DeclareReductionRef.isUsable()) {
22315 auto *DRDRef = DeclareReductionRef.getAs<DeclRefExpr>();
22316 auto *DRD = cast<OMPDeclareReductionDecl>(Val: DRDRef->getDecl());
22317 if (DRD->getInitializer()) {
22318 Init = DRDRef;
22319 RHSVD->setInit(DRDRef);
22320 RHSVD->setInitStyle(VarDecl::CallInit);
22321 }
22322 } else {
22323 switch (BOK) {
22324 case BO_Add:
22325 case BO_Xor:
22326 case BO_Or:
22327 case BO_LOr:
22328 // '+', '-', '^', '|', '||' reduction ops - initializer is '0'.
22329 if (Type->isScalarType() || Type->isAnyComplexType())
22330 Init = S.ActOnIntegerConstant(Loc: ELoc, /*Val=*/0).get();
22331 break;
22332 case BO_Mul:
22333 // '*' reduction op - initializer is '1'.
22334 // For C++ class types (e.g. std::complex) the OpenMP built-in
22335 // reduction identifiers are an extension: the standard only defines
22336 // identities for arithmetic (and, in Clang, _Complex) types. Without
22337 // an explicit initializer the private copy would be value-initialized,
22338 // which yields the *additive* identity (e.g. std::complex(0,0)) and is
22339 // wrong for multiplication. Initialize from the integer literal '1'
22340 // instead and let the converting constructor build the multiplicative
22341 // identity (e.g. std::complex(1) == (1,0)).
22342 if (Type->isScalarType() || Type->isAnyComplexType()) {
22343 Init = S.ActOnIntegerConstant(Loc: ELoc, /*Val=*/1).get();
22344 } else if (S.getLangOpts().CPlusPlus && Type->isRecordType()) {
22345 // Only use '1' when the type is actually copy-initializable from it.
22346 // Otherwise fall back to value-initialization (the previous behavior)
22347 // rather than rejecting the reduction, so a class that used to
22348 // compile keeps compiling. Such a class keeps its (possibly
22349 // incorrect) value-initialized identity, matching the pre-existing
22350 // behavior; BO_Add likewise relies on value-initialization for class
22351 // types.
22352 Expr *One = S.ActOnIntegerConstant(Loc: ELoc, /*Val=*/1).get();
22353 InitializedEntity Entity =
22354 InitializedEntity::InitializeTemporary(Type);
22355 InitializationKind Kind = InitializationKind::CreateCopy(InitLoc: ELoc, EqualLoc: ELoc);
22356 InitializationSequence Seq(S, Entity, Kind, One);
22357 if (Seq)
22358 Init = One;
22359 }
22360 break;
22361 case BO_LAnd:
22362 if (Type->isScalarType() || Type->isAnyComplexType()) {
22363 // '&&' reduction ops - initializer is '1'.
22364 Init = S.ActOnIntegerConstant(Loc: ELoc, /*Val=*/1).get();
22365 }
22366 break;
22367 case BO_And: {
22368 // '&' reduction op - initializer is '~0'.
22369 QualType OrigType = Type;
22370 if (auto *ComplexTy = OrigType->getAs<ComplexType>())
22371 Type = ComplexTy->getElementType();
22372 if (Type->isRealFloatingType()) {
22373 llvm::APFloat InitValue = llvm::APFloat::getAllOnesValue(
22374 Semantics: Context.getFloatTypeSemantics(T: Type));
22375 Init = FloatingLiteral::Create(C: Context, V: InitValue, /*isexact=*/true,
22376 Type, L: ELoc);
22377 } else if (Type->isScalarType()) {
22378 uint64_t Size = Context.getTypeSize(T: Type);
22379 QualType IntTy = Context.getIntTypeForBitwidth(DestWidth: Size, /*Signed=*/0);
22380 llvm::APInt InitValue = llvm::APInt::getAllOnes(numBits: Size);
22381 Init = IntegerLiteral::Create(C: Context, V: InitValue, type: IntTy, l: ELoc);
22382 }
22383 if (Init && OrigType->isAnyComplexType()) {
22384 // Init = 0xFFFF + 0xFFFFi;
22385 auto *Im = new (Context) ImaginaryLiteral(Init, OrigType);
22386 Init = S.CreateBuiltinBinOp(OpLoc: ELoc, Opc: BO_Add, LHSExpr: Init, RHSExpr: Im).get();
22387 }
22388 Type = OrigType;
22389 break;
22390 }
22391 case BO_LT:
22392 case BO_GT: {
22393 // 'min' reduction op - initializer is 'Largest representable number in
22394 // the reduction list item type'.
22395 // 'max' reduction op - initializer is 'Least representable number in
22396 // the reduction list item type'.
22397 if (Type->isIntegerType() || Type->isPointerType()) {
22398 bool IsSigned = Type->hasSignedIntegerRepresentation();
22399 uint64_t Size = Context.getTypeSize(T: Type);
22400 QualType IntTy =
22401 Context.getIntTypeForBitwidth(DestWidth: Size, /*Signed=*/IsSigned);
22402 llvm::APInt InitValue =
22403 (BOK != BO_LT) ? IsSigned ? llvm::APInt::getSignedMinValue(numBits: Size)
22404 : llvm::APInt::getMinValue(numBits: Size)
22405 : IsSigned ? llvm::APInt::getSignedMaxValue(numBits: Size)
22406 : llvm::APInt::getMaxValue(numBits: Size);
22407 Init = IntegerLiteral::Create(C: Context, V: InitValue, type: IntTy, l: ELoc);
22408 if (Type->isPointerType()) {
22409 // Cast to pointer type.
22410 ExprResult CastExpr = S.BuildCStyleCastExpr(
22411 LParenLoc: ELoc, Ty: Context.getTrivialTypeSourceInfo(T: Type, Loc: ELoc), RParenLoc: ELoc, Op: Init);
22412 if (CastExpr.isInvalid())
22413 continue;
22414 Init = CastExpr.get();
22415 }
22416 } else if (Type->isRealFloatingType()) {
22417 llvm::APFloat InitValue = llvm::APFloat::getLargest(
22418 Sem: Context.getFloatTypeSemantics(T: Type), Negative: BOK != BO_LT);
22419 Init = FloatingLiteral::Create(C: Context, V: InitValue, /*isexact=*/true,
22420 Type, L: ELoc);
22421 }
22422 break;
22423 }
22424 case BO_PtrMemD:
22425 case BO_PtrMemI:
22426 case BO_MulAssign:
22427 case BO_Div:
22428 case BO_Rem:
22429 case BO_Sub:
22430 case BO_Shl:
22431 case BO_Shr:
22432 case BO_LE:
22433 case BO_GE:
22434 case BO_EQ:
22435 case BO_NE:
22436 case BO_Cmp:
22437 case BO_AndAssign:
22438 case BO_XorAssign:
22439 case BO_OrAssign:
22440 case BO_Assign:
22441 case BO_AddAssign:
22442 case BO_SubAssign:
22443 case BO_DivAssign:
22444 case BO_RemAssign:
22445 case BO_ShlAssign:
22446 case BO_ShrAssign:
22447 case BO_Comma:
22448 llvm_unreachable("Unexpected reduction operation");
22449 }
22450 }
22451 if (Init && DeclareReductionRef.isUnset()) {
22452 S.AddInitializerToDecl(dcl: RHSVD, init: Init, /*DirectInit=*/false);
22453 // Store initializer for single element in private copy. Will be used
22454 // during codegen.
22455 PrivateVD->setInit(RHSVD->getInit());
22456 PrivateVD->setInitStyle(RHSVD->getInitStyle());
22457 } else if (!Init) {
22458 S.ActOnUninitializedDecl(dcl: RHSVD);
22459 // Store initializer for single element in private copy. Will be used
22460 // during codegen.
22461 PrivateVD->setInit(RHSVD->getInit());
22462 PrivateVD->setInitStyle(RHSVD->getInitStyle());
22463 }
22464 if (RHSVD->isInvalidDecl())
22465 continue;
22466 if (!RHSVD->hasInit() && DeclareReductionRef.isUnset()) {
22467 S.Diag(Loc: ELoc, DiagID: diag::err_omp_reduction_id_not_compatible)
22468 << Type << ReductionIdRange;
22469 bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
22470 VarDecl::DeclarationOnly;
22471 S.Diag(Loc: D->getLocation(),
22472 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
22473 << D;
22474 continue;
22475 }
22476 DeclRefExpr *PrivateDRE = buildDeclRefExpr(S, D: PrivateVD, Ty: PrivateTy, Loc: ELoc);
22477 ExprResult ReductionOp;
22478 if (DeclareReductionRef.isUsable()) {
22479 QualType RedTy = DeclareReductionRef.get()->getType();
22480 QualType PtrRedTy = Context.getPointerType(T: RedTy);
22481 ExprResult LHS = S.CreateBuiltinUnaryOp(OpLoc: ELoc, Opc: UO_AddrOf, InputExpr: LHSDRE);
22482 ExprResult RHS = S.CreateBuiltinUnaryOp(OpLoc: ELoc, Opc: UO_AddrOf, InputExpr: RHSDRE);
22483 if (!BasePath.empty()) {
22484 LHS = S.DefaultLvalueConversion(E: LHS.get());
22485 RHS = S.DefaultLvalueConversion(E: RHS.get());
22486 LHS = ImplicitCastExpr::Create(
22487 Context, T: PtrRedTy, Kind: CK_UncheckedDerivedToBase, Operand: LHS.get(), BasePath: &BasePath,
22488 Cat: LHS.get()->getValueKind(), FPO: FPOptionsOverride());
22489 RHS = ImplicitCastExpr::Create(
22490 Context, T: PtrRedTy, Kind: CK_UncheckedDerivedToBase, Operand: RHS.get(), BasePath: &BasePath,
22491 Cat: RHS.get()->getValueKind(), FPO: FPOptionsOverride());
22492 }
22493 FunctionProtoType::ExtProtoInfo EPI;
22494 QualType Params[] = {PtrRedTy, PtrRedTy};
22495 QualType FnTy = Context.getFunctionType(ResultTy: Context.VoidTy, Args: Params, EPI);
22496 auto *OVE = new (Context) OpaqueValueExpr(
22497 ELoc, Context.getPointerType(T: FnTy), VK_PRValue, OK_Ordinary,
22498 S.DefaultLvalueConversion(E: DeclareReductionRef.get()).get());
22499 Expr *Args[] = {LHS.get(), RHS.get()};
22500 ReductionOp =
22501 CallExpr::Create(Ctx: Context, Fn: OVE, Args, Ty: Context.VoidTy, VK: VK_PRValue, RParenLoc: ELoc,
22502 FPFeatures: S.CurFPFeatureOverrides());
22503 } else {
22504 BinaryOperatorKind CombBOK = getRelatedCompoundReductionOp(BOK);
22505 if (Type->isRecordType() && CombBOK != BOK) {
22506 Sema::TentativeAnalysisScope Trap(S);
22507 ReductionOp =
22508 S.BuildBinOp(S: Stack->getCurScope(), OpLoc: ReductionId.getBeginLoc(),
22509 Opc: CombBOK, LHSExpr: LHSDRE, RHSExpr: RHSDRE);
22510 }
22511 if (!ReductionOp.isUsable()) {
22512 ReductionOp =
22513 S.BuildBinOp(S: Stack->getCurScope(), OpLoc: ReductionId.getBeginLoc(), Opc: BOK,
22514 LHSExpr: LHSDRE, RHSExpr: RHSDRE);
22515 if (ReductionOp.isUsable()) {
22516 if (BOK != BO_LT && BOK != BO_GT) {
22517 ReductionOp =
22518 S.BuildBinOp(S: Stack->getCurScope(), OpLoc: ReductionId.getBeginLoc(),
22519 Opc: BO_Assign, LHSExpr: LHSDRE, RHSExpr: ReductionOp.get());
22520 } else {
22521 auto *ConditionalOp = new (Context)
22522 ConditionalOperator(ReductionOp.get(), ELoc, LHSDRE, ELoc,
22523 RHSDRE, Type, VK_LValue, OK_Ordinary);
22524 ReductionOp =
22525 S.BuildBinOp(S: Stack->getCurScope(), OpLoc: ReductionId.getBeginLoc(),
22526 Opc: BO_Assign, LHSExpr: LHSDRE, RHSExpr: ConditionalOp);
22527 }
22528 }
22529 }
22530 if (ReductionOp.isUsable())
22531 ReductionOp = S.ActOnFinishFullExpr(Expr: ReductionOp.get(),
22532 /*DiscardedValue=*/false);
22533 if (!ReductionOp.isUsable())
22534 continue;
22535 }
22536
22537 // Add copy operations for inscan reductions.
22538 // LHS = RHS;
22539 ExprResult CopyOpRes, TempArrayRes, TempArrayElem;
22540 if (ClauseKind == OMPC_reduction &&
22541 RD.RedModifier == OMPC_REDUCTION_inscan) {
22542 ExprResult RHS = S.DefaultLvalueConversion(E: RHSDRE);
22543 CopyOpRes = S.BuildBinOp(S: Stack->getCurScope(), OpLoc: ELoc, Opc: BO_Assign, LHSExpr: LHSDRE,
22544 RHSExpr: RHS.get());
22545 if (!CopyOpRes.isUsable())
22546 continue;
22547 CopyOpRes =
22548 S.ActOnFinishFullExpr(Expr: CopyOpRes.get(), /*DiscardedValue=*/true);
22549 if (!CopyOpRes.isUsable())
22550 continue;
22551 // For simd directive and simd-based directives in simd mode no need to
22552 // construct temp array, need just a single temp element.
22553 if (Stack->getCurrentDirective() == OMPD_simd ||
22554 (S.getLangOpts().OpenMPSimd &&
22555 isOpenMPSimdDirective(DKind: Stack->getCurrentDirective()))) {
22556 VarDecl *TempArrayVD =
22557 buildVarDecl(SemaRef&: S, Loc: ELoc, Type: PrivateTy, Name: D->getName(),
22558 Attrs: D->hasAttrs() ? &D->getAttrs() : nullptr);
22559 // Add a constructor to the temp decl.
22560 S.ActOnUninitializedDecl(dcl: TempArrayVD);
22561 TempArrayRes = buildDeclRefExpr(S, D: TempArrayVD, Ty: PrivateTy, Loc: ELoc);
22562 } else {
22563 // Build temp array for prefix sum.
22564 auto *Dim = new (S.Context)
22565 OpaqueValueExpr(ELoc, S.Context.getSizeType(), VK_PRValue);
22566 QualType ArrayTy = S.Context.getVariableArrayType(
22567 EltTy: PrivateTy, NumElts: Dim, ASM: ArraySizeModifier::Normal,
22568 /*IndexTypeQuals=*/0);
22569 VarDecl *TempArrayVD =
22570 buildVarDecl(SemaRef&: S, Loc: ELoc, Type: ArrayTy, Name: D->getName(),
22571 Attrs: D->hasAttrs() ? &D->getAttrs() : nullptr);
22572 // Add a constructor to the temp decl.
22573 S.ActOnUninitializedDecl(dcl: TempArrayVD);
22574 TempArrayRes = buildDeclRefExpr(S, D: TempArrayVD, Ty: ArrayTy, Loc: ELoc);
22575 TempArrayElem =
22576 S.DefaultFunctionArrayLvalueConversion(E: TempArrayRes.get());
22577 auto *Idx = new (S.Context)
22578 OpaqueValueExpr(ELoc, S.Context.getSizeType(), VK_PRValue);
22579 TempArrayElem = S.CreateBuiltinArraySubscriptExpr(Base: TempArrayElem.get(),
22580 LLoc: ELoc, Idx, RLoc: ELoc);
22581 }
22582 }
22583
22584 // OpenMP [2.15.4.6, Restrictions, p.2]
22585 // A list item that appears in an in_reduction clause of a task construct
22586 // must appear in a task_reduction clause of a construct associated with a
22587 // taskgroup region that includes the participating task in its taskgroup
22588 // set. The construct associated with the innermost region that meets this
22589 // condition must specify the same reduction-identifier as the in_reduction
22590 // clause.
22591 if (ClauseKind == OMPC_in_reduction) {
22592 SourceRange ParentSR;
22593 BinaryOperatorKind ParentBOK;
22594 const Expr *ParentReductionOp = nullptr;
22595 Expr *ParentBOKTD = nullptr, *ParentReductionOpTD = nullptr;
22596 DSAStackTy::DSAVarData ParentBOKDSA =
22597 Stack->getTopMostTaskgroupReductionData(D, SR&: ParentSR, BOK&: ParentBOK,
22598 TaskgroupDescriptor&: ParentBOKTD);
22599 DSAStackTy::DSAVarData ParentReductionOpDSA =
22600 Stack->getTopMostTaskgroupReductionData(
22601 D, SR&: ParentSR, ReductionRef&: ParentReductionOp, TaskgroupDescriptor&: ParentReductionOpTD);
22602 bool IsParentBOK = ParentBOKDSA.DKind != OMPD_unknown;
22603 bool IsParentReductionOp = ParentReductionOpDSA.DKind != OMPD_unknown;
22604 if ((DeclareReductionRef.isUnset() && IsParentReductionOp) ||
22605 (DeclareReductionRef.isUsable() && IsParentBOK) ||
22606 (IsParentBOK && BOK != ParentBOK) || IsParentReductionOp) {
22607 bool EmitError = true;
22608 if (IsParentReductionOp && DeclareReductionRef.isUsable()) {
22609 llvm::FoldingSetNodeID RedId, ParentRedId;
22610 ParentReductionOp->Profile(ID&: ParentRedId, Context, /*Canonical=*/true);
22611 DeclareReductionRef.get()->Profile(ID&: RedId, Context,
22612 /*Canonical=*/true);
22613 EmitError = RedId != ParentRedId;
22614 }
22615 if (EmitError) {
22616 S.Diag(Loc: ReductionId.getBeginLoc(),
22617 DiagID: diag::err_omp_reduction_identifier_mismatch)
22618 << ReductionIdRange << RefExpr->getSourceRange();
22619 S.Diag(Loc: ParentSR.getBegin(),
22620 DiagID: diag::note_omp_previous_reduction_identifier)
22621 << ParentSR
22622 << (IsParentBOK ? ParentBOKDSA.RefExpr
22623 : ParentReductionOpDSA.RefExpr)
22624 ->getSourceRange();
22625 continue;
22626 }
22627 }
22628 TaskgroupDescriptor = IsParentBOK ? ParentBOKTD : ParentReductionOpTD;
22629 }
22630
22631 DeclRefExpr *Ref = nullptr;
22632 Expr *VarsExpr = RefExpr->IgnoreParens();
22633 bool IsBindingDecl = isa<BindingDecl>(Val: D);
22634 if (!VD && !IsBindingDecl && !S.CurContext->isDependentContext()) {
22635 if (ASE || OASE) {
22636 TransformExprToCaptures RebuildToCapture(S, D);
22637 VarsExpr =
22638 RebuildToCapture.TransformExpr(E: RefExpr->IgnoreParens()).get();
22639 Ref = RebuildToCapture.getCapturedExpr();
22640 } else {
22641 VarsExpr = Ref = buildCapture(S, D, CaptureExpr: SimpleRefExpr, /*WithInit=*/false);
22642 }
22643 if (!S.OpenMP().isOpenMPCapturedDecl(D)) {
22644 RD.ExprCaptures.emplace_back(Args: Ref->getDecl());
22645 if (Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()) {
22646 ExprResult RefRes = S.DefaultLvalueConversion(E: Ref);
22647 if (!RefRes.isUsable())
22648 continue;
22649 ExprResult PostUpdateRes =
22650 S.BuildBinOp(S: Stack->getCurScope(), OpLoc: ELoc, Opc: BO_Assign, LHSExpr: SimpleRefExpr,
22651 RHSExpr: RefRes.get());
22652 if (!PostUpdateRes.isUsable())
22653 continue;
22654 if (isOpenMPTaskingDirective(Kind: Stack->getCurrentDirective()) ||
22655 Stack->getCurrentDirective() == OMPD_taskgroup) {
22656 S.Diag(Loc: RefExpr->getExprLoc(),
22657 DiagID: diag::err_omp_reduction_non_addressable_expression)
22658 << RefExpr->getSourceRange();
22659 continue;
22660 }
22661 RD.ExprPostUpdates.emplace_back(
22662 Args: S.IgnoredValueConversions(E: PostUpdateRes.get()).get());
22663 }
22664 }
22665 }
22666 // All reduction items are still marked as reduction (to do not increase
22667 // code base size).
22668 unsigned Modifier = RD.RedModifier;
22669 // Consider task_reductions as reductions with task modifier. Required for
22670 // correct analysis of in_reduction clauses.
22671 if (CurrDir == OMPD_taskgroup && ClauseKind == OMPC_task_reduction)
22672 Modifier = OMPC_REDUCTION_task;
22673 Stack->addDSA(D, E: RefExpr->IgnoreParens(), A: OMPC_reduction, PrivateCopy: Ref, Modifier,
22674 AppliedToPointee: ASE || OASE);
22675 if (Modifier == OMPC_REDUCTION_task &&
22676 (CurrDir == OMPD_taskgroup ||
22677 ((isOpenMPParallelDirective(DKind: CurrDir) ||
22678 isOpenMPWorksharingDirective(DKind: CurrDir)) &&
22679 !isOpenMPSimdDirective(DKind: CurrDir)))) {
22680 if (DeclareReductionRef.isUsable())
22681 Stack->addTaskgroupReductionData(D, SR: ReductionIdRange,
22682 ReductionRef: DeclareReductionRef.get());
22683 else
22684 Stack->addTaskgroupReductionData(D, SR: ReductionIdRange, BOK);
22685 }
22686 RD.push(Item: VarsExpr, Private: PrivateDRE, LHS: LHSDRE, RHS: RHSDRE, ReductionOp: ReductionOp.get(),
22687 TaskgroupDescriptor, CopyOp: CopyOpRes.get(), CopyArrayTemp: TempArrayRes.get(),
22688 CopyArrayElem: TempArrayElem.get(), IsPrivate);
22689 }
22690 return RD.Vars.empty();
22691}
22692
22693OMPClause *SemaOpenMP::ActOnOpenMPReductionClause(
22694 ArrayRef<Expr *> VarList,
22695 OpenMPVarListDataTy::OpenMPReductionClauseModifiers Modifiers,
22696 SourceLocation StartLoc, SourceLocation LParenLoc,
22697 SourceLocation ModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc,
22698 CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
22699 ArrayRef<Expr *> UnresolvedReductions) {
22700 OpenMPReductionClauseModifier Modifier =
22701 static_cast<OpenMPReductionClauseModifier>(Modifiers.ExtraModifier);
22702 OpenMPOriginalSharingModifier OriginalSharingModifier =
22703 static_cast<OpenMPOriginalSharingModifier>(
22704 Modifiers.OriginalSharingModifier);
22705 if (ModifierLoc.isValid() && Modifier == OMPC_REDUCTION_unknown) {
22706 Diag(Loc: LParenLoc, DiagID: diag::err_omp_unexpected_clause_value)
22707 << getListOfPossibleValues(K: OMPC_reduction, /*First=*/0,
22708 /*Last=*/OMPC_REDUCTION_unknown)
22709 << getOpenMPClauseNameForDiag(C: OMPC_reduction);
22710 return nullptr;
22711 }
22712 // OpenMP 5.0, 2.19.5.4 reduction Clause, Restrictions
22713 // A reduction clause with the inscan reduction-modifier may only appear on a
22714 // worksharing-loop construct, a worksharing-loop SIMD construct, a simd
22715 // construct, a parallel worksharing-loop construct or a parallel
22716 // worksharing-loop SIMD construct.
22717 if (Modifier == OMPC_REDUCTION_inscan &&
22718 (DSAStack->getCurrentDirective() != OMPD_for &&
22719 DSAStack->getCurrentDirective() != OMPD_for_simd &&
22720 DSAStack->getCurrentDirective() != OMPD_simd &&
22721 DSAStack->getCurrentDirective() != OMPD_parallel_for &&
22722 DSAStack->getCurrentDirective() != OMPD_parallel_for_simd)) {
22723 Diag(Loc: ModifierLoc, DiagID: diag::err_omp_wrong_inscan_reduction);
22724 return nullptr;
22725 }
22726 ReductionData RD(VarList.size(), Modifier, OriginalSharingModifier);
22727 if (actOnOMPReductionKindClause(S&: SemaRef, DSAStack, ClauseKind: OMPC_reduction, VarList,
22728 StartLoc, LParenLoc, ColonLoc, EndLoc,
22729 ReductionIdScopeSpec, ReductionId,
22730 UnresolvedReductions, RD))
22731 return nullptr;
22732
22733 return OMPReductionClause::Create(
22734 C: getASTContext(), StartLoc, LParenLoc, ModifierLoc, ColonLoc, EndLoc,
22735 Modifier, VL: RD.Vars,
22736 QualifierLoc: ReductionIdScopeSpec.getWithLocInContext(Context&: getASTContext()), NameInfo: ReductionId,
22737 Privates: RD.Privates, LHSExprs: RD.LHSs, RHSExprs: RD.RHSs, ReductionOps: RD.ReductionOps, CopyOps: RD.InscanCopyOps,
22738 CopyArrayTemps: RD.InscanCopyArrayTemps, CopyArrayElems: RD.InscanCopyArrayElems,
22739 PreInit: buildPreInits(Context&: getASTContext(), PreInits: RD.ExprCaptures),
22740 PostUpdate: buildPostUpdate(S&: SemaRef, PostUpdates: RD.ExprPostUpdates), IsPrivateVarReduction: RD.IsPrivateVarReduction,
22741 OriginalSharingModifier);
22742}
22743
22744OMPClause *SemaOpenMP::ActOnOpenMPTaskReductionClause(
22745 ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
22746 SourceLocation ColonLoc, SourceLocation EndLoc,
22747 CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
22748 ArrayRef<Expr *> UnresolvedReductions) {
22749 ReductionData RD(VarList.size());
22750 if (actOnOMPReductionKindClause(S&: SemaRef, DSAStack, ClauseKind: OMPC_task_reduction,
22751 VarList, StartLoc, LParenLoc, ColonLoc,
22752 EndLoc, ReductionIdScopeSpec, ReductionId,
22753 UnresolvedReductions, RD))
22754 return nullptr;
22755
22756 return OMPTaskReductionClause::Create(
22757 C: getASTContext(), StartLoc, LParenLoc, ColonLoc, EndLoc, VL: RD.Vars,
22758 QualifierLoc: ReductionIdScopeSpec.getWithLocInContext(Context&: getASTContext()), NameInfo: ReductionId,
22759 Privates: RD.Privates, LHSExprs: RD.LHSs, RHSExprs: RD.RHSs, ReductionOps: RD.ReductionOps,
22760 PreInit: buildPreInits(Context&: getASTContext(), PreInits: RD.ExprCaptures),
22761 PostUpdate: buildPostUpdate(S&: SemaRef, PostUpdates: RD.ExprPostUpdates));
22762}
22763
22764OMPClause *SemaOpenMP::ActOnOpenMPInReductionClause(
22765 ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
22766 SourceLocation ColonLoc, SourceLocation EndLoc,
22767 CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
22768 ArrayRef<Expr *> UnresolvedReductions) {
22769 ReductionData RD(VarList.size());
22770 if (actOnOMPReductionKindClause(S&: SemaRef, DSAStack, ClauseKind: OMPC_in_reduction, VarList,
22771 StartLoc, LParenLoc, ColonLoc, EndLoc,
22772 ReductionIdScopeSpec, ReductionId,
22773 UnresolvedReductions, RD))
22774 return nullptr;
22775
22776 return OMPInReductionClause::Create(
22777 C: getASTContext(), StartLoc, LParenLoc, ColonLoc, EndLoc, VL: RD.Vars,
22778 QualifierLoc: ReductionIdScopeSpec.getWithLocInContext(Context&: getASTContext()), NameInfo: ReductionId,
22779 Privates: RD.Privates, LHSExprs: RD.LHSs, RHSExprs: RD.RHSs, ReductionOps: RD.ReductionOps, TaskgroupDescriptors: RD.TaskgroupDescriptors,
22780 PreInit: buildPreInits(Context&: getASTContext(), PreInits: RD.ExprCaptures),
22781 PostUpdate: buildPostUpdate(S&: SemaRef, PostUpdates: RD.ExprPostUpdates));
22782}
22783
22784bool SemaOpenMP::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind,
22785 SourceLocation LinLoc) {
22786 if ((!getLangOpts().CPlusPlus && LinKind != OMPC_LINEAR_val) ||
22787 LinKind == OMPC_LINEAR_unknown || LinKind == OMPC_LINEAR_step) {
22788 Diag(Loc: LinLoc, DiagID: diag::err_omp_wrong_linear_modifier)
22789 << getLangOpts().CPlusPlus;
22790 return true;
22791 }
22792 return false;
22793}
22794
22795bool SemaOpenMP::CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc,
22796 OpenMPLinearClauseKind LinKind,
22797 QualType Type, bool IsDeclareSimd) {
22798 const auto *VD = dyn_cast_or_null<VarDecl>(Val: D);
22799 // A variable must not have an incomplete type or a reference type.
22800 if (SemaRef.RequireCompleteType(Loc: ELoc, T: Type,
22801 DiagID: diag::err_omp_linear_incomplete_type))
22802 return true;
22803 if ((LinKind == OMPC_LINEAR_uval || LinKind == OMPC_LINEAR_ref) &&
22804 !Type->isReferenceType()) {
22805 Diag(Loc: ELoc, DiagID: diag::err_omp_wrong_linear_modifier_non_reference)
22806 << Type << getOpenMPSimpleClauseTypeName(Kind: OMPC_linear, Type: LinKind);
22807 return true;
22808 }
22809 Type = Type.getNonReferenceType();
22810
22811 // OpenMP 5.0 [2.19.3, List Item Privatization, Restrictions]
22812 // A variable that is privatized must not have a const-qualified type
22813 // unless it is of class type with a mutable member. This restriction does
22814 // not apply to the firstprivate clause, nor to the linear clause on
22815 // declarative directives (like declare simd).
22816 if (!IsDeclareSimd &&
22817 rejectConstNotMutableType(SemaRef, D, Type, CKind: OMPC_linear, ELoc))
22818 return true;
22819
22820 // A list item must be of integral or pointer type.
22821 Type = Type.getUnqualifiedType().getCanonicalType();
22822 const auto *Ty = Type.getTypePtrOrNull();
22823 if (!Ty || (LinKind != OMPC_LINEAR_ref && !Ty->isDependentType() &&
22824 !Ty->isIntegralType(Ctx: getASTContext()) && !Ty->isPointerType())) {
22825 Diag(Loc: ELoc, DiagID: diag::err_omp_linear_expected_int_or_ptr) << Type;
22826 if (D) {
22827 bool IsDecl = !VD || VD->isThisDeclarationADefinition(getASTContext()) ==
22828 VarDecl::DeclarationOnly;
22829 Diag(Loc: D->getLocation(),
22830 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
22831 << D;
22832 }
22833 return true;
22834 }
22835 return false;
22836}
22837
22838OMPClause *SemaOpenMP::ActOnOpenMPLinearClause(
22839 ArrayRef<Expr *> VarList, Expr *Step, SourceLocation StartLoc,
22840 SourceLocation LParenLoc, OpenMPLinearClauseKind LinKind,
22841 SourceLocation LinLoc, SourceLocation ColonLoc,
22842 SourceLocation StepModifierLoc, SourceLocation EndLoc) {
22843 SmallVector<Expr *, 8> Vars;
22844 SmallVector<Expr *, 8> Privates;
22845 SmallVector<Expr *, 8> Inits;
22846 SmallVector<Decl *, 4> ExprCaptures;
22847 SmallVector<Expr *, 4> ExprPostUpdates;
22848 // OpenMP 5.2 [Section 5.4.6, linear clause]
22849 // step-simple-modifier is exclusive, can't be used with 'val', 'uval', or
22850 // 'ref'
22851 if (LinLoc.isValid() && StepModifierLoc.isInvalid() && Step &&
22852 getLangOpts().OpenMP >= 52)
22853 Diag(Loc: Step->getBeginLoc(), DiagID: diag::err_omp_step_simple_modifier_exclusive);
22854 if (CheckOpenMPLinearModifier(LinKind, LinLoc))
22855 LinKind = OMPC_LINEAR_val;
22856 for (Expr *RefExpr : VarList) {
22857 assert(RefExpr && "NULL expr in OpenMP linear clause.");
22858 SourceLocation ELoc;
22859 SourceRange ERange;
22860 Expr *SimpleRefExpr = RefExpr;
22861 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange);
22862 if (Res.second) {
22863 // It will be analyzed later.
22864 Vars.push_back(Elt: RefExpr);
22865 Privates.push_back(Elt: nullptr);
22866 Inits.push_back(Elt: nullptr);
22867 }
22868 ValueDecl *D = Res.first;
22869 if (!D)
22870 continue;
22871
22872 // Linear on bindings only works for simple simd, not parallel constructs.
22873 if (isa<BindingDecl>(Val: D)) {
22874 OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
22875 if (isOpenMPParallelDirective(DKind)) {
22876 Diag(Loc: ELoc, DiagID: diag::err_omp_unsupported_on_binding) << 2;
22877 continue;
22878 }
22879 }
22880
22881 QualType Type = D->getType();
22882 auto *VD = dyn_cast<VarDecl>(Val: D);
22883
22884 // OpenMP [2.14.3.7, linear clause]
22885 // A list-item cannot appear in more than one linear clause.
22886 // A list-item that appears in a linear clause cannot appear in any
22887 // other data-sharing attribute clause.
22888 DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false);
22889 if (DVar.RefExpr) {
22890 Diag(Loc: ELoc, DiagID: diag::err_omp_wrong_dsa)
22891 << getOpenMPClauseNameForDiag(C: DVar.CKind)
22892 << getOpenMPClauseNameForDiag(C: OMPC_linear);
22893 reportOriginalDsa(SemaRef, DSAStack, D, DVar);
22894 continue;
22895 }
22896
22897 if (CheckOpenMPLinearDecl(D, ELoc, LinKind, Type))
22898 continue;
22899 Type = Type.getNonReferenceType().getUnqualifiedType().getCanonicalType();
22900
22901 // Build private copy of original var.
22902 VarDecl *Private =
22903 buildVarDecl(SemaRef, Loc: ELoc, Type, Name: D->getName(),
22904 Attrs: D->hasAttrs() ? &D->getAttrs() : nullptr,
22905 OrigRef: VD ? cast<DeclRefExpr>(Val: SimpleRefExpr) : nullptr);
22906 DeclRefExpr *PrivateRef = buildDeclRefExpr(S&: SemaRef, D: Private, Ty: Type, Loc: ELoc);
22907 // Build var to save initial value.
22908 VarDecl *Init = buildVarDecl(SemaRef, Loc: ELoc, Type, Name: ".linear.start");
22909 Expr *InitExpr;
22910 DeclRefExpr *Ref = nullptr;
22911 bool IsBindingDecl = isa<BindingDecl>(Val: D);
22912 if (!VD && !IsBindingDecl && !SemaRef.CurContext->isDependentContext()) {
22913 Ref = buildCapture(S&: SemaRef, D, CaptureExpr: SimpleRefExpr, /*WithInit=*/false);
22914 if (!isOpenMPCapturedDecl(D)) {
22915 ExprCaptures.push_back(Elt: Ref->getDecl());
22916 if (Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()) {
22917 ExprResult RefRes = SemaRef.DefaultLvalueConversion(E: Ref);
22918 if (!RefRes.isUsable())
22919 continue;
22920 ExprResult PostUpdateRes =
22921 SemaRef.BuildBinOp(DSAStack->getCurScope(), OpLoc: ELoc, Opc: BO_Assign,
22922 LHSExpr: SimpleRefExpr, RHSExpr: RefRes.get());
22923 if (!PostUpdateRes.isUsable())
22924 continue;
22925 ExprPostUpdates.push_back(
22926 Elt: SemaRef.IgnoredValueConversions(E: PostUpdateRes.get()).get());
22927 }
22928 }
22929 }
22930 if (LinKind == OMPC_LINEAR_uval)
22931 InitExpr = VD ? VD->getInit() : SimpleRefExpr;
22932 else
22933 InitExpr = (VD || IsBindingDecl) ? SimpleRefExpr : Ref;
22934 SemaRef.AddInitializerToDecl(
22935 dcl: Init, init: SemaRef.DefaultLvalueConversion(E: InitExpr).get(),
22936 /*DirectInit=*/false);
22937 DeclRefExpr *InitRef = buildDeclRefExpr(S&: SemaRef, D: Init, Ty: Type, Loc: ELoc);
22938
22939 DSAStack->addDSA(D, E: RefExpr->IgnoreParens(), A: OMPC_linear, PrivateCopy: Ref);
22940 Vars.push_back(
22941 Elt: (VD || IsBindingDecl || SemaRef.CurContext->isDependentContext())
22942 ? RefExpr->IgnoreParens()
22943 : Ref);
22944 Privates.push_back(Elt: PrivateRef);
22945 Inits.push_back(Elt: InitRef);
22946 }
22947
22948 if (Vars.empty())
22949 return nullptr;
22950
22951 Expr *StepExpr = Step;
22952 Expr *CalcStepExpr = nullptr;
22953 if (Step && !Step->isValueDependent() && !Step->isTypeDependent() &&
22954 !Step->isInstantiationDependent() &&
22955 !Step->containsUnexpandedParameterPack()) {
22956 SourceLocation StepLoc = Step->getBeginLoc();
22957 ExprResult Val = PerformOpenMPImplicitIntegerConversion(Loc: StepLoc, Op: Step);
22958 if (Val.isInvalid())
22959 return nullptr;
22960 StepExpr = Val.get();
22961
22962 // Build var to save the step value.
22963 VarDecl *SaveVar =
22964 buildVarDecl(SemaRef, Loc: StepLoc, Type: StepExpr->getType(), Name: ".linear.step");
22965 ExprResult SaveRef =
22966 buildDeclRefExpr(S&: SemaRef, D: SaveVar, Ty: StepExpr->getType(), Loc: StepLoc);
22967 ExprResult CalcStep = SemaRef.BuildBinOp(
22968 S: SemaRef.getCurScope(), OpLoc: StepLoc, Opc: BO_Assign, LHSExpr: SaveRef.get(), RHSExpr: StepExpr);
22969 CalcStep =
22970 SemaRef.ActOnFinishFullExpr(Expr: CalcStep.get(), /*DiscardedValue=*/false);
22971
22972 // Warn about zero linear step (it would be probably better specified as
22973 // making corresponding variables 'const').
22974 if (std::optional<llvm::APSInt> Result =
22975 StepExpr->getIntegerConstantExpr(Ctx: getASTContext())) {
22976 if (!Result->isNegative() && !Result->isStrictlyPositive())
22977 Diag(Loc: StepLoc, DiagID: diag::warn_omp_linear_step_zero)
22978 << Vars[0] << (Vars.size() > 1);
22979 } else if (CalcStep.isUsable()) {
22980 // Calculate the step beforehand instead of doing this on each iteration.
22981 // (This is not used if the number of iterations may be kfold-ed).
22982 CalcStepExpr = CalcStep.get();
22983 }
22984 }
22985
22986 return OMPLinearClause::Create(C: getASTContext(), StartLoc, LParenLoc, Modifier: LinKind,
22987 ModifierLoc: LinLoc, ColonLoc, StepModifierLoc, EndLoc,
22988 VL: Vars, PL: Privates, IL: Inits, Step: StepExpr, CalcStep: CalcStepExpr,
22989 PreInit: buildPreInits(Context&: getASTContext(), PreInits: ExprCaptures),
22990 PostUpdate: buildPostUpdate(S&: SemaRef, PostUpdates: ExprPostUpdates));
22991}
22992
22993static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
22994 Expr *NumIterations, Sema &SemaRef,
22995 Scope *S, DSAStackTy *Stack) {
22996 // Walk the vars and build update/final expressions for the CodeGen.
22997 SmallVector<Expr *, 8> Updates;
22998 SmallVector<Expr *, 8> Finals;
22999 SmallVector<Expr *, 8> UsedExprs;
23000 Expr *Step = Clause.getStep();
23001 Expr *CalcStep = Clause.getCalcStep();
23002 // OpenMP [2.14.3.7, linear clause]
23003 // If linear-step is not specified it is assumed to be 1.
23004 if (!Step)
23005 Step = SemaRef.ActOnIntegerConstant(Loc: SourceLocation(), Val: 1).get();
23006 else if (CalcStep)
23007 Step = cast<BinaryOperator>(Val: CalcStep)->getLHS();
23008 bool HasErrors = false;
23009 auto CurInit = Clause.inits().begin();
23010 auto CurPrivate = Clause.privates().begin();
23011 OpenMPLinearClauseKind LinKind = Clause.getModifier();
23012 for (Expr *RefExpr : Clause.varlist()) {
23013 SourceLocation ELoc;
23014 SourceRange ERange;
23015 Expr *SimpleRefExpr = RefExpr;
23016 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange);
23017 ValueDecl *D = Res.first;
23018 if (Res.second || !D) {
23019 Updates.push_back(Elt: nullptr);
23020 Finals.push_back(Elt: nullptr);
23021 HasErrors = true;
23022 continue;
23023 }
23024 auto &&Info = Stack->isLoopControlVariable(D);
23025 // OpenMP [2.15.11, distribute simd Construct]
23026 // A list item may not appear in a linear clause, unless it is the loop
23027 // iteration variable.
23028 if (isOpenMPDistributeDirective(DKind: Stack->getCurrentDirective()) &&
23029 isOpenMPSimdDirective(DKind: Stack->getCurrentDirective()) && !Info.first) {
23030 SemaRef.Diag(Loc: ELoc,
23031 DiagID: diag::err_omp_linear_distribute_var_non_loop_iteration);
23032 Updates.push_back(Elt: nullptr);
23033 Finals.push_back(Elt: nullptr);
23034 HasErrors = true;
23035 continue;
23036 }
23037 Expr *InitExpr = *CurInit;
23038
23039 // Build privatized reference to the current linear var.
23040 auto *DE = cast<DeclRefExpr>(Val: SimpleRefExpr);
23041 Expr *CapturedRef;
23042 if (isa<BindingDecl>(Val: DE->getDecl())) {
23043 CapturedRef = SimpleRefExpr;
23044 } else if (LinKind == OMPC_LINEAR_uval) {
23045 CapturedRef = cast<VarDecl>(Val: DE->getDecl())->getInit();
23046 } else {
23047 CapturedRef =
23048 buildDeclRefExpr(S&: SemaRef, D: cast<VarDecl>(Val: DE->getDecl()),
23049 Ty: DE->getType().getUnqualifiedType(), Loc: DE->getExprLoc(),
23050 /*RefersToCapture=*/true);
23051 }
23052
23053 // Build update: Var = InitExpr + IV * Step
23054 ExprResult Update;
23055 if (!Info.first)
23056 Update = buildCounterUpdate(
23057 SemaRef, S, Loc: RefExpr->getExprLoc(), VarRef: *CurPrivate, Start: InitExpr, Iter: IV, Step,
23058 /*Subtract=*/false, /*IsNonRectangularLB=*/false);
23059 else
23060 Update = *CurPrivate;
23061 Update = SemaRef.ActOnFinishFullExpr(Expr: Update.get(), CC: DE->getBeginLoc(),
23062 /*DiscardedValue=*/false);
23063
23064 // Build final: Var = PrivCopy;
23065 ExprResult Final;
23066 if (!Info.first)
23067 Final = SemaRef.BuildBinOp(
23068 S, OpLoc: RefExpr->getExprLoc(), Opc: BO_Assign, LHSExpr: CapturedRef,
23069 RHSExpr: SemaRef.DefaultLvalueConversion(E: *CurPrivate).get());
23070 else
23071 Final = *CurPrivate;
23072 Final = SemaRef.ActOnFinishFullExpr(Expr: Final.get(), CC: DE->getBeginLoc(),
23073 /*DiscardedValue=*/false);
23074
23075 if (!Update.isUsable() || !Final.isUsable()) {
23076 Updates.push_back(Elt: nullptr);
23077 Finals.push_back(Elt: nullptr);
23078 UsedExprs.push_back(Elt: nullptr);
23079 HasErrors = true;
23080 } else {
23081 Updates.push_back(Elt: Update.get());
23082 Finals.push_back(Elt: Final.get());
23083 if (!Info.first)
23084 UsedExprs.push_back(Elt: SimpleRefExpr);
23085 }
23086 ++CurInit;
23087 ++CurPrivate;
23088 }
23089 if (Expr *S = Clause.getStep())
23090 UsedExprs.push_back(Elt: S);
23091 // Fill the remaining part with the nullptr.
23092 UsedExprs.append(NumInputs: Clause.varlist_size() + 1 - UsedExprs.size(), Elt: nullptr);
23093 Clause.setUpdates(Updates);
23094 Clause.setFinals(Finals);
23095 Clause.setUsedExprs(UsedExprs);
23096 return HasErrors;
23097}
23098
23099OMPClause *SemaOpenMP::ActOnOpenMPAlignedClause(
23100 ArrayRef<Expr *> VarList, Expr *Alignment, SourceLocation StartLoc,
23101 SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc) {
23102 SmallVector<Expr *, 8> Vars;
23103 for (Expr *RefExpr : VarList) {
23104 assert(RefExpr && "NULL expr in OpenMP aligned clause.");
23105 SourceLocation ELoc;
23106 SourceRange ERange;
23107 Expr *SimpleRefExpr = RefExpr;
23108 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange);
23109 if (Res.second) {
23110 // It will be analyzed later.
23111 Vars.push_back(Elt: RefExpr);
23112 }
23113 ValueDecl *D = Res.first;
23114 if (!D)
23115 continue;
23116
23117 QualType QType = D->getType();
23118 auto *VD = dyn_cast<VarDecl>(Val: D);
23119
23120 // OpenMP [2.8.1, simd construct, Restrictions]
23121 // The type of list items appearing in the aligned clause must be
23122 // array, pointer, reference to array, or reference to pointer.
23123 QType = QType.getNonReferenceType().getUnqualifiedType().getCanonicalType();
23124 const Type *Ty = QType.getTypePtrOrNull();
23125 if (!Ty || (!Ty->isArrayType() && !Ty->isPointerType())) {
23126 Diag(Loc: ELoc, DiagID: diag::err_omp_aligned_expected_array_or_ptr)
23127 << QType << getLangOpts().CPlusPlus << ERange;
23128 bool IsDecl = !VD || VD->isThisDeclarationADefinition(getASTContext()) ==
23129 VarDecl::DeclarationOnly;
23130 Diag(Loc: D->getLocation(),
23131 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
23132 << D;
23133 continue;
23134 }
23135
23136 // OpenMP [2.8.1, simd construct, Restrictions]
23137 // A list-item cannot appear in more than one aligned clause.
23138 if (const Expr *PrevRef = DSAStack->addUniqueAligned(D, NewDE: SimpleRefExpr)) {
23139 Diag(Loc: ELoc, DiagID: diag::err_omp_used_in_clause_twice)
23140 << 0 << getOpenMPClauseNameForDiag(C: OMPC_aligned) << ERange;
23141 Diag(Loc: PrevRef->getExprLoc(), DiagID: diag::note_omp_explicit_dsa)
23142 << getOpenMPClauseNameForDiag(C: OMPC_aligned);
23143 continue;
23144 }
23145
23146 DeclRefExpr *Ref = nullptr;
23147 if (!VD && isOpenMPCapturedDecl(D))
23148 Ref = buildCapture(S&: SemaRef, D, CaptureExpr: SimpleRefExpr, /*WithInit=*/true);
23149 Vars.push_back(Elt: SemaRef
23150 .DefaultFunctionArrayConversion(
23151 E: (VD || !Ref) ? RefExpr->IgnoreParens() : Ref)
23152 .get());
23153 }
23154
23155 // OpenMP [2.8.1, simd construct, Description]
23156 // The parameter of the aligned clause, alignment, must be a constant
23157 // positive integer expression.
23158 // If no optional parameter is specified, implementation-defined default
23159 // alignments for SIMD instructions on the target platforms are assumed.
23160 if (Alignment != nullptr) {
23161 ExprResult AlignResult =
23162 VerifyPositiveIntegerConstantInClause(E: Alignment, CKind: OMPC_aligned);
23163 if (AlignResult.isInvalid())
23164 return nullptr;
23165 Alignment = AlignResult.get();
23166 }
23167 if (Vars.empty())
23168 return nullptr;
23169
23170 return OMPAlignedClause::Create(C: getASTContext(), StartLoc, LParenLoc,
23171 ColonLoc, EndLoc, VL: Vars, A: Alignment);
23172}
23173
23174OMPClause *SemaOpenMP::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList,
23175 SourceLocation StartLoc,
23176 SourceLocation LParenLoc,
23177 SourceLocation EndLoc) {
23178 SmallVector<Expr *, 8> Vars;
23179 SmallVector<Expr *, 8> SrcExprs;
23180 SmallVector<Expr *, 8> DstExprs;
23181 SmallVector<Expr *, 8> AssignmentOps;
23182 for (Expr *RefExpr : VarList) {
23183 assert(RefExpr && "NULL expr in OpenMP copyin clause.");
23184 if (isa<DependentScopeDeclRefExpr>(Val: RefExpr)) {
23185 // It will be analyzed later.
23186 Vars.push_back(Elt: RefExpr);
23187 SrcExprs.push_back(Elt: nullptr);
23188 DstExprs.push_back(Elt: nullptr);
23189 AssignmentOps.push_back(Elt: nullptr);
23190 continue;
23191 }
23192
23193 SourceLocation ELoc = RefExpr->getExprLoc();
23194 // OpenMP [2.1, C/C++]
23195 // A list item is a variable name.
23196 // OpenMP [2.14.4.1, Restrictions, p.1]
23197 // A list item that appears in a copyin clause must be threadprivate.
23198 auto *DE = dyn_cast<DeclRefExpr>(Val: RefExpr);
23199 if (!DE || !isa<VarDecl>(Val: DE->getDecl())) {
23200 Diag(Loc: ELoc, DiagID: diag::err_omp_expected_var_name_member_expr)
23201 << 0 << RefExpr->getSourceRange();
23202 continue;
23203 }
23204
23205 Decl *D = DE->getDecl();
23206 auto *VD = cast<VarDecl>(Val: D);
23207
23208 QualType Type = VD->getType();
23209 if (Type->isDependentType() || Type->isInstantiationDependentType()) {
23210 // It will be analyzed later.
23211 Vars.push_back(Elt: DE);
23212 SrcExprs.push_back(Elt: nullptr);
23213 DstExprs.push_back(Elt: nullptr);
23214 AssignmentOps.push_back(Elt: nullptr);
23215 continue;
23216 }
23217
23218 // OpenMP [2.14.4.1, Restrictions, C/C++, p.1]
23219 // A list item that appears in a copyin clause must be threadprivate.
23220 if (!DSAStack->isThreadPrivate(D: VD)) {
23221 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
23222 Diag(Loc: ELoc, DiagID: diag::err_omp_required_access)
23223 << getOpenMPClauseNameForDiag(C: OMPC_copyin)
23224 << getOpenMPDirectiveName(D: OMPD_threadprivate, V: OMPVersion);
23225 continue;
23226 }
23227
23228 // OpenMP [2.14.4.1, Restrictions, C/C++, p.2]
23229 // A variable of class type (or array thereof) that appears in a
23230 // copyin clause requires an accessible, unambiguous copy assignment
23231 // operator for the class type.
23232 QualType ElemType =
23233 getASTContext().getBaseElementType(QT: Type).getNonReferenceType();
23234 VarDecl *SrcVD =
23235 buildVarDecl(SemaRef, Loc: DE->getBeginLoc(), Type: ElemType.getUnqualifiedType(),
23236 Name: ".copyin.src", Attrs: VD->hasAttrs() ? &VD->getAttrs() : nullptr);
23237 DeclRefExpr *PseudoSrcExpr = buildDeclRefExpr(
23238 S&: SemaRef, D: SrcVD, Ty: ElemType.getUnqualifiedType(), Loc: DE->getExprLoc());
23239 VarDecl *DstVD =
23240 buildVarDecl(SemaRef, Loc: DE->getBeginLoc(), Type: ElemType, Name: ".copyin.dst",
23241 Attrs: VD->hasAttrs() ? &VD->getAttrs() : nullptr);
23242 DeclRefExpr *PseudoDstExpr =
23243 buildDeclRefExpr(S&: SemaRef, D: DstVD, Ty: ElemType, Loc: DE->getExprLoc());
23244 // For arrays generate assignment operation for single element and replace
23245 // it by the original array element in CodeGen.
23246 ExprResult AssignmentOp =
23247 SemaRef.BuildBinOp(/*S=*/nullptr, OpLoc: DE->getExprLoc(), Opc: BO_Assign,
23248 LHSExpr: PseudoDstExpr, RHSExpr: PseudoSrcExpr);
23249 if (AssignmentOp.isInvalid())
23250 continue;
23251 AssignmentOp =
23252 SemaRef.ActOnFinishFullExpr(Expr: AssignmentOp.get(), CC: DE->getExprLoc(),
23253 /*DiscardedValue=*/false);
23254 if (AssignmentOp.isInvalid())
23255 continue;
23256
23257 DSAStack->addDSA(D: VD, E: DE, A: OMPC_copyin);
23258 Vars.push_back(Elt: DE);
23259 SrcExprs.push_back(Elt: PseudoSrcExpr);
23260 DstExprs.push_back(Elt: PseudoDstExpr);
23261 AssignmentOps.push_back(Elt: AssignmentOp.get());
23262 }
23263
23264 if (Vars.empty())
23265 return nullptr;
23266
23267 return OMPCopyinClause::Create(C: getASTContext(), StartLoc, LParenLoc, EndLoc,
23268 VL: Vars, SrcExprs, DstExprs, AssignmentOps);
23269}
23270
23271OMPClause *SemaOpenMP::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList,
23272 SourceLocation StartLoc,
23273 SourceLocation LParenLoc,
23274 SourceLocation EndLoc) {
23275 SmallVector<Expr *, 8> Vars;
23276 SmallVector<Expr *, 8> SrcExprs;
23277 SmallVector<Expr *, 8> DstExprs;
23278 SmallVector<Expr *, 8> AssignmentOps;
23279 for (Expr *RefExpr : VarList) {
23280 assert(RefExpr && "NULL expr in OpenMP copyprivate clause.");
23281 SourceLocation ELoc;
23282 SourceRange ERange;
23283 Expr *SimpleRefExpr = RefExpr;
23284 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange);
23285 if (Res.second) {
23286 // It will be analyzed later.
23287 Vars.push_back(Elt: RefExpr);
23288 SrcExprs.push_back(Elt: nullptr);
23289 DstExprs.push_back(Elt: nullptr);
23290 AssignmentOps.push_back(Elt: nullptr);
23291 }
23292 ValueDecl *D = Res.first;
23293 if (!D)
23294 continue;
23295
23296 QualType Type = D->getType();
23297 auto *VD = dyn_cast<VarDecl>(Val: D);
23298
23299 // OpenMP [2.14.4.2, Restrictions, p.2]
23300 // A list item that appears in a copyprivate clause may not appear in a
23301 // private or firstprivate clause on the single construct.
23302 if (!VD || !DSAStack->isThreadPrivate(D: VD)) {
23303 DSAStackTy::DSAVarData DVar =
23304 DSAStack->getTopDSA(D, /*FromParent=*/false);
23305 if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_copyprivate &&
23306 DVar.RefExpr) {
23307 Diag(Loc: ELoc, DiagID: diag::err_omp_wrong_dsa)
23308 << getOpenMPClauseNameForDiag(C: DVar.CKind)
23309 << getOpenMPClauseNameForDiag(C: OMPC_copyprivate);
23310 reportOriginalDsa(SemaRef, DSAStack, D, DVar);
23311 continue;
23312 }
23313
23314 // OpenMP [2.11.4.2, Restrictions, p.1]
23315 // All list items that appear in a copyprivate clause must be either
23316 // threadprivate or private in the enclosing context.
23317 if (DVar.CKind == OMPC_unknown) {
23318 DVar = DSAStack->getImplicitDSA(D, FromParent: false);
23319 // A data member is private only if an enclosing construct captured it.
23320 const bool IsShared = DVar.CKind == OMPC_shared;
23321 if (IsShared ||
23322 (isa<FieldDecl>(Val: D) && !SemaRef.CurContext->isDependentContext() &&
23323 !isOpenMPCapturedDecl(D))) {
23324 Diag(Loc: ELoc, DiagID: diag::err_omp_required_access)
23325 << getOpenMPClauseNameForDiag(C: OMPC_copyprivate)
23326 << "threadprivate or private in the enclosing context";
23327 if (IsShared)
23328 reportOriginalDsa(SemaRef, DSAStack, D, DVar);
23329 continue;
23330 }
23331 }
23332 }
23333
23334 // Variably modified types are not supported.
23335 if (!Type->isAnyPointerType() && Type->isVariablyModifiedType()) {
23336 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
23337 Diag(Loc: ELoc, DiagID: diag::err_omp_variably_modified_type_not_supported)
23338 << getOpenMPClauseNameForDiag(C: OMPC_copyprivate) << Type
23339 << getOpenMPDirectiveName(DSAStack->getCurrentDirective(),
23340 V: OMPVersion);
23341 bool IsDecl = !VD || VD->isThisDeclarationADefinition(getASTContext()) ==
23342 VarDecl::DeclarationOnly;
23343 Diag(Loc: D->getLocation(),
23344 DiagID: IsDecl ? diag::note_previous_decl : diag::note_defined_here)
23345 << D;
23346 continue;
23347 }
23348
23349 // OpenMP [2.14.4.1, Restrictions, C/C++, p.2]
23350 // A variable of class type (or array thereof) that appears in a
23351 // copyin clause requires an accessible, unambiguous copy assignment
23352 // operator for the class type.
23353 Type = getASTContext()
23354 .getBaseElementType(QT: Type.getNonReferenceType())
23355 .getUnqualifiedType();
23356 VarDecl *SrcVD =
23357 buildVarDecl(SemaRef, Loc: RefExpr->getBeginLoc(), Type, Name: ".copyprivate.src",
23358 Attrs: D->hasAttrs() ? &D->getAttrs() : nullptr);
23359 DeclRefExpr *PseudoSrcExpr = buildDeclRefExpr(S&: SemaRef, D: SrcVD, Ty: Type, Loc: ELoc);
23360 VarDecl *DstVD =
23361 buildVarDecl(SemaRef, Loc: RefExpr->getBeginLoc(), Type, Name: ".copyprivate.dst",
23362 Attrs: D->hasAttrs() ? &D->getAttrs() : nullptr);
23363 DeclRefExpr *PseudoDstExpr = buildDeclRefExpr(S&: SemaRef, D: DstVD, Ty: Type, Loc: ELoc);
23364 ExprResult AssignmentOp = SemaRef.BuildBinOp(
23365 DSAStack->getCurScope(), OpLoc: ELoc, Opc: BO_Assign, LHSExpr: PseudoDstExpr, RHSExpr: PseudoSrcExpr);
23366 if (AssignmentOp.isInvalid())
23367 continue;
23368 AssignmentOp = SemaRef.ActOnFinishFullExpr(Expr: AssignmentOp.get(), CC: ELoc,
23369 /*DiscardedValue=*/false);
23370 if (AssignmentOp.isInvalid())
23371 continue;
23372
23373 // No need to mark vars as copyprivate, they are already threadprivate or
23374 // implicitly private.
23375 const bool IsBindingDecl = isa<BindingDecl>(Val: D);
23376 assert(VD || IsBindingDecl || SemaRef.CurContext->isDependentContext() ||
23377 isOpenMPCapturedDecl(D));
23378 Vars.push_back(
23379 Elt: (VD || IsBindingDecl || SemaRef.CurContext->isDependentContext())
23380 ? RefExpr->IgnoreParens()
23381 : buildCapture(S&: SemaRef, D, CaptureExpr: SimpleRefExpr, /*WithInit=*/false));
23382 SrcExprs.push_back(Elt: PseudoSrcExpr);
23383 DstExprs.push_back(Elt: PseudoDstExpr);
23384 AssignmentOps.push_back(Elt: AssignmentOp.get());
23385 }
23386
23387 if (Vars.empty())
23388 return nullptr;
23389
23390 return OMPCopyprivateClause::Create(C: getASTContext(), StartLoc, LParenLoc,
23391 EndLoc, VL: Vars, SrcExprs, DstExprs,
23392 AssignmentOps);
23393}
23394
23395OMPClause *SemaOpenMP::ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList,
23396 SourceLocation StartLoc,
23397 SourceLocation LParenLoc,
23398 SourceLocation EndLoc) {
23399 if (VarList.empty())
23400 return nullptr;
23401
23402 return OMPFlushClause::Create(C: getASTContext(), StartLoc, LParenLoc, EndLoc,
23403 VL: VarList);
23404}
23405
23406/// Tries to find omp_depend_t. type.
23407static bool findOMPDependT(Sema &S, SourceLocation Loc, DSAStackTy *Stack,
23408 bool Diagnose = true) {
23409 QualType OMPDependT = Stack->getOMPDependT();
23410 if (!OMPDependT.isNull())
23411 return true;
23412 IdentifierInfo *II = &S.PP.getIdentifierTable().get(Name: "omp_depend_t");
23413 ParsedType PT = S.getTypeName(II: *II, NameLoc: Loc, S: S.getCurScope());
23414 if (!PT.getAsOpaquePtr() || PT.get().isNull()) {
23415 if (Diagnose)
23416 S.Diag(Loc, DiagID: diag::err_omp_implied_type_not_found) << "omp_depend_t";
23417 return false;
23418 }
23419 Stack->setOMPDependT(PT.get());
23420 return true;
23421}
23422
23423OMPClause *SemaOpenMP::ActOnOpenMPDepobjClause(Expr *Depobj,
23424 SourceLocation StartLoc,
23425 SourceLocation LParenLoc,
23426 SourceLocation EndLoc) {
23427 if (!Depobj)
23428 return nullptr;
23429
23430 bool OMPDependTFound = findOMPDependT(S&: SemaRef, Loc: StartLoc, DSAStack);
23431
23432 // OpenMP 5.0, 2.17.10.1 depobj Construct
23433 // depobj is an lvalue expression of type omp_depend_t.
23434 if (!Depobj->isTypeDependent() && !Depobj->isValueDependent() &&
23435 !Depobj->isInstantiationDependent() &&
23436 !Depobj->containsUnexpandedParameterPack() &&
23437 (OMPDependTFound && !getASTContext().typesAreCompatible(
23438 DSAStack->getOMPDependT(), T2: Depobj->getType(),
23439 /*CompareUnqualified=*/true))) {
23440 Diag(Loc: Depobj->getExprLoc(), DiagID: diag::err_omp_expected_omp_depend_t_lvalue)
23441 << 0 << Depobj->getType() << Depobj->getSourceRange();
23442 }
23443
23444 if (!Depobj->isLValue()) {
23445 Diag(Loc: Depobj->getExprLoc(), DiagID: diag::err_omp_expected_omp_depend_t_lvalue)
23446 << 1 << Depobj->getSourceRange();
23447 }
23448
23449 return new (getASTContext())
23450 OMPDepobjClause(StartLoc, LParenLoc, EndLoc, Depobj);
23451}
23452
23453namespace {
23454// Utility struct that gathers the related info for doacross clause.
23455struct DoacrossDataInfoTy {
23456 // The list of expressions.
23457 SmallVector<Expr *, 8> Vars;
23458 // The OperatorOffset for doacross loop.
23459 DSAStackTy::OperatorOffsetTy OpsOffs;
23460 // The depended loop count.
23461 llvm::APSInt TotalDepCount;
23462};
23463} // namespace
23464static DoacrossDataInfoTy
23465ProcessOpenMPDoacrossClauseCommon(Sema &SemaRef, bool IsSource,
23466 ArrayRef<Expr *> VarList, DSAStackTy *Stack,
23467 SourceLocation EndLoc) {
23468
23469 SmallVector<Expr *, 8> Vars;
23470 DSAStackTy::OperatorOffsetTy OpsOffs;
23471 llvm::APSInt DepCounter(/*BitWidth=*/32);
23472 llvm::APSInt TotalDepCount(/*BitWidth=*/32);
23473
23474 if (const Expr *OrderedCountExpr =
23475 Stack->getParentOrderedRegionParam().first) {
23476 TotalDepCount = OrderedCountExpr->EvaluateKnownConstInt(Ctx: SemaRef.Context);
23477 TotalDepCount.setIsUnsigned(/*Val=*/true);
23478 }
23479
23480 for (Expr *RefExpr : VarList) {
23481 assert(RefExpr && "NULL expr in OpenMP doacross clause.");
23482 if (isa<DependentScopeDeclRefExpr>(Val: RefExpr)) {
23483 // It will be analyzed later.
23484 Vars.push_back(Elt: RefExpr);
23485 continue;
23486 }
23487
23488 SourceLocation ELoc = RefExpr->getExprLoc();
23489 Expr *SimpleExpr = RefExpr->IgnoreParenCasts();
23490 if (!IsSource) {
23491 if (Stack->getParentOrderedRegionParam().first &&
23492 DepCounter >= TotalDepCount) {
23493 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_depend_sink_unexpected_expr);
23494 continue;
23495 }
23496 ++DepCounter;
23497 // OpenMP [2.13.9, Summary]
23498 // depend(dependence-type : vec), where dependence-type is:
23499 // 'sink' and where vec is the iteration vector, which has the form:
23500 // x1 [+- d1], x2 [+- d2 ], . . . , xn [+- dn]
23501 // where n is the value specified by the ordered clause in the loop
23502 // directive, xi denotes the loop iteration variable of the i-th nested
23503 // loop associated with the loop directive, and di is a constant
23504 // non-negative integer.
23505 if (SemaRef.CurContext->isDependentContext()) {
23506 // It will be analyzed later.
23507 Vars.push_back(Elt: RefExpr);
23508 continue;
23509 }
23510 SimpleExpr = SimpleExpr->IgnoreImplicit();
23511 OverloadedOperatorKind OOK = OO_None;
23512 SourceLocation OOLoc;
23513 Expr *LHS = SimpleExpr;
23514 Expr *RHS = nullptr;
23515 if (auto *BO = dyn_cast<BinaryOperator>(Val: SimpleExpr)) {
23516 OOK = BinaryOperator::getOverloadedOperator(Opc: BO->getOpcode());
23517 OOLoc = BO->getOperatorLoc();
23518 LHS = BO->getLHS()->IgnoreParenImpCasts();
23519 RHS = BO->getRHS()->IgnoreParenImpCasts();
23520 } else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(Val: SimpleExpr)) {
23521 OOK = OCE->getOperator();
23522 OOLoc = OCE->getOperatorLoc();
23523 LHS = OCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
23524 RHS = OCE->getArg(/*Arg=*/1)->IgnoreParenImpCasts();
23525 } else if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Val: SimpleExpr)) {
23526 OOK = MCE->getMethodDecl()
23527 ->getNameInfo()
23528 .getName()
23529 .getCXXOverloadedOperator();
23530 OOLoc = MCE->getCallee()->getExprLoc();
23531 LHS = MCE->getImplicitObjectArgument()->IgnoreParenImpCasts();
23532 RHS = MCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
23533 }
23534 SourceLocation ELoc;
23535 SourceRange ERange;
23536 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: LHS, ELoc, ERange);
23537 if (Res.second) {
23538 // It will be analyzed later.
23539 Vars.push_back(Elt: RefExpr);
23540 }
23541 ValueDecl *D = Res.first;
23542 if (!D)
23543 continue;
23544
23545 if (OOK != OO_Plus && OOK != OO_Minus && (RHS || OOK != OO_None)) {
23546 SemaRef.Diag(Loc: OOLoc, DiagID: diag::err_omp_depend_sink_expected_plus_minus);
23547 continue;
23548 }
23549 if (RHS) {
23550 ExprResult RHSRes =
23551 SemaRef.OpenMP().VerifyPositiveIntegerConstantInClause(
23552 E: RHS, CKind: OMPC_depend, /*StrictlyPositive=*/false);
23553 if (RHSRes.isInvalid())
23554 continue;
23555 }
23556 if (!SemaRef.CurContext->isDependentContext() &&
23557 Stack->getParentOrderedRegionParam().first &&
23558 DepCounter != Stack->isParentLoopControlVariable(D).first) {
23559 const ValueDecl *VD =
23560 Stack->getParentLoopControlVariable(I: DepCounter.getZExtValue());
23561 if (VD)
23562 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_depend_sink_expected_loop_iteration)
23563 << 1 << VD;
23564 else
23565 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_depend_sink_expected_loop_iteration)
23566 << 0;
23567 continue;
23568 }
23569 OpsOffs.emplace_back(Args&: RHS, Args&: OOK);
23570 }
23571 Vars.push_back(Elt: RefExpr->IgnoreParenImpCasts());
23572 }
23573 if (!SemaRef.CurContext->isDependentContext() && !IsSource &&
23574 TotalDepCount > VarList.size() &&
23575 Stack->getParentOrderedRegionParam().first &&
23576 Stack->getParentLoopControlVariable(I: VarList.size() + 1)) {
23577 SemaRef.Diag(Loc: EndLoc, DiagID: diag::err_omp_depend_sink_expected_loop_iteration)
23578 << 1 << Stack->getParentLoopControlVariable(I: VarList.size() + 1);
23579 }
23580 return {.Vars: Vars, .OpsOffs: OpsOffs, .TotalDepCount: TotalDepCount};
23581}
23582
23583OMPClause *SemaOpenMP::ActOnOpenMPDependClause(
23584 const OMPDependClause::DependDataTy &Data, Expr *DepModifier,
23585 ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
23586 SourceLocation EndLoc) {
23587 OpenMPDependClauseKind DepKind = Data.DepKind;
23588 SourceLocation DepLoc = Data.DepLoc;
23589 if (DSAStack->getCurrentDirective() == OMPD_ordered_standalone &&
23590 DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink) {
23591 Diag(Loc: DepLoc, DiagID: diag::err_omp_unexpected_clause_value)
23592 << "'source' or 'sink'" << getOpenMPClauseNameForDiag(C: OMPC_depend);
23593 return nullptr;
23594 }
23595 if (DSAStack->getCurrentDirective() == OMPD_taskwait &&
23596 DepKind == OMPC_DEPEND_mutexinoutset) {
23597 Diag(Loc: DepLoc, DiagID: diag::err_omp_taskwait_depend_mutexinoutset_not_allowed);
23598 return nullptr;
23599 }
23600 if ((DSAStack->getCurrentDirective() != OMPD_ordered_standalone ||
23601 DSAStack->getCurrentDirective() == OMPD_depobj) &&
23602 (DepKind == OMPC_DEPEND_unknown || DepKind == OMPC_DEPEND_source ||
23603 DepKind == OMPC_DEPEND_sink ||
23604 ((getLangOpts().OpenMP < 50 ||
23605 DSAStack->getCurrentDirective() == OMPD_depobj) &&
23606 DepKind == OMPC_DEPEND_depobj))) {
23607 SmallVector<unsigned, 6> Except = {OMPC_DEPEND_source, OMPC_DEPEND_sink,
23608 OMPC_DEPEND_outallmemory,
23609 OMPC_DEPEND_inoutallmemory};
23610 if (getLangOpts().OpenMP < 50 ||
23611 DSAStack->getCurrentDirective() == OMPD_depobj)
23612 Except.push_back(Elt: OMPC_DEPEND_depobj);
23613 if (getLangOpts().OpenMP < 51)
23614 Except.push_back(Elt: OMPC_DEPEND_inoutset);
23615 std::string Expected = (getLangOpts().OpenMP >= 50 && !DepModifier)
23616 ? "depend modifier(iterator) or "
23617 : "";
23618 Diag(Loc: DepLoc, DiagID: diag::err_omp_unexpected_clause_value)
23619 << Expected + getListOfPossibleValues(K: OMPC_depend, /*First=*/0,
23620 /*Last=*/OMPC_DEPEND_unknown,
23621 Exclude: Except)
23622 << getOpenMPClauseNameForDiag(C: OMPC_depend);
23623 return nullptr;
23624 }
23625 if (DepModifier &&
23626 (DepKind == OMPC_DEPEND_source || DepKind == OMPC_DEPEND_sink)) {
23627 Diag(Loc: DepModifier->getExprLoc(),
23628 DiagID: diag::err_omp_depend_sink_source_with_modifier);
23629 return nullptr;
23630 }
23631 if (DepModifier &&
23632 !DepModifier->getType()->isSpecificBuiltinType(K: BuiltinType::OMPIterator))
23633 Diag(Loc: DepModifier->getExprLoc(), DiagID: diag::err_omp_depend_modifier_not_iterator);
23634
23635 SmallVector<Expr *, 8> Vars;
23636 DSAStackTy::OperatorOffsetTy OpsOffs;
23637 llvm::APSInt TotalDepCount(/*BitWidth=*/32);
23638
23639 if (DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) {
23640 DoacrossDataInfoTy VarOffset = ProcessOpenMPDoacrossClauseCommon(
23641 SemaRef, IsSource: DepKind == OMPC_DEPEND_source, VarList, DSAStack, EndLoc);
23642 Vars = VarOffset.Vars;
23643 OpsOffs = VarOffset.OpsOffs;
23644 TotalDepCount = VarOffset.TotalDepCount;
23645 } else {
23646 for (Expr *RefExpr : VarList) {
23647 assert(RefExpr && "NULL expr in OpenMP depend clause.");
23648 if (isa<DependentScopeDeclRefExpr>(Val: RefExpr)) {
23649 // It will be analyzed later.
23650 Vars.push_back(Elt: RefExpr);
23651 continue;
23652 }
23653
23654 SourceLocation ELoc = RefExpr->getExprLoc();
23655 Expr *SimpleExpr = RefExpr->IgnoreParenCasts();
23656 if (DepKind != OMPC_DEPEND_sink && DepKind != OMPC_DEPEND_source) {
23657 bool OMPDependTFound = getLangOpts().OpenMP >= 50;
23658 if (OMPDependTFound)
23659 OMPDependTFound = findOMPDependT(S&: SemaRef, Loc: StartLoc, DSAStack,
23660 Diagnose: DepKind == OMPC_DEPEND_depobj);
23661 if (DepKind == OMPC_DEPEND_depobj) {
23662 // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++
23663 // List items used in depend clauses with the depobj dependence type
23664 // must be expressions of the omp_depend_t type.
23665 if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() &&
23666 !RefExpr->isInstantiationDependent() &&
23667 !RefExpr->containsUnexpandedParameterPack() &&
23668 (OMPDependTFound &&
23669 !getASTContext().hasSameUnqualifiedType(
23670 DSAStack->getOMPDependT(), T2: RefExpr->getType()))) {
23671 Diag(Loc: ELoc, DiagID: diag::err_omp_expected_omp_depend_t_lvalue)
23672 << 0 << RefExpr->getType() << RefExpr->getSourceRange();
23673 continue;
23674 }
23675 if (!RefExpr->isLValue()) {
23676 Diag(Loc: ELoc, DiagID: diag::err_omp_expected_omp_depend_t_lvalue)
23677 << 1 << RefExpr->getType() << RefExpr->getSourceRange();
23678 continue;
23679 }
23680 } else {
23681 // OpenMP 5.0 [2.17.11, Restrictions]
23682 // List items used in depend clauses cannot be zero-length array
23683 // sections.
23684 QualType ExprTy = RefExpr->getType().getNonReferenceType();
23685 const auto *OASE = dyn_cast<ArraySectionExpr>(Val: SimpleExpr);
23686 if (OASE) {
23687 QualType BaseType =
23688 ArraySectionExpr::getBaseOriginalType(Base: OASE->getBase());
23689 if (BaseType.isNull())
23690 return nullptr;
23691 if (const auto *ATy = BaseType->getAsArrayTypeUnsafe())
23692 ExprTy = ATy->getElementType();
23693 else
23694 ExprTy = BaseType->getPointeeType();
23695 if (BaseType.isNull() || ExprTy.isNull())
23696 return nullptr;
23697 ExprTy = ExprTy.getNonReferenceType();
23698 const Expr *Length = OASE->getLength();
23699 Expr::EvalResult Result;
23700 if (Length && !Length->isValueDependent() &&
23701 Length->EvaluateAsInt(Result, Ctx: getASTContext()) &&
23702 Result.Val.getInt().isZero()) {
23703 Diag(Loc: ELoc,
23704 DiagID: diag::err_omp_depend_zero_length_array_section_not_allowed)
23705 << SimpleExpr->getSourceRange();
23706 continue;
23707 }
23708 }
23709
23710 // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++
23711 // List items used in depend clauses with the in, out, inout,
23712 // inoutset, or mutexinoutset dependence types cannot be
23713 // expressions of the omp_depend_t type.
23714 if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() &&
23715 !RefExpr->isInstantiationDependent() &&
23716 !RefExpr->containsUnexpandedParameterPack() &&
23717 (!RefExpr->IgnoreParenImpCasts()->isLValue() ||
23718 (OMPDependTFound && DSAStack->getOMPDependT().getTypePtr() ==
23719 ExprTy.getTypePtr()))) {
23720 Diag(Loc: ELoc, DiagID: diag::err_omp_expected_addressable_lvalue_or_array_item)
23721 << (getLangOpts().OpenMP >= 50 ? 1 : 0)
23722 << (getLangOpts().OpenMP >= 50 ? 1 : 0)
23723 << RefExpr->getSourceRange();
23724 continue;
23725 }
23726
23727 auto *ASE = dyn_cast<ArraySubscriptExpr>(Val: SimpleExpr);
23728 if (ASE && !ASE->getBase()->isTypeDependent() &&
23729 !ASE->getBase()
23730 ->getType()
23731 .getNonReferenceType()
23732 ->isPointerType() &&
23733 !ASE->getBase()->getType().getNonReferenceType()->isArrayType()) {
23734 Diag(Loc: ELoc, DiagID: diag::err_omp_expected_addressable_lvalue_or_array_item)
23735 << (getLangOpts().OpenMP >= 50 ? 1 : 0)
23736 << (getLangOpts().OpenMP >= 50 ? 1 : 0)
23737 << RefExpr->getSourceRange();
23738 continue;
23739 }
23740
23741 ExprResult Res;
23742 {
23743 Sema::TentativeAnalysisScope Trap(SemaRef);
23744 Res = SemaRef.CreateBuiltinUnaryOp(OpLoc: ELoc, Opc: UO_AddrOf,
23745 InputExpr: RefExpr->IgnoreParenImpCasts());
23746 }
23747 if (!Res.isUsable() && !isa<ArraySectionExpr>(Val: SimpleExpr) &&
23748 !isa<OMPArrayShapingExpr>(Val: SimpleExpr)) {
23749 Diag(Loc: ELoc, DiagID: diag::err_omp_expected_addressable_lvalue_or_array_item)
23750 << (getLangOpts().OpenMP >= 50 ? 1 : 0)
23751 << (getLangOpts().OpenMP >= 50 ? 1 : 0)
23752 << RefExpr->getSourceRange();
23753 continue;
23754 }
23755 }
23756 }
23757 Vars.push_back(Elt: RefExpr->IgnoreParenImpCasts());
23758 }
23759 }
23760
23761 if (DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink &&
23762 DepKind != OMPC_DEPEND_outallmemory &&
23763 DepKind != OMPC_DEPEND_inoutallmemory && Vars.empty())
23764 return nullptr;
23765
23766 auto *C = OMPDependClause::Create(
23767 C: getASTContext(), StartLoc, LParenLoc, EndLoc,
23768 Data: {.DepKind: DepKind, .DepLoc: DepLoc, .ColonLoc: Data.ColonLoc, .OmpAllMemoryLoc: Data.OmpAllMemoryLoc}, DepModifier, VL: Vars,
23769 NumLoops: TotalDepCount.getZExtValue());
23770 if ((DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) &&
23771 DSAStack->isParentOrderedRegion())
23772 DSAStack->addDoacrossDependClause(C, OpsOffs);
23773 return C;
23774}
23775
23776OMPClause *SemaOpenMP::ActOnOpenMPDeviceClause(
23777 OpenMPDeviceClauseModifier Modifier, Expr *Device, SourceLocation StartLoc,
23778 SourceLocation LParenLoc, SourceLocation ModifierLoc,
23779 SourceLocation EndLoc) {
23780 assert((ModifierLoc.isInvalid() || getLangOpts().OpenMP >= 50) &&
23781 "Unexpected device modifier in OpenMP < 50.");
23782
23783 bool ErrorFound = false;
23784 if (ModifierLoc.isValid() && Modifier == OMPC_DEVICE_unknown) {
23785 std::string Values =
23786 getListOfPossibleValues(K: OMPC_device, /*First=*/0, Last: OMPC_DEVICE_unknown);
23787 Diag(Loc: ModifierLoc, DiagID: diag::err_omp_unexpected_clause_value)
23788 << Values << getOpenMPClauseNameForDiag(C: OMPC_device);
23789 ErrorFound = true;
23790 }
23791
23792 Expr *ValExpr = Device;
23793 Stmt *HelperValStmt = nullptr;
23794
23795 // OpenMP 5.2 [1.3, Execution Model]: a conforming device number is either
23796 // a non-negative integer that is less than or equal to omp_get_num_devices()
23797 // or equal to omp_initial_device or omp_invalid_device. The predefined
23798 // identifiers were introduced in OpenMP 5.2; earlier versions require a
23799 // non-negative integer.
23800 if (getLangOpts().OpenMP >= 52) {
23801 if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() &&
23802 !ValExpr->isInstantiationDependent()) {
23803 SourceLocation Loc = ValExpr->getExprLoc();
23804 ExprResult Value = PerformOpenMPImplicitIntegerConversion(Loc, Op: ValExpr);
23805 if (Value.isInvalid()) {
23806 ErrorFound = true;
23807 } else {
23808 ValExpr = Value.get();
23809 if (std::optional<llvm::APSInt> Result =
23810 ValExpr->getIntegerConstantExpr(Ctx: getASTContext())) {
23811 if (Result->isSigned() && Result->slt(RHS: -2)) {
23812 Diag(Loc, DiagID: diag::err_omp_device_expression_invalid)
23813 << ValExpr->getSourceRange();
23814 ErrorFound = true;
23815 }
23816 }
23817 }
23818 }
23819 } else {
23820 ErrorFound = !isNonNegativeIntegerValue(ValExpr, SemaRef, CKind: OMPC_device,
23821 /*StrictlyPositive=*/false) ||
23822 ErrorFound;
23823 }
23824 if (ErrorFound)
23825 return nullptr;
23826
23827 // OpenMP 5.0 [2.12.5, Restrictions]
23828 // In case of ancestor device-modifier, a requires directive with
23829 // the reverse_offload clause must be specified.
23830 if (Modifier == OMPC_DEVICE_ancestor) {
23831 if (!DSAStack->hasRequiresDeclWithClause<OMPReverseOffloadClause>()) {
23832 SemaRef.targetDiag(
23833 Loc: StartLoc,
23834 DiagID: diag::err_omp_device_ancestor_without_requires_reverse_offload);
23835 ErrorFound = true;
23836 }
23837 }
23838
23839 OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
23840 OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause(
23841 DKind, CKind: OMPC_device, OMPVersion: getLangOpts().getOpenMPVersion());
23842 if (CaptureRegion != OMPD_unknown &&
23843 !SemaRef.CurContext->isDependentContext()) {
23844 ValExpr = SemaRef.MakeFullExpr(Arg: ValExpr).get();
23845 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
23846 ValExpr = tryBuildCapture(SemaRef, Capture: ValExpr, Captures).get();
23847 HelperValStmt = buildPreInits(Context&: getASTContext(), Captures);
23848 }
23849
23850 return new (getASTContext())
23851 OMPDeviceClause(Modifier, ValExpr, HelperValStmt, CaptureRegion, StartLoc,
23852 LParenLoc, ModifierLoc, EndLoc);
23853}
23854
23855static bool checkTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef,
23856 DSAStackTy *Stack, QualType QTy,
23857 bool FullCheck = true) {
23858 if (SemaRef.RequireCompleteType(Loc: SL, T: QTy, DiagID: diag::err_incomplete_type))
23859 return false;
23860 if (FullCheck && !SemaRef.CurContext->isDependentContext() &&
23861 !QTy.isTriviallyCopyableType(Context: SemaRef.Context))
23862 SemaRef.Diag(Loc: SL, DiagID: diag::warn_omp_non_trivial_type_mapped) << QTy << SR;
23863 return true;
23864}
23865
23866/// Return true if it can be proven that the provided array expression
23867/// (array section or array subscript) does NOT specify the whole size of the
23868/// array whose base type is \a BaseQTy.
23869static bool checkArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef,
23870 const Expr *E,
23871 QualType BaseQTy) {
23872 const auto *OASE = dyn_cast<ArraySectionExpr>(Val: E);
23873
23874 // If this is an array subscript, it refers to the whole size if the size of
23875 // the dimension is constant and equals 1. Also, an array section assumes the
23876 // format of an array subscript if no colon is used.
23877 if (isa<ArraySubscriptExpr>(Val: E) ||
23878 (OASE && OASE->getColonLocFirst().isInvalid())) {
23879 if (const auto *ATy = dyn_cast<ConstantArrayType>(Val: BaseQTy.getTypePtr()))
23880 return ATy->getSExtSize() != 1;
23881 // Size can't be evaluated statically.
23882 return false;
23883 }
23884
23885 assert(OASE && "Expecting array section if not an array subscript.");
23886 const Expr *LowerBound = OASE->getLowerBound();
23887 const Expr *Length = OASE->getLength();
23888
23889 // If there is a lower bound that does not evaluates to zero, we are not
23890 // covering the whole dimension.
23891 if (LowerBound) {
23892 Expr::EvalResult Result;
23893 if (!LowerBound->EvaluateAsInt(Result, Ctx: SemaRef.getASTContext()))
23894 return false; // Can't get the integer value as a constant.
23895
23896 llvm::APSInt ConstLowerBound = Result.Val.getInt();
23897 if (ConstLowerBound.getSExtValue())
23898 return true;
23899 }
23900
23901 // If we don't have a length we covering the whole dimension.
23902 if (!Length)
23903 return false;
23904
23905 // If the base is a pointer, we don't have a way to get the size of the
23906 // pointee.
23907 if (BaseQTy->isPointerType())
23908 return false;
23909
23910 // We can only check if the length is the same as the size of the dimension
23911 // if we have a constant array.
23912 const auto *CATy = dyn_cast<ConstantArrayType>(Val: BaseQTy.getTypePtr());
23913 if (!CATy)
23914 return false;
23915
23916 Expr::EvalResult Result;
23917 if (!Length->EvaluateAsInt(Result, Ctx: SemaRef.getASTContext()))
23918 return false; // Can't get the integer value as a constant.
23919
23920 llvm::APSInt ConstLength = Result.Val.getInt();
23921 return CATy->getSExtSize() != ConstLength.getSExtValue();
23922}
23923
23924// Return true if it can be proven that the provided array expression (array
23925// section or array subscript) does NOT specify a single element of the array
23926// whose base type is \a BaseQTy.
23927static bool checkArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef,
23928 const Expr *E,
23929 QualType BaseQTy) {
23930 const auto *OASE = dyn_cast<ArraySectionExpr>(Val: E);
23931
23932 // An array subscript always refer to a single element. Also, an array section
23933 // assumes the format of an array subscript if no colon is used.
23934 if (isa<ArraySubscriptExpr>(Val: E) ||
23935 (OASE && OASE->getColonLocFirst().isInvalid()))
23936 return false;
23937
23938 assert(OASE && "Expecting array section if not an array subscript.");
23939 const Expr *Length = OASE->getLength();
23940
23941 // If we don't have a length we have to check if the array has unitary size
23942 // for this dimension. Also, we should always expect a length if the base type
23943 // is pointer.
23944 if (!Length) {
23945 if (const auto *ATy = dyn_cast<ConstantArrayType>(Val: BaseQTy.getTypePtr()))
23946 return ATy->getSExtSize() != 1;
23947 // We cannot assume anything.
23948 return false;
23949 }
23950
23951 // Check if the length evaluates to 1.
23952 Expr::EvalResult Result;
23953 if (!Length->EvaluateAsInt(Result, Ctx: SemaRef.getASTContext()))
23954 return false; // Can't get the integer value as a constant.
23955
23956 llvm::APSInt ConstLength = Result.Val.getInt();
23957 return ConstLength.getSExtValue() != 1;
23958}
23959
23960// The base of elements of list in a map clause have to be either:
23961// - a reference to variable or field.
23962// - a member expression.
23963// - an array expression.
23964//
23965// E.g. if we have the expression 'r.S.Arr[:12]', we want to retrieve the
23966// reference to 'r'.
23967//
23968// If we have:
23969//
23970// struct SS {
23971// Bla S;
23972// foo() {
23973// #pragma omp target map (S.Arr[:12]);
23974// }
23975// }
23976//
23977// We want to retrieve the member expression 'this->S';
23978
23979// OpenMP 5.0 [2.19.7.1, map Clause, Restrictions, p.2]
23980// If a list item is an array section, it must specify contiguous storage.
23981//
23982// For this restriction it is sufficient that we make sure only references
23983// to variables or fields and array expressions, and that no array sections
23984// exist except in the rightmost expression (unless they cover the whole
23985// dimension of the array). E.g. these would be invalid:
23986//
23987// r.ArrS[3:5].Arr[6:7]
23988//
23989// r.ArrS[3:5].x
23990//
23991// but these would be valid:
23992// r.ArrS[3].Arr[6:7]
23993//
23994// r.ArrS[3].x
23995namespace {
23996class MapBaseChecker final : public StmtVisitor<MapBaseChecker, bool> {
23997 Sema &SemaRef;
23998 OpenMPClauseKind CKind = OMPC_unknown;
23999 OpenMPDirectiveKind DKind = OMPD_unknown;
24000 OMPClauseMappableExprCommon::MappableExprComponentList &Components;
24001 bool IsNonContiguous = false;
24002 bool NoDiagnose = false;
24003 const Expr *RelevantExpr = nullptr;
24004 bool AllowUnitySizeArraySection = true;
24005 bool AllowWholeSizeArraySection = true;
24006 bool AllowAnotherPtr = true;
24007 SourceLocation ELoc;
24008 SourceRange ERange;
24009
24010 void emitErrorMsg() {
24011 // If nothing else worked, this is not a valid map clause expression.
24012 if (SemaRef.getLangOpts().OpenMP < 50) {
24013 SemaRef.Diag(Loc: ELoc,
24014 DiagID: diag::err_omp_expected_named_var_member_or_array_expression)
24015 << ERange;
24016 } else {
24017 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_non_lvalue_in_map_or_motion_clauses)
24018 << getOpenMPClauseNameForDiag(C: CKind) << ERange;
24019 }
24020 }
24021
24022public:
24023 bool VisitDeclRefExpr(DeclRefExpr *DRE) {
24024 ValueDecl *D = DRE->getDecl();
24025 Expr *E = DRE;
24026
24027 // Handle BindingDecls by mapping them as member accesses.
24028 // When the user writes:
24029 // auto [a, b] = p;
24030 // #pragma omp target map(tofrom:a) map(to:b)
24031 // we transform it to:
24032 // #pragma omp target map(tofrom:p.x) map(to:p.y)
24033 // This avoids conflicts when different bindings have different map types.
24034 if (auto *BD = dyn_cast<BindingDecl>(Val: D)) {
24035 auto *DD = cast<DecompositionDecl>(Val: BD->getDecomposedDecl());
24036 Expr *BindingExpr = BD->getBinding();
24037
24038 // Check if the binding is a member expression (struct/class
24039 // decomposition).
24040 if (auto *ME = dyn_cast_or_null<MemberExpr>(Val: BindingExpr)) {
24041
24042 // Use the DecompositionDecl as the base for the member expression.
24043 // The structured binding creates a copy (if initialized from a
24044 // variable) or holds the only storage (if initialized from a prvalue).
24045 // Using DD ensures map clauses reference the correct storage.
24046 Expr *BaseExpr =
24047 SemaRef
24048 .BuildDeclarationNameExpr(
24049 SS: CXXScopeSpec(),
24050 NameInfo: DeclarationNameInfo(DD->getDeclName(), DRE->getLocation()),
24051 D: DD)
24052 .get();
24053
24054 // Create member expression: base.member.
24055 E = MemberExpr::Create(
24056 C: SemaRef.Context, Base: BaseExpr, /*IsArrow=*/false, OperatorLoc: ME->getOperatorLoc(),
24057 QualifierLoc: ME->getQualifierLoc(), TemplateKWLoc: ME->getTemplateKeywordLoc(),
24058 MemberDecl: ME->getMemberDecl(), FoundDecl: ME->getFoundDecl(), MemberNameInfo: ME->getMemberNameInfo(),
24059 /*TemplateArgs=*/nullptr, T: ME->getType(), VK: ME->getValueKind(),
24060 OK: ME->getObjectKind(), NOUR: ME->isNonOdrUse());
24061
24062 // Now process this as a member expression, which will properly
24063 // handle the field-level mapping.
24064 return Visit(S: E);
24065 }
24066 if (auto *ASE = dyn_cast_or_null<ArraySubscriptExpr>(Val: BindingExpr)) {
24067 Expr *BaseExpr =
24068 SemaRef
24069 .BuildDeclarationNameExpr(
24070 SS: CXXScopeSpec(),
24071 NameInfo: DeclarationNameInfo(DD->getDeclName(), DRE->getLocation()),
24072 D: DD)
24073 .get();
24074 E = new (SemaRef.Context) ArraySubscriptExpr(
24075 BaseExpr, ASE->getIdx(), ASE->getType(), ASE->getValueKind(),
24076 ASE->getObjectKind(), ASE->getRBracketLoc());
24077 return Visit(S: E);
24078 }
24079 // Tuple-like should already be rejected; do not map DD as a silent
24080 // fallback.
24081 SemaRef.Diag(Loc: DRE->getExprLoc(),
24082 DiagID: diag::err_omp_unsupported_structured_binding_init)
24083 << 4;
24084 return false;
24085 }
24086 // Handle DecompositionDecl directly (implicit captures).
24087 else if (auto *DD = dyn_cast<DecompositionDecl>(Val: D)) {
24088 if (const VarDecl *OrigVar =
24089 getOriginalVarOrDiagnose(S&: SemaRef, DD, Loc: DRE->getExprLoc())) {
24090 D = const_cast<VarDecl *>(OrigVar);
24091 DeclarationNameInfo NameInfo(D->getDeclName(), DRE->getLocation());
24092 E = DeclRefExpr::Create(Context: SemaRef.Context, QualifierLoc: DRE->getQualifierLoc(),
24093 TemplateKWLoc: DRE->getTemplateKeywordLoc(), D,
24094 /*RefersToEnclosingVariableOrCapture=*/false,
24095 NameInfo, T: D->getType(), VK: DRE->getValueKind(),
24096 FoundD: DRE->getFoundDecl(),
24097 /*TemplateArgs=*/nullptr, NOUR: DRE->isNonOdrUse());
24098 } else {
24099 return false;
24100 }
24101 } else if (!isa<VarDecl>(Val: D)) {
24102 emitErrorMsg();
24103 return false;
24104 }
24105 assert(!RelevantExpr && "RelevantExpr is expected to be nullptr");
24106 RelevantExpr = E;
24107 // Record the component.
24108 Components.emplace_back(Args&: E, Args&: D, Args&: IsNonContiguous);
24109 return true;
24110 }
24111
24112 bool VisitMemberExpr(MemberExpr *ME) {
24113 Expr *E = ME;
24114 Expr *BaseE = ME->getBase()->IgnoreParenCasts();
24115
24116 if (isa<CXXThisExpr>(Val: BaseE)) {
24117 assert(!RelevantExpr && "RelevantExpr is expected to be nullptr");
24118 // We found a base expression: this->Val.
24119 RelevantExpr = ME;
24120 } else {
24121 E = BaseE;
24122 }
24123
24124 if (!isa<FieldDecl>(Val: ME->getMemberDecl())) {
24125 if (!NoDiagnose) {
24126 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_expected_access_to_data_field)
24127 << ME->getSourceRange();
24128 return false;
24129 }
24130 if (RelevantExpr)
24131 return false;
24132 return Visit(S: E);
24133 }
24134
24135 auto *FD = cast<FieldDecl>(Val: ME->getMemberDecl());
24136
24137 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.3]
24138 // A bit-field cannot appear in a map clause.
24139 //
24140 if (FD->isBitField()) {
24141 if (!NoDiagnose) {
24142 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_bit_fields_forbidden_in_clause)
24143 << ME->getSourceRange() << getOpenMPClauseNameForDiag(C: CKind);
24144 return false;
24145 }
24146 if (RelevantExpr)
24147 return false;
24148 return Visit(S: E);
24149 }
24150
24151 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
24152 // If the type of a list item is a reference to a type T then the type
24153 // will be considered to be T for all purposes of this clause.
24154 QualType CurType = BaseE->getType().getNonReferenceType();
24155
24156 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.2]
24157 // A list item cannot be a variable that is a member of a structure with
24158 // a union type.
24159 //
24160 if (CurType->isUnionType()) {
24161 if (!NoDiagnose) {
24162 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_union_type_not_allowed)
24163 << ME->getSourceRange();
24164 return false;
24165 }
24166 return RelevantExpr || Visit(S: E);
24167 }
24168
24169 // If we got a member expression, we should not expect any array section
24170 // before that:
24171 //
24172 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.7]
24173 // If a list item is an element of a structure, only the rightmost symbol
24174 // of the variable reference can be an array section.
24175 //
24176 AllowUnitySizeArraySection = false;
24177 AllowWholeSizeArraySection = false;
24178
24179 // Record the component.
24180 Components.emplace_back(Args&: ME, Args&: FD, Args&: IsNonContiguous);
24181 return RelevantExpr || Visit(S: E);
24182 }
24183
24184 bool VisitArraySubscriptExpr(ArraySubscriptExpr *AE) {
24185 Expr *E = AE->getBase()->IgnoreParenImpCasts();
24186
24187 if (!E->getType()->isAnyPointerType() && !E->getType()->isArrayType()) {
24188 if (!NoDiagnose) {
24189 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_expected_base_var_name)
24190 << 0 << AE->getSourceRange();
24191 return false;
24192 }
24193 return RelevantExpr || Visit(S: E);
24194 }
24195
24196 // If we got an array subscript that express the whole dimension we
24197 // can have any array expressions before. If it only expressing part of
24198 // the dimension, we can only have unitary-size array expressions.
24199 if (checkArrayExpressionDoesNotReferToWholeSize(SemaRef, E: AE, BaseQTy: E->getType()))
24200 AllowWholeSizeArraySection = false;
24201
24202 if (const auto *TE = dyn_cast<CXXThisExpr>(Val: E->IgnoreParenCasts())) {
24203 Expr::EvalResult Result;
24204 if (!AE->getIdx()->isValueDependent() &&
24205 AE->getIdx()->EvaluateAsInt(Result, Ctx: SemaRef.getASTContext()) &&
24206 !Result.Val.getInt().isZero()) {
24207 SemaRef.Diag(Loc: AE->getIdx()->getExprLoc(),
24208 DiagID: diag::err_omp_invalid_map_this_expr);
24209 SemaRef.Diag(Loc: AE->getIdx()->getExprLoc(),
24210 DiagID: diag::note_omp_invalid_subscript_on_this_ptr_map);
24211 }
24212 assert(!RelevantExpr && "RelevantExpr is expected to be nullptr");
24213 RelevantExpr = TE;
24214 }
24215
24216 // Record the component - we don't have any declaration associated.
24217 Components.emplace_back(Args&: AE, Args: nullptr, Args&: IsNonContiguous);
24218
24219 return RelevantExpr || Visit(S: E);
24220 }
24221
24222 bool VisitArraySectionExpr(ArraySectionExpr *OASE) {
24223 // After OMP 5.0 Array section in reduction clause will be implicitly
24224 // mapped
24225 assert(!(SemaRef.getLangOpts().OpenMP < 50 && NoDiagnose) &&
24226 "Array sections cannot be implicitly mapped.");
24227 Expr *E = OASE->getBase()->IgnoreParenImpCasts();
24228 QualType CurType =
24229 ArraySectionExpr::getBaseOriginalType(Base: E).getCanonicalType();
24230
24231 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
24232 // If the type of a list item is a reference to a type T then the type
24233 // will be considered to be T for all purposes of this clause.
24234 if (CurType->isReferenceType())
24235 CurType = CurType->getPointeeType();
24236
24237 bool IsPointer = CurType->isAnyPointerType();
24238
24239 if (!IsPointer && !CurType->isArrayType()) {
24240 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_expected_base_var_name)
24241 << 0 << OASE->getSourceRange();
24242 return false;
24243 }
24244
24245 bool NotWhole =
24246 checkArrayExpressionDoesNotReferToWholeSize(SemaRef, E: OASE, BaseQTy: CurType);
24247 bool NotUnity =
24248 checkArrayExpressionDoesNotReferToUnitySize(SemaRef, E: OASE, BaseQTy: CurType);
24249
24250 if (AllowWholeSizeArraySection) {
24251 // Any array section is currently allowed. Allowing a whole size array
24252 // section implies allowing a unity array section as well.
24253 //
24254 // If this array section refers to the whole dimension we can still
24255 // accept other array sections before this one, except if the base is a
24256 // pointer. Otherwise, only unitary sections are accepted.
24257 if (NotWhole || IsPointer)
24258 AllowWholeSizeArraySection = false;
24259 } else if (DKind == OMPD_target_update &&
24260 SemaRef.getLangOpts().OpenMP >= 50) {
24261 if (IsPointer && !AllowAnotherPtr)
24262 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_section_length_undefined)
24263 << /*array of unknown bound */ 1;
24264 else
24265 IsNonContiguous = true;
24266 } else if (AllowUnitySizeArraySection && NotUnity) {
24267 // A unity or whole array section is not allowed and that is not
24268 // compatible with the properties of the current array section.
24269 if (NoDiagnose)
24270 return false;
24271 SemaRef.Diag(Loc: ELoc,
24272 DiagID: diag::err_array_section_does_not_specify_contiguous_storage)
24273 << OASE->getSourceRange();
24274 return false;
24275 }
24276
24277 if (IsPointer)
24278 AllowAnotherPtr = false;
24279
24280 if (const auto *TE = dyn_cast<CXXThisExpr>(Val: E)) {
24281 Expr::EvalResult ResultR;
24282 Expr::EvalResult ResultL;
24283 if (!OASE->getLength()->isValueDependent() &&
24284 OASE->getLength()->EvaluateAsInt(Result&: ResultR, Ctx: SemaRef.getASTContext()) &&
24285 !ResultR.Val.getInt().isOne()) {
24286 SemaRef.Diag(Loc: OASE->getLength()->getExprLoc(),
24287 DiagID: diag::err_omp_invalid_map_this_expr);
24288 SemaRef.Diag(Loc: OASE->getLength()->getExprLoc(),
24289 DiagID: diag::note_omp_invalid_length_on_this_ptr_mapping);
24290 }
24291 if (OASE->getLowerBound() && !OASE->getLowerBound()->isValueDependent() &&
24292 OASE->getLowerBound()->EvaluateAsInt(Result&: ResultL,
24293 Ctx: SemaRef.getASTContext()) &&
24294 !ResultL.Val.getInt().isZero()) {
24295 SemaRef.Diag(Loc: OASE->getLowerBound()->getExprLoc(),
24296 DiagID: diag::err_omp_invalid_map_this_expr);
24297 SemaRef.Diag(Loc: OASE->getLowerBound()->getExprLoc(),
24298 DiagID: diag::note_omp_invalid_lower_bound_on_this_ptr_mapping);
24299 }
24300 assert(!RelevantExpr && "RelevantExpr is expected to be nullptr");
24301 RelevantExpr = TE;
24302 }
24303
24304 // Record the component - we don't have any declaration associated.
24305 Components.emplace_back(Args&: OASE, Args: nullptr, /*IsNonContiguous=*/Args: false);
24306 return RelevantExpr || Visit(S: E);
24307 }
24308 bool VisitOMPArrayShapingExpr(OMPArrayShapingExpr *E) {
24309 Expr *Base = E->getBase();
24310
24311 // Record the component - we don't have any declaration associated.
24312 Components.emplace_back(Args&: E, Args: nullptr, Args&: IsNonContiguous);
24313
24314 return Visit(S: Base->IgnoreParenImpCasts());
24315 }
24316
24317 bool VisitUnaryOperator(UnaryOperator *UO) {
24318 if (SemaRef.getLangOpts().OpenMP < 50 || !UO->isLValue() ||
24319 UO->getOpcode() != UO_Deref) {
24320 emitErrorMsg();
24321 return false;
24322 }
24323 if (!RelevantExpr) {
24324 // Record the component if haven't found base decl.
24325 Components.emplace_back(Args&: UO, Args: nullptr, /*IsNonContiguous=*/Args: false);
24326 }
24327 return RelevantExpr || Visit(S: UO->getSubExpr()->IgnoreParenImpCasts());
24328 }
24329 bool VisitBinaryOperator(BinaryOperator *BO) {
24330 if (SemaRef.getLangOpts().OpenMP < 50 || !BO->getType()->isPointerType()) {
24331 emitErrorMsg();
24332 return false;
24333 }
24334
24335 // Pointer arithmetic is the only thing we expect to happen here so after we
24336 // make sure the binary operator is a pointer type, the only thing we need
24337 // to do is to visit the subtree that has the same type as root (so that we
24338 // know the other subtree is just an offset)
24339 Expr *LE = BO->getLHS()->IgnoreParenImpCasts();
24340 Expr *RE = BO->getRHS()->IgnoreParenImpCasts();
24341 Components.emplace_back(Args&: BO, Args: nullptr, Args: false);
24342 assert((LE->getType().getTypePtr() == BO->getType().getTypePtr() ||
24343 RE->getType().getTypePtr() == BO->getType().getTypePtr()) &&
24344 "Either LHS or RHS have base decl inside");
24345 if (BO->getType().getTypePtr() == LE->getType().getTypePtr())
24346 return RelevantExpr || Visit(S: LE);
24347 return RelevantExpr || Visit(S: RE);
24348 }
24349 bool VisitCXXThisExpr(CXXThisExpr *CTE) {
24350 assert(!RelevantExpr && "RelevantExpr is expected to be nullptr");
24351 RelevantExpr = CTE;
24352 Components.emplace_back(Args&: CTE, Args: nullptr, Args&: IsNonContiguous);
24353 return true;
24354 }
24355 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *COCE) {
24356 assert(!RelevantExpr && "RelevantExpr is expected to be nullptr");
24357 Components.emplace_back(Args&: COCE, Args: nullptr, Args&: IsNonContiguous);
24358 return true;
24359 }
24360 bool VisitOpaqueValueExpr(OpaqueValueExpr *E) {
24361 Expr *Source = E->getSourceExpr();
24362 if (!Source) {
24363 emitErrorMsg();
24364 return false;
24365 }
24366 return Visit(S: Source);
24367 }
24368 bool VisitStmt(Stmt *) {
24369 emitErrorMsg();
24370 return false;
24371 }
24372 const Expr *getFoundBase() const { return RelevantExpr; }
24373 explicit MapBaseChecker(
24374 Sema &SemaRef, OpenMPClauseKind CKind, OpenMPDirectiveKind DKind,
24375 OMPClauseMappableExprCommon::MappableExprComponentList &Components,
24376 bool NoDiagnose, SourceLocation &ELoc, SourceRange &ERange)
24377 : SemaRef(SemaRef), CKind(CKind), DKind(DKind), Components(Components),
24378 NoDiagnose(NoDiagnose), ELoc(ELoc), ERange(ERange) {}
24379};
24380} // namespace
24381
24382/// Return the expression of the base of the mappable expression or null if it
24383/// cannot be determined and do all the necessary checks to see if the
24384/// expression is valid as a standalone mappable expression. In the process,
24385/// record all the components of the expression.
24386static const Expr *checkMapClauseExpressionBase(
24387 Sema &SemaRef, Expr *E,
24388 OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents,
24389 OpenMPClauseKind CKind, OpenMPDirectiveKind DKind, bool NoDiagnose) {
24390 SourceLocation ELoc = E->getExprLoc();
24391 SourceRange ERange = E->getSourceRange();
24392 MapBaseChecker Checker(SemaRef, CKind, DKind, CurComponents, NoDiagnose, ELoc,
24393 ERange);
24394 if (Checker.Visit(S: E->IgnoreParens())) {
24395 // Check if the highest dimension array section has length specified
24396 if (SemaRef.getLangOpts().OpenMP >= 50 && !CurComponents.empty() &&
24397 (CKind == OMPC_to || CKind == OMPC_from)) {
24398 auto CI = CurComponents.rbegin();
24399 auto CE = CurComponents.rend();
24400 for (; CI != CE; ++CI) {
24401 const auto *OASE =
24402 dyn_cast<ArraySectionExpr>(Val: CI->getAssociatedExpression());
24403 if (!OASE)
24404 continue;
24405 if (OASE && OASE->getLength())
24406 break;
24407 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_array_section_does_not_specify_length)
24408 << ERange;
24409 }
24410 }
24411 return Checker.getFoundBase();
24412 }
24413 return nullptr;
24414}
24415
24416// Return true if expression E associated with value VD has conflicts with other
24417// map information.
24418static bool checkMapConflicts(
24419 Sema &SemaRef, DSAStackTy *DSAS, const ValueDecl *VD, const Expr *E,
24420 bool CurrentRegionOnly,
24421 OMPClauseMappableExprCommon::MappableExprComponentListRef CurComponents,
24422 OpenMPClauseKind CKind) {
24423 assert(VD && E);
24424 SourceLocation ELoc = E->getExprLoc();
24425 SourceRange ERange = E->getSourceRange();
24426
24427 // In order to easily check the conflicts we need to match each component of
24428 // the expression under test with the components of the expressions that are
24429 // already in the stack.
24430
24431 assert(!CurComponents.empty() && "Map clause expression with no components!");
24432 assert(CurComponents.back().getAssociatedDeclaration() == VD &&
24433 "Map clause expression with unexpected base!");
24434
24435 // Variables to help detecting enclosing problems in data environment nests.
24436 bool IsEnclosedByDataEnvironmentExpr = false;
24437 const Expr *EnclosingExpr = nullptr;
24438
24439 bool FoundError = DSAS->checkMappableExprComponentListsForDecl(
24440 VD, CurrentRegionOnly,
24441 Check: [&IsEnclosedByDataEnvironmentExpr, &SemaRef, VD, CurrentRegionOnly, ELoc,
24442 ERange, CKind, &EnclosingExpr,
24443 CurComponents](OMPClauseMappableExprCommon::MappableExprComponentListRef
24444 StackComponents,
24445 OpenMPClauseKind Kind) {
24446 if (CKind == Kind && SemaRef.LangOpts.OpenMP >= 50)
24447 return false;
24448 assert(!StackComponents.empty() &&
24449 "Map clause expression with no components!");
24450 assert(StackComponents.back().getAssociatedDeclaration() == VD &&
24451 "Map clause expression with unexpected base!");
24452 (void)VD;
24453
24454 // The whole expression in the stack.
24455 const Expr *RE = StackComponents.front().getAssociatedExpression();
24456
24457 // Expressions must start from the same base. Here we detect at which
24458 // point both expressions diverge from each other and see if we can
24459 // detect if the memory referred to both expressions is contiguous and
24460 // do not overlap.
24461 auto CI = CurComponents.rbegin();
24462 auto CE = CurComponents.rend();
24463 auto SI = StackComponents.rbegin();
24464 auto SE = StackComponents.rend();
24465 for (; CI != CE && SI != SE; ++CI, ++SI) {
24466
24467 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.3]
24468 // At most one list item can be an array item derived from a given
24469 // variable in map clauses of the same construct.
24470 if (CurrentRegionOnly &&
24471 (isa<ArraySubscriptExpr>(Val: CI->getAssociatedExpression()) ||
24472 isa<ArraySectionExpr>(Val: CI->getAssociatedExpression()) ||
24473 isa<OMPArrayShapingExpr>(Val: CI->getAssociatedExpression())) &&
24474 (isa<ArraySubscriptExpr>(Val: SI->getAssociatedExpression()) ||
24475 isa<ArraySectionExpr>(Val: SI->getAssociatedExpression()) ||
24476 isa<OMPArrayShapingExpr>(Val: SI->getAssociatedExpression()))) {
24477 SemaRef.Diag(Loc: CI->getAssociatedExpression()->getExprLoc(),
24478 DiagID: diag::err_omp_multiple_array_items_in_map_clause)
24479 << CI->getAssociatedExpression()->getSourceRange();
24480 SemaRef.Diag(Loc: SI->getAssociatedExpression()->getExprLoc(),
24481 DiagID: diag::note_used_here)
24482 << SI->getAssociatedExpression()->getSourceRange();
24483 return true;
24484 }
24485
24486 // Do both expressions have the same kind?
24487 if (CI->getAssociatedExpression()->getStmtClass() !=
24488 SI->getAssociatedExpression()->getStmtClass())
24489 break;
24490
24491 // Are we dealing with different variables/fields?
24492 if (CI->getAssociatedDeclaration() != SI->getAssociatedDeclaration())
24493 break;
24494 }
24495 // Check if the extra components of the expressions in the enclosing
24496 // data environment are redundant for the current base declaration.
24497 // If they are, the maps completely overlap, which is legal.
24498 for (; SI != SE; ++SI) {
24499 QualType Type;
24500 if (const auto *ASE =
24501 dyn_cast<ArraySubscriptExpr>(Val: SI->getAssociatedExpression())) {
24502 Type = ASE->getBase()->IgnoreParenImpCasts()->getType();
24503 } else if (const auto *OASE = dyn_cast<ArraySectionExpr>(
24504 Val: SI->getAssociatedExpression())) {
24505 const Expr *E = OASE->getBase()->IgnoreParenImpCasts();
24506 Type = ArraySectionExpr::getBaseOriginalType(Base: E).getCanonicalType();
24507 } else if (const auto *OASE = dyn_cast<OMPArrayShapingExpr>(
24508 Val: SI->getAssociatedExpression())) {
24509 Type = OASE->getBase()->getType()->getPointeeType();
24510 }
24511 if (Type.isNull() || Type->isAnyPointerType() ||
24512 checkArrayExpressionDoesNotReferToWholeSize(
24513 SemaRef, E: SI->getAssociatedExpression(), BaseQTy: Type))
24514 break;
24515 }
24516
24517 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.4]
24518 // List items of map clauses in the same construct must not share
24519 // original storage.
24520 //
24521 // If the expressions are exactly the same or one is a subset of the
24522 // other, it means they are sharing storage.
24523 if (CI == CE && SI == SE) {
24524 if (CurrentRegionOnly) {
24525 if (CKind == OMPC_map) {
24526 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_map_shared_storage) << ERange;
24527 } else {
24528 assert(CKind == OMPC_to || CKind == OMPC_from);
24529 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_once_referenced_in_target_update)
24530 << ERange;
24531 }
24532 SemaRef.Diag(Loc: RE->getExprLoc(), DiagID: diag::note_used_here)
24533 << RE->getSourceRange();
24534 return true;
24535 }
24536 // If we find the same expression in the enclosing data environment,
24537 // that is legal.
24538 IsEnclosedByDataEnvironmentExpr = true;
24539 return false;
24540 }
24541
24542 QualType DerivedType =
24543 std::prev(x: CI)->getAssociatedDeclaration()->getType();
24544 SourceLocation DerivedLoc =
24545 std::prev(x: CI)->getAssociatedExpression()->getExprLoc();
24546
24547 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
24548 // If the type of a list item is a reference to a type T then the type
24549 // will be considered to be T for all purposes of this clause.
24550 DerivedType = DerivedType.getNonReferenceType();
24551
24552 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.1]
24553 // A variable for which the type is pointer and an array section
24554 // derived from that variable must not appear as list items of map
24555 // clauses of the same construct.
24556 //
24557 // Also, cover one of the cases in:
24558 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.5]
24559 // If any part of the original storage of a list item has corresponding
24560 // storage in the device data environment, all of the original storage
24561 // must have corresponding storage in the device data environment.
24562 //
24563 if (DerivedType->isAnyPointerType()) {
24564 if (CI == CE || SI == SE) {
24565 SemaRef.Diag(
24566 Loc: DerivedLoc,
24567 DiagID: diag::err_omp_pointer_mapped_along_with_derived_section)
24568 << DerivedLoc;
24569 SemaRef.Diag(Loc: RE->getExprLoc(), DiagID: diag::note_used_here)
24570 << RE->getSourceRange();
24571 return true;
24572 }
24573 if (CI->getAssociatedExpression()->getStmtClass() !=
24574 SI->getAssociatedExpression()->getStmtClass() ||
24575 CI->getAssociatedDeclaration()->getCanonicalDecl() ==
24576 SI->getAssociatedDeclaration()->getCanonicalDecl()) {
24577 assert(CI != CE && SI != SE);
24578 SemaRef.Diag(Loc: DerivedLoc, DiagID: diag::err_omp_same_pointer_dereferenced)
24579 << DerivedLoc;
24580 SemaRef.Diag(Loc: RE->getExprLoc(), DiagID: diag::note_used_here)
24581 << RE->getSourceRange();
24582 return true;
24583 }
24584 }
24585
24586 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.4]
24587 // List items of map clauses in the same construct must not share
24588 // original storage.
24589 //
24590 // An expression is a subset of the other.
24591 if (CurrentRegionOnly && (CI == CE || SI == SE)) {
24592 if (CKind == OMPC_map) {
24593 if (CI != CE || SI != SE) {
24594 // Allow constructs like this: map(s, s.ptr[0:1]), where s.ptr is
24595 // a pointer.
24596 auto Begin =
24597 CI != CE ? CurComponents.begin() : StackComponents.begin();
24598 auto End = CI != CE ? CurComponents.end() : StackComponents.end();
24599 auto It = Begin;
24600 while (It != End && !It->getAssociatedDeclaration())
24601 std::advance(i&: It, n: 1);
24602 assert(It != End &&
24603 "Expected at least one component with the declaration.");
24604 if (It != Begin && It->getAssociatedDeclaration()
24605 ->getType()
24606 .getCanonicalType()
24607 ->isAnyPointerType()) {
24608 IsEnclosedByDataEnvironmentExpr = false;
24609 EnclosingExpr = nullptr;
24610 return false;
24611 }
24612 }
24613 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_map_shared_storage) << ERange;
24614 } else {
24615 assert(CKind == OMPC_to || CKind == OMPC_from);
24616 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_once_referenced_in_target_update)
24617 << ERange;
24618 }
24619 SemaRef.Diag(Loc: RE->getExprLoc(), DiagID: diag::note_used_here)
24620 << RE->getSourceRange();
24621 return true;
24622 }
24623
24624 // The current expression uses the same base as other expression in the
24625 // data environment but does not contain it completely.
24626 if (!CurrentRegionOnly && SI != SE)
24627 EnclosingExpr = RE;
24628
24629 // The current expression is a subset of the expression in the data
24630 // environment.
24631 IsEnclosedByDataEnvironmentExpr |=
24632 (!CurrentRegionOnly && CI != CE && SI == SE);
24633
24634 return false;
24635 });
24636
24637 if (CurrentRegionOnly)
24638 return FoundError;
24639
24640 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.5]
24641 // If any part of the original storage of a list item has corresponding
24642 // storage in the device data environment, all of the original storage must
24643 // have corresponding storage in the device data environment.
24644 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.6]
24645 // If a list item is an element of a structure, and a different element of
24646 // the structure has a corresponding list item in the device data environment
24647 // prior to a task encountering the construct associated with the map clause,
24648 // then the list item must also have a corresponding list item in the device
24649 // data environment prior to the task encountering the construct.
24650 //
24651 if (EnclosingExpr && !IsEnclosedByDataEnvironmentExpr) {
24652 SemaRef.Diag(Loc: ELoc,
24653 DiagID: diag::err_omp_original_storage_is_shared_and_does_not_contain)
24654 << ERange;
24655 SemaRef.Diag(Loc: EnclosingExpr->getExprLoc(), DiagID: diag::note_used_here)
24656 << EnclosingExpr->getSourceRange();
24657 return true;
24658 }
24659
24660 return FoundError;
24661}
24662
24663// Look up the user-defined mapper given the mapper name and mapped type, and
24664// build a reference to it. \a ItemLoc is the location of the mapped list item;
24665// it is used as the point of instantiation since \a MapperId has no location
24666// for implicit map clauses.
24667static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
24668 CXXScopeSpec &MapperIdScopeSpec,
24669 const DeclarationNameInfo &MapperId,
24670 QualType Type,
24671 Expr *UnresolvedMapper,
24672 SourceLocation ItemLoc) {
24673 if (MapperIdScopeSpec.isInvalid())
24674 return ExprError();
24675 // Get the actual type for the array type.
24676 if (Type->isArrayType()) {
24677 assert(Type->getAsArrayTypeUnsafe() && "Expect to get a valid array type");
24678 Type = Type->getAsArrayTypeUnsafe()->getElementType().getCanonicalType();
24679 }
24680 // Find all user-defined mappers with the given MapperId.
24681 SmallVector<UnresolvedSet<8>, 4> Lookups;
24682 LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName);
24683 Lookup.suppressDiagnostics();
24684 if (S) {
24685 while (S && SemaRef.LookupParsedName(R&: Lookup, S, SS: &MapperIdScopeSpec,
24686 /*ObjectType=*/QualType())) {
24687 NamedDecl *D = Lookup.getRepresentativeDecl();
24688 while (S && !S->isDeclScope(D))
24689 S = S->getParent();
24690 if (S)
24691 S = S->getParent();
24692 Lookups.emplace_back();
24693 Lookups.back().append(I: Lookup.begin(), E: Lookup.end());
24694 Lookup.clear();
24695 }
24696 } else if (auto *ULE = cast_or_null<UnresolvedLookupExpr>(Val: UnresolvedMapper)) {
24697 // Extract the user-defined mappers with the given MapperId.
24698 Lookups.push_back(Elt: UnresolvedSet<8>());
24699 for (NamedDecl *D : ULE->decls()) {
24700 auto *DMD = cast<OMPDeclareMapperDecl>(Val: D);
24701 assert(DMD && "Expect valid OMPDeclareMapperDecl during instantiation.");
24702 Lookups.back().addDecl(D: DMD);
24703 }
24704 }
24705 // Defer the lookup for dependent types. The results will be passed through
24706 // UnresolvedMapper on instantiation.
24707 if (SemaRef.CurContext->isDependentContext() || Type->isDependentType() ||
24708 Type->isInstantiationDependentType() ||
24709 Type->containsUnexpandedParameterPack() ||
24710 filterLookupForUDReductionAndMapper<bool>(Lookups, Gen: [](ValueDecl *D) {
24711 return !D->isInvalidDecl() &&
24712 (D->getType()->isDependentType() ||
24713 D->getType()->isInstantiationDependentType() ||
24714 D->getType()->containsUnexpandedParameterPack());
24715 })) {
24716 UnresolvedSet<8> URS;
24717 for (const UnresolvedSet<8> &Set : Lookups) {
24718 if (Set.empty())
24719 continue;
24720 URS.append(I: Set.begin(), E: Set.end());
24721 }
24722 return UnresolvedLookupExpr::Create(
24723 Context: SemaRef.Context, /*NamingClass=*/nullptr,
24724 QualifierLoc: MapperIdScopeSpec.getWithLocInContext(Context&: SemaRef.Context), NameInfo: MapperId,
24725 /*ADL=*/RequiresADL: false, Begin: URS.begin(), End: URS.end(), /*KnownDependent=*/false,
24726 /*KnownInstantiationDependent=*/false);
24727 }
24728 SourceLocation Loc = MapperId.getLoc();
24729 // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions
24730 // The type must be of struct, union or class type in C and C++
24731 if (!Type->isStructureOrClassType() && !Type->isUnionType() &&
24732 (MapperIdScopeSpec.isSet() || MapperId.getAsString() != "default")) {
24733 SemaRef.Diag(Loc, DiagID: diag::err_omp_mapper_wrong_type);
24734 return ExprError();
24735 }
24736 // Perform argument dependent lookup.
24737 if (SemaRef.getLangOpts().CPlusPlus && !MapperIdScopeSpec.isSet())
24738 argumentDependentLookup(SemaRef, Id: MapperId, Loc: ItemLoc, Ty: Type, Lookups);
24739 // Return the first user-defined mapper with the desired type.
24740 if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>(
24741 Lookups, Gen: [&SemaRef, Type](ValueDecl *D) -> ValueDecl * {
24742 if (!D->isInvalidDecl() &&
24743 SemaRef.Context.hasSameType(T1: D->getType(), T2: Type))
24744 return D;
24745 return nullptr;
24746 }))
24747 return SemaRef.BuildDeclRefExpr(D: VD, Ty: Type, VK: VK_LValue, Loc);
24748 // Find the first user-defined mapper with a type derived from the desired
24749 // type.
24750 if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>(
24751 Lookups, Gen: [&SemaRef, Type, ItemLoc](ValueDecl *D) -> ValueDecl * {
24752 if (!D->isInvalidDecl() &&
24753 SemaRef.IsDerivedFrom(Loc: ItemLoc, Derived: Type, Base: D->getType()) &&
24754 !Type.isMoreQualifiedThan(other: D->getType(),
24755 Ctx: SemaRef.getASTContext()))
24756 return D;
24757 return nullptr;
24758 })) {
24759 CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
24760 /*DetectVirtual=*/false);
24761 if (SemaRef.IsDerivedFrom(Loc: ItemLoc, Derived: Type, Base: VD->getType(), Paths)) {
24762 if (!Paths.isAmbiguous(BaseType: SemaRef.Context.getCanonicalType(
24763 T: VD->getType().getUnqualifiedType()))) {
24764 if (SemaRef.CheckBaseClassAccess(
24765 AccessLoc: ItemLoc, Base: VD->getType(), Derived: Type, Path: Paths.front(),
24766 /*DiagID=*/0) != Sema::AR_inaccessible) {
24767 return SemaRef.BuildDeclRefExpr(D: VD, Ty: Type, VK: VK_LValue, Loc);
24768 }
24769 }
24770 }
24771 }
24772 // Report error if a mapper is specified, but cannot be found.
24773 if (MapperIdScopeSpec.isSet() || MapperId.getAsString() != "default") {
24774 SemaRef.Diag(Loc, DiagID: diag::err_omp_invalid_mapper)
24775 << Type << MapperId.getName();
24776 return ExprError();
24777 }
24778 return ExprEmpty();
24779}
24780
24781namespace {
24782// Utility struct that gathers all the related lists associated with a mappable
24783// expression.
24784struct MappableVarListInfo {
24785 // The list of expressions.
24786 ArrayRef<Expr *> VarList;
24787 // The list of processed expressions.
24788 SmallVector<Expr *, 16> ProcessedVarList;
24789 // The mappble components for each expression.
24790 OMPClauseMappableExprCommon::MappableExprComponentLists VarComponents;
24791 // The base declaration of the variable.
24792 SmallVector<ValueDecl *, 16> VarBaseDeclarations;
24793 // The reference to the user-defined mapper associated with every expression.
24794 SmallVector<Expr *, 16> UDMapperList;
24795
24796 MappableVarListInfo(ArrayRef<Expr *> VarList) : VarList(VarList) {
24797 // We have a list of components and base declarations for each entry in the
24798 // variable list.
24799 VarComponents.reserve(N: VarList.size());
24800 VarBaseDeclarations.reserve(N: VarList.size());
24801 }
24802};
24803} // namespace
24804
24805static DeclRefExpr *buildImplicitMap(Sema &S, QualType BaseType,
24806 DSAStackTy *Stack,
24807 SmallVectorImpl<OMPClause *> &Maps) {
24808
24809 const RecordDecl *RD = BaseType->getAsRecordDecl();
24810 SourceRange Range = RD->getSourceRange();
24811 DeclarationNameInfo ImplicitName;
24812 // Dummy variable _s for Mapper.
24813 VarDecl *VD = buildVarDecl(SemaRef&: S, Loc: Range.getEnd(), Type: BaseType, Name: "_s");
24814 DeclRefExpr *MapperVarRef =
24815 buildDeclRefExpr(S, D: VD, Ty: BaseType, Loc: SourceLocation());
24816
24817 // Create implicit map clause for mapper.
24818 SmallVector<Expr *, 4> SExprs;
24819 for (auto *FD : RD->fields()) {
24820 Expr *BE = S.BuildMemberExpr(
24821 Base: MapperVarRef, /*IsArrow=*/false, OpLoc: Range.getBegin(),
24822 NNS: NestedNameSpecifierLoc(), TemplateKWLoc: Range.getBegin(), Member: FD,
24823 FoundDecl: DeclAccessPair::make(D: FD, AS: FD->getAccess()),
24824 /*HadMultipleCandidates=*/false,
24825 MemberNameInfo: DeclarationNameInfo(FD->getDeclName(), FD->getSourceRange().getBegin()),
24826 Ty: FD->getType(), VK: VK_LValue, OK: OK_Ordinary);
24827 SExprs.push_back(Elt: BE);
24828 }
24829 CXXScopeSpec MapperIdScopeSpec;
24830 DeclarationNameInfo MapperId;
24831 OpenMPDirectiveKind DKind = Stack->getCurrentDirective();
24832
24833 OMPClause *MapClause = S.OpenMP().ActOnOpenMPMapClause(
24834 IteratorModifier: nullptr, MapTypeModifiers: OMPC_MAP_MODIFIER_unknown, MapTypeModifiersLoc: SourceLocation(), MapperIdScopeSpec,
24835 MapperId, MapType: DKind == OMPD_target_enter_data ? OMPC_MAP_to : OMPC_MAP_tofrom,
24836 /*IsMapTypeImplicit=*/true, MapLoc: SourceLocation(), ColonLoc: SourceLocation(), VarList: SExprs,
24837 Locs: OMPVarListLocTy());
24838 Maps.push_back(Elt: MapClause);
24839 return MapperVarRef;
24840}
24841
24842static ExprResult buildImplicitMapper(Sema &S, QualType BaseType,
24843 DSAStackTy *Stack) {
24844
24845 // Build impilicit map for mapper
24846 SmallVector<OMPClause *, 4> Maps;
24847 DeclRefExpr *MapperVarRef = buildImplicitMap(S, BaseType, Stack, Maps);
24848
24849 const RecordDecl *RD = BaseType->getAsRecordDecl();
24850 // AST context is RD's ParentASTContext().
24851 ASTContext &Ctx = RD->getParentASTContext();
24852 // DeclContext is RD's DeclContext.
24853 DeclContext *DCT = const_cast<DeclContext *>(RD->getDeclContext());
24854
24855 // Create implicit default mapper for "RD".
24856 DeclarationName MapperId;
24857 auto &DeclNames = Ctx.DeclarationNames;
24858 MapperId = DeclNames.getIdentifier(ID: &Ctx.Idents.get(Name: "default"));
24859 auto *DMD = OMPDeclareMapperDecl::Create(C&: Ctx, DC: DCT, L: SourceLocation(), Name: MapperId,
24860 T: BaseType, VarName: MapperId, Clauses: Maps, PrevDeclInScope: nullptr);
24861 Scope *Scope = S.getScopeForContext(Ctx: DCT);
24862 if (Scope)
24863 S.PushOnScopeChains(D: DMD, S: Scope, /*AddToContext=*/false);
24864 DCT->addDecl(D: DMD);
24865 DMD->setAccess(clang::AS_none);
24866 auto *VD = cast<DeclRefExpr>(Val: MapperVarRef)->getDecl();
24867 VD->setDeclContext(DMD);
24868 VD->setLexicalDeclContext(DMD);
24869 DMD->addDecl(D: VD);
24870 DMD->setMapperVarRef(MapperVarRef);
24871 FieldDecl *FD = *RD->field_begin();
24872 // create mapper refence.
24873 return DeclRefExpr::Create(Context: Ctx, QualifierLoc: NestedNameSpecifierLoc{}, TemplateKWLoc: FD->getLocation(),
24874 D: DMD, RefersToEnclosingVariableOrCapture: false, NameLoc: SourceLocation(), T: BaseType, VK: VK_LValue);
24875}
24876
24877// Look up the user-defined mapper given the mapper name and mapper type,
24878// return true if found one.
24879static bool hasUserDefinedMapper(Sema &SemaRef, Scope *S,
24880 CXXScopeSpec &MapperIdScopeSpec,
24881 const DeclarationNameInfo &MapperId,
24882 QualType Type) {
24883 // Find all user-defined mappers with the given MapperId.
24884 SmallVector<UnresolvedSet<8>, 4> Lookups;
24885 LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName);
24886 Lookup.suppressDiagnostics();
24887 while (S && SemaRef.LookupParsedName(R&: Lookup, S, SS: &MapperIdScopeSpec,
24888 /*ObjectType=*/QualType())) {
24889 NamedDecl *D = Lookup.getRepresentativeDecl();
24890 while (S && !S->isDeclScope(D))
24891 S = S->getParent();
24892 if (S)
24893 S = S->getParent();
24894 Lookups.emplace_back();
24895 Lookups.back().append(I: Lookup.begin(), E: Lookup.end());
24896 Lookup.clear();
24897 }
24898 if (SemaRef.CurContext->isDependentContext() || Type->isDependentType() ||
24899 Type->isInstantiationDependentType() ||
24900 Type->containsUnexpandedParameterPack() ||
24901 filterLookupForUDReductionAndMapper<bool>(Lookups, Gen: [](ValueDecl *D) {
24902 return !D->isInvalidDecl() &&
24903 (D->getType()->isDependentType() ||
24904 D->getType()->isInstantiationDependentType() ||
24905 D->getType()->containsUnexpandedParameterPack());
24906 }))
24907 return false;
24908 // Perform argument dependent lookup.
24909 SourceLocation Loc = MapperId.getLoc();
24910 if (SemaRef.getLangOpts().CPlusPlus && !MapperIdScopeSpec.isSet())
24911 argumentDependentLookup(SemaRef, Id: MapperId, Loc, Ty: Type, Lookups);
24912 if (filterLookupForUDReductionAndMapper<ValueDecl *>(
24913 Lookups, Gen: [&SemaRef, Type](ValueDecl *D) -> ValueDecl * {
24914 if (!D->isInvalidDecl() &&
24915 SemaRef.Context.hasSameType(T1: D->getType(), T2: Type))
24916 return D;
24917 return nullptr;
24918 }))
24919 return true;
24920 // Find the first user-defined mapper with a type derived from the desired
24921 // type.
24922 auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>(
24923 Lookups, Gen: [&SemaRef, Type, Loc](ValueDecl *D) -> ValueDecl * {
24924 if (!D->isInvalidDecl() &&
24925 SemaRef.IsDerivedFrom(Loc, Derived: Type, Base: D->getType()) &&
24926 !Type.isMoreQualifiedThan(other: D->getType(), Ctx: SemaRef.getASTContext()))
24927 return D;
24928 return nullptr;
24929 });
24930 if (!VD)
24931 return false;
24932 CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
24933 /*DetectVirtual=*/false);
24934 if (SemaRef.IsDerivedFrom(Loc, Derived: Type, Base: VD->getType(), Paths)) {
24935 bool IsAmbiguous = !Paths.isAmbiguous(
24936 BaseType: SemaRef.Context.getCanonicalType(T: VD->getType().getUnqualifiedType()));
24937 if (IsAmbiguous)
24938 return false;
24939 if (SemaRef.CheckBaseClassAccess(AccessLoc: Loc, Base: VD->getType(), Derived: Type, Path: Paths.front(),
24940 /*DiagID=*/0) != Sema::AR_inaccessible)
24941 return true;
24942 }
24943 return false;
24944}
24945
24946static bool isImplicitMapperNeeded(Sema &S, DSAStackTy *Stack,
24947 QualType CanonType, const Expr *E) {
24948
24949 // DFS over data members in structures/classes.
24950 SmallVector<std::pair<QualType, FieldDecl *>, 4> Types(1,
24951 {CanonType, nullptr});
24952 llvm::DenseMap<const Type *, bool> Visited;
24953 SmallVector<std::pair<FieldDecl *, unsigned>, 4> ParentChain(1, {nullptr, 1});
24954 while (!Types.empty()) {
24955 auto [BaseType, CurFD] = Types.pop_back_val();
24956 while (ParentChain.back().second == 0)
24957 ParentChain.pop_back();
24958 --ParentChain.back().second;
24959 if (BaseType.isNull())
24960 continue;
24961 // Only structs/classes are allowed to have mappers.
24962 const RecordDecl *RD = BaseType.getCanonicalType()->getAsRecordDecl();
24963 if (!RD)
24964 continue;
24965 auto It = Visited.find(Val: BaseType.getTypePtr());
24966 if (It == Visited.end()) {
24967 // Try to find the associated user-defined mapper.
24968 CXXScopeSpec MapperIdScopeSpec;
24969 DeclarationNameInfo DefaultMapperId;
24970 DefaultMapperId.setName(S.Context.DeclarationNames.getIdentifier(
24971 ID: &S.Context.Idents.get(Name: "default")));
24972 DefaultMapperId.setLoc(E->getExprLoc());
24973 bool HasUDMapper =
24974 hasUserDefinedMapper(SemaRef&: S, S: Stack->getCurScope(), MapperIdScopeSpec,
24975 MapperId: DefaultMapperId, Type: BaseType);
24976 It = Visited.try_emplace(Key: BaseType.getTypePtr(), Args&: HasUDMapper).first;
24977 }
24978 // Found default mapper.
24979 if (It->second)
24980 return true;
24981 // Check for the "default" mapper for data members.
24982 bool FirstIter = true;
24983 for (FieldDecl *FD : RD->fields()) {
24984 if (!FD)
24985 continue;
24986 QualType FieldTy = FD->getType();
24987 if (FieldTy.isNull() ||
24988 !(FieldTy->isStructureOrClassType() || FieldTy->isUnionType()))
24989 continue;
24990 if (FirstIter) {
24991 FirstIter = false;
24992 ParentChain.emplace_back(Args&: CurFD, Args: 1);
24993 } else {
24994 ++ParentChain.back().second;
24995 }
24996 Types.emplace_back(Args&: FieldTy, Args&: FD);
24997 }
24998 }
24999 return false;
25000}
25001
25002// Check the validity of the provided variable list for the provided clause kind
25003// \a CKind. In the check process the valid expressions, mappable expression
25004// components, variables, and user-defined mappers are extracted and used to
25005// fill \a ProcessedVarList, \a VarComponents, \a VarBaseDeclarations, and \a
25006// UDMapperList in MVLI. \a MapType, \a IsMapTypeImplicit, \a MapperIdScopeSpec,
25007// and \a MapperId are expected to be valid if the clause kind is 'map'.
25008static void checkMappableExpressionList(
25009 Sema &SemaRef, DSAStackTy *DSAS, OpenMPClauseKind CKind,
25010 MappableVarListInfo &MVLI, SourceLocation StartLoc,
25011 CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo MapperId,
25012 ArrayRef<Expr *> UnresolvedMappers,
25013 OpenMPMapClauseKind MapType = OMPC_MAP_unknown,
25014 ArrayRef<OpenMPMapModifierKind> Modifiers = {},
25015 bool IsMapTypeImplicit = false, bool NoDiagnose = false) {
25016 // We only expect mappable expressions in 'to', 'from', 'map', and
25017 // 'use_device_addr' clauses.
25018 assert((CKind == OMPC_map || CKind == OMPC_to || CKind == OMPC_from ||
25019 CKind == OMPC_use_device_addr) &&
25020 "Unexpected clause kind with mappable expressions!");
25021 llvm::omp::Version OMPVersion = SemaRef.getLangOpts().getOpenMPVersion();
25022
25023 // If the identifier of user-defined mapper is not specified, it is "default".
25024 // We do not change the actual name in this clause to distinguish whether a
25025 // mapper is specified explicitly, i.e., it is not explicitly specified when
25026 // MapperId.getName() is empty.
25027 if (!MapperId.getName() || MapperId.getName().isEmpty()) {
25028 auto &DeclNames = SemaRef.getASTContext().DeclarationNames;
25029 MapperId.setName(DeclNames.getIdentifier(
25030 ID: &SemaRef.getASTContext().Idents.get(Name: "default")));
25031 MapperId.setLoc(StartLoc);
25032 }
25033
25034 // Iterators to find the current unresolved mapper expression.
25035 auto UMIt = UnresolvedMappers.begin(), UMEnd = UnresolvedMappers.end();
25036 bool UpdateUMIt = false;
25037 Expr *UnresolvedMapper = nullptr;
25038
25039 bool HasHoldModifier =
25040 llvm::is_contained(Range&: Modifiers, Element: OMPC_MAP_MODIFIER_ompx_hold);
25041
25042 // Keep track of the mappable components and base declarations in this clause.
25043 // Each entry in the list is going to have a list of components associated. We
25044 // record each set of the components so that we can build the clause later on.
25045 // In the end we should have the same amount of declarations and component
25046 // lists.
25047
25048 for (Expr *RE : MVLI.VarList) {
25049 assert(RE && "Null expr in omp to/from/map clause");
25050 SourceLocation ELoc = RE->getExprLoc();
25051
25052 // Find the current unresolved mapper expression.
25053 if (UpdateUMIt && UMIt != UMEnd) {
25054 UMIt++;
25055 assert(
25056 UMIt != UMEnd &&
25057 "Expect the size of UnresolvedMappers to match with that of VarList");
25058 }
25059 UpdateUMIt = true;
25060 if (UMIt != UMEnd)
25061 UnresolvedMapper = *UMIt;
25062
25063 const Expr *VE = RE->IgnoreParenLValueCasts();
25064
25065 if (VE->isValueDependent() || VE->isTypeDependent() ||
25066 VE->isInstantiationDependent() ||
25067 VE->containsUnexpandedParameterPack()) {
25068 // Try to find the associated user-defined mapper.
25069 ExprResult ER = buildUserDefinedMapperRef(
25070 SemaRef, S: DSAS->getCurScope(), MapperIdScopeSpec, MapperId,
25071 Type: VE->getType().getCanonicalType(), UnresolvedMapper, ItemLoc: ELoc);
25072 if (ER.isInvalid())
25073 continue;
25074 MVLI.UDMapperList.push_back(Elt: ER.get());
25075 // We can only analyze this information once the missing information is
25076 // resolved.
25077 MVLI.ProcessedVarList.push_back(Elt: RE);
25078 continue;
25079 }
25080
25081 Expr *SimpleExpr = RE->IgnoreParenCasts();
25082 if (!RE->isLValue()) {
25083 if (SemaRef.getLangOpts().OpenMP < 50) {
25084 SemaRef.Diag(
25085 Loc: ELoc, DiagID: diag::err_omp_expected_named_var_member_or_array_expression)
25086 << RE->getSourceRange();
25087 } else {
25088 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_non_lvalue_in_map_or_motion_clauses)
25089 << getOpenMPClauseNameForDiag(C: CKind) << RE->getSourceRange();
25090 }
25091 continue;
25092 }
25093
25094 // Check for unsupported structured bindings early.
25095 if (!NoDiagnose) {
25096 if (const auto *DRE = dyn_cast<DeclRefExpr>(Val: SimpleExpr)) {
25097 const DecompositionDecl *DD = nullptr;
25098 const BindingDecl *BD = nullptr;
25099 if (const auto *B = dyn_cast<BindingDecl>(Val: DRE->getDecl())) {
25100 BD = B;
25101 DD = cast<DecompositionDecl>(Val: B->getDecomposedDecl());
25102 } else if (const auto *D =
25103 dyn_cast<DecompositionDecl>(Val: DRE->getDecl())) {
25104 DD = D;
25105 }
25106 if (DD) {
25107 if (BD && BD->getHoldingVar()) {
25108 SemaRef.Diag(Loc: ELoc,
25109 DiagID: diag::err_omp_unsupported_structured_binding_init)
25110 << 4;
25111 continue;
25112 }
25113 if (!getOriginalVarOrDiagnose(S&: SemaRef, DD, Loc: ELoc))
25114 continue;
25115 }
25116 }
25117 }
25118 OMPClauseMappableExprCommon::MappableExprComponentList CurComponents;
25119 ValueDecl *CurDeclaration = nullptr;
25120
25121 // Obtain the array or member expression bases if required. Also, fill the
25122 // components array with all the components identified in the process.
25123 const Expr *BE =
25124 checkMapClauseExpressionBase(SemaRef, E: SimpleExpr, CurComponents, CKind,
25125 DKind: DSAS->getCurrentDirective(), NoDiagnose);
25126 if (!BE)
25127 continue;
25128
25129 assert(!CurComponents.empty() &&
25130 "Invalid mappable expression information.");
25131
25132 if (const auto *TE = dyn_cast<CXXThisExpr>(Val: BE)) {
25133 // Add store "this" pointer to class in DSAStackTy for future checking
25134 DSAS->addMappedClassesQualTypes(QT: TE->getType());
25135 // Try to find the associated user-defined mapper.
25136 ExprResult ER = buildUserDefinedMapperRef(
25137 SemaRef, S: DSAS->getCurScope(), MapperIdScopeSpec, MapperId,
25138 Type: VE->getType().getCanonicalType(), UnresolvedMapper, ItemLoc: ELoc);
25139 if (ER.isInvalid())
25140 continue;
25141 MVLI.UDMapperList.push_back(Elt: ER.get());
25142 // Skip restriction checking for variable or field declarations
25143 MVLI.ProcessedVarList.push_back(Elt: RE);
25144 MVLI.VarComponents.resize(N: MVLI.VarComponents.size() + 1);
25145 MVLI.VarComponents.back().append(in_start: CurComponents.begin(),
25146 in_end: CurComponents.end());
25147 MVLI.VarBaseDeclarations.push_back(Elt: nullptr);
25148 continue;
25149 }
25150
25151 // For the following checks, we rely on the base declaration which is
25152 // expected to be associated with the last component. The declaration is
25153 // expected to be a variable or a field (if 'this' is being mapped).
25154 CurDeclaration = CurComponents.back().getAssociatedDeclaration();
25155 assert(CurDeclaration && "Null decl on map clause.");
25156 assert(
25157 CurDeclaration->isCanonicalDecl() &&
25158 "Expecting components to have associated only canonical declarations.");
25159
25160 auto *VD = dyn_cast<VarDecl>(Val: CurDeclaration);
25161 const auto *FD = dyn_cast<FieldDecl>(Val: CurDeclaration);
25162
25163 assert((VD || FD) && "Only variables or fields are expected here!");
25164 (void)FD;
25165
25166 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.10]
25167 // threadprivate variables cannot appear in a map clause.
25168 // OpenMP 4.5 [2.10.5, target update Construct]
25169 // threadprivate variables cannot appear in a from clause.
25170 if (VD && DSAS->isThreadPrivate(D: VD)) {
25171 if (NoDiagnose)
25172 continue;
25173 DSAStackTy::DSAVarData DVar = DSAS->getTopDSA(D: VD, /*FromParent=*/false);
25174 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_threadprivate_in_clause)
25175 << getOpenMPClauseNameForDiag(C: CKind);
25176 reportOriginalDsa(SemaRef, Stack: DSAS, D: VD, DVar);
25177 continue;
25178 }
25179
25180 // OpenMP 6.0 [7.9.6, map Clause, Restrictions, p. 386]
25181 // A device-local variable must not appear as a list item in a map clause.
25182 if (VD && CKind == OMPC_map) {
25183 if (std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
25184 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) {
25185 if (*Res == OMPDeclareTargetDeclAttr::MT_Local) {
25186 if (NoDiagnose)
25187 continue;
25188 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_device_local_in_clause)
25189 << VD << getOpenMPClauseNameForDiag(C: CKind);
25190 continue;
25191 }
25192 }
25193 }
25194
25195 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.9]
25196 // A list item cannot appear in both a map clause and a data-sharing
25197 // attribute clause on the same construct.
25198
25199 // Check conflicts with other map clause expressions. We check the conflicts
25200 // with the current construct separately from the enclosing data
25201 // environment, because the restrictions are different. We only have to
25202 // check conflicts across regions for the map clauses.
25203 if (checkMapConflicts(SemaRef, DSAS, VD: CurDeclaration, E: SimpleExpr,
25204 /*CurrentRegionOnly=*/true, CurComponents, CKind))
25205 break;
25206 if (CKind == OMPC_map &&
25207 (SemaRef.getLangOpts().OpenMP <= 45 || StartLoc.isValid()) &&
25208 checkMapConflicts(SemaRef, DSAS, VD: CurDeclaration, E: SimpleExpr,
25209 /*CurrentRegionOnly=*/false, CurComponents, CKind))
25210 break;
25211
25212 // OpenMP 4.5 [2.10.5, target update Construct]
25213 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
25214 // If the type of a list item is a reference to a type T then the type will
25215 // be considered to be T for all purposes of this clause.
25216 auto I = llvm::find_if(
25217 Range&: CurComponents,
25218 P: [](const OMPClauseMappableExprCommon::MappableComponent &MC) {
25219 return MC.getAssociatedDeclaration();
25220 });
25221 assert(I != CurComponents.end() && "Null decl on map clause.");
25222 (void)I;
25223 QualType Type;
25224 auto *ASE = dyn_cast<ArraySubscriptExpr>(Val: VE->IgnoreParens());
25225 auto *OASE = dyn_cast<ArraySectionExpr>(Val: VE->IgnoreParens());
25226 auto *OAShE = dyn_cast<OMPArrayShapingExpr>(Val: VE->IgnoreParens());
25227 if (ASE) {
25228 Type = ASE->getType().getNonReferenceType();
25229 } else if (OASE) {
25230 QualType BaseType =
25231 ArraySectionExpr::getBaseOriginalType(Base: OASE->getBase());
25232 if (const auto *ATy = BaseType->getAsArrayTypeUnsafe())
25233 Type = ATy->getElementType();
25234 else
25235 Type = BaseType->getPointeeType();
25236 Type = Type.getNonReferenceType();
25237 } else if (OAShE) {
25238 Type = OAShE->getBase()->getType()->getPointeeType();
25239 } else {
25240 Type = VE->getType();
25241 }
25242
25243 // OpenMP 4.5 [2.10.5, target update Construct, Restrictions, p.4]
25244 // A list item in a to or from clause must have a mappable type.
25245 // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.9]
25246 // A list item must have a mappable type.
25247 if (!checkTypeMappable(SL: VE->getExprLoc(), SR: VE->getSourceRange(), SemaRef,
25248 Stack: DSAS, QTy: Type, /*FullCheck=*/true))
25249 continue;
25250
25251 if (CKind == OMPC_map) {
25252 // target enter data
25253 // OpenMP [2.10.2, Restrictions, p. 99]
25254 // A map-type must be specified in all map clauses and must be either
25255 // to or alloc. Starting with OpenMP 5.2 the default map type is `to` if
25256 // no map type is present.
25257 OpenMPDirectiveKind DKind = DSAS->getCurrentDirective();
25258 if (DKind == OMPD_target_enter_data &&
25259 !(MapType == OMPC_MAP_to || MapType == OMPC_MAP_alloc ||
25260 SemaRef.getLangOpts().OpenMP >= 52)) {
25261 SemaRef.Diag(Loc: StartLoc, DiagID: diag::err_omp_invalid_map_type_for_directive)
25262 << (IsMapTypeImplicit ? 1 : 0)
25263 << getOpenMPSimpleClauseTypeName(Kind: OMPC_map, Type: MapType)
25264 << getOpenMPDirectiveName(D: DKind, V: OMPVersion);
25265 continue;
25266 }
25267
25268 // target exit_data
25269 // OpenMP [2.10.3, Restrictions, p. 102]
25270 // A map-type must be specified in all map clauses and must be either
25271 // from, release, or delete. Starting with OpenMP 5.2 the default map
25272 // type is `from` if no map type is present.
25273 if (DKind == OMPD_target_exit_data &&
25274 !(MapType == OMPC_MAP_from || MapType == OMPC_MAP_release ||
25275 MapType == OMPC_MAP_delete || SemaRef.getLangOpts().OpenMP >= 52)) {
25276 SemaRef.Diag(Loc: StartLoc, DiagID: diag::err_omp_invalid_map_type_for_directive)
25277 << (IsMapTypeImplicit ? 1 : 0)
25278 << getOpenMPSimpleClauseTypeName(Kind: OMPC_map, Type: MapType)
25279 << getOpenMPDirectiveName(D: DKind, V: OMPVersion);
25280 continue;
25281 }
25282
25283 // The 'ompx_hold' modifier is specifically intended to be used on a
25284 // 'target' or 'target data' directive to prevent data from being unmapped
25285 // during the associated statement. It is not permitted on a 'target
25286 // enter data' or 'target exit data' directive, which have no associated
25287 // statement.
25288 if ((DKind == OMPD_target_enter_data || DKind == OMPD_target_exit_data) &&
25289 HasHoldModifier) {
25290 SemaRef.Diag(Loc: StartLoc,
25291 DiagID: diag::err_omp_invalid_map_type_modifier_for_directive)
25292 << getOpenMPSimpleClauseTypeName(Kind: OMPC_map,
25293 Type: OMPC_MAP_MODIFIER_ompx_hold)
25294 << getOpenMPDirectiveName(D: DKind, V: OMPVersion);
25295 continue;
25296 }
25297
25298 // target, target data
25299 // OpenMP 5.0 [2.12.2, Restrictions, p. 163]
25300 // OpenMP 5.0 [2.12.5, Restrictions, p. 174]
25301 // A map-type in a map clause must be to, from, tofrom or alloc
25302 if ((DKind == OMPD_target_data ||
25303 isOpenMPTargetExecutionDirective(DKind)) &&
25304 !(MapType == OMPC_MAP_to || MapType == OMPC_MAP_from ||
25305 MapType == OMPC_MAP_tofrom || MapType == OMPC_MAP_alloc)) {
25306 SemaRef.Diag(Loc: StartLoc, DiagID: diag::err_omp_invalid_map_type_for_directive)
25307 << (IsMapTypeImplicit ? 1 : 0)
25308 << getOpenMPSimpleClauseTypeName(Kind: OMPC_map, Type: MapType)
25309 << getOpenMPDirectiveName(D: DKind, V: OMPVersion);
25310 continue;
25311 }
25312
25313 // OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
25314 // A list item cannot appear in both a map clause and a data-sharing
25315 // attribute clause on the same construct
25316 //
25317 // OpenMP 5.0 [2.19.7.1, Restrictions, p.7]
25318 // A list item cannot appear in both a map clause and a data-sharing
25319 // attribute clause on the same construct unless the construct is a
25320 // combined construct.
25321 if (VD && ((SemaRef.LangOpts.OpenMP <= 45 &&
25322 isOpenMPTargetExecutionDirective(DKind)) ||
25323 DKind == OMPD_target)) {
25324 DSAStackTy::DSAVarData DVar = DSAS->getTopDSA(D: VD, /*FromParent=*/false);
25325 if (isOpenMPPrivate(Kind: DVar.CKind)) {
25326 SemaRef.Diag(Loc: ELoc, DiagID: diag::err_omp_variable_in_given_clause_and_dsa)
25327 << getOpenMPClauseNameForDiag(C: DVar.CKind)
25328 << getOpenMPClauseNameForDiag(C: OMPC_map)
25329 << getOpenMPDirectiveName(D: DSAS->getCurrentDirective(),
25330 V: OMPVersion);
25331 reportOriginalDsa(SemaRef, Stack: DSAS, D: CurDeclaration, DVar);
25332 continue;
25333 }
25334 }
25335 }
25336
25337 // Try to find the associated user-defined mapper.
25338 ExprResult ER = buildUserDefinedMapperRef(
25339 SemaRef, S: DSAS->getCurScope(), MapperIdScopeSpec, MapperId,
25340 Type: Type.getCanonicalType(), UnresolvedMapper, ItemLoc: ELoc);
25341 if (ER.isInvalid())
25342 continue;
25343
25344 // If no user-defined mapper is found, we need to create an implicit one for
25345 // arrays/array-sections on structs that have members that have
25346 // user-defined mappers. This is needed to ensure that the mapper for the
25347 // member is invoked when mapping each element of the array/array-section.
25348 if (!ER.get()) {
25349 QualType BaseType;
25350
25351 if (isa<ArraySectionExpr>(Val: VE)) {
25352 BaseType = VE->getType().getCanonicalType();
25353 if (BaseType->isSpecificBuiltinType(K: BuiltinType::ArraySection)) {
25354 const auto *OASE = cast<ArraySectionExpr>(Val: VE->IgnoreParenImpCasts());
25355 QualType BType =
25356 ArraySectionExpr::getBaseOriginalType(Base: OASE->getBase());
25357 QualType ElemType;
25358 if (const auto *ATy = BType->getAsArrayTypeUnsafe())
25359 ElemType = ATy->getElementType();
25360 else
25361 ElemType = BType->getPointeeType();
25362 BaseType = ElemType.getCanonicalType();
25363 }
25364 } else if (VE->getType()->isArrayType()) {
25365 const ArrayType *AT = VE->getType()->getAsArrayTypeUnsafe();
25366 const QualType ElemType = AT->getElementType();
25367 BaseType = ElemType.getCanonicalType();
25368 }
25369
25370 if (!BaseType.isNull() && BaseType->getAsRecordDecl() &&
25371 isImplicitMapperNeeded(S&: SemaRef, Stack: DSAS, CanonType: BaseType, E: VE)) {
25372 ER = buildImplicitMapper(S&: SemaRef, BaseType, Stack: DSAS);
25373 }
25374 }
25375 MVLI.UDMapperList.push_back(Elt: ER.get());
25376
25377 // Save the current expression.
25378 MVLI.ProcessedVarList.push_back(Elt: RE);
25379
25380 // Store the components in the stack so that they can be used to check
25381 // against other clauses later on.
25382 DSAS->addMappableExpressionComponents(VD: CurDeclaration, Components: CurComponents,
25383 /*WhereFoundClauseKind=*/OMPC_map);
25384
25385 // Save the components and declaration to create the clause. For purposes of
25386 // the clause creation, any component list that has base 'this' uses
25387 // null as base declaration.
25388 MVLI.VarComponents.resize(N: MVLI.VarComponents.size() + 1);
25389 MVLI.VarComponents.back().append(in_start: CurComponents.begin(),
25390 in_end: CurComponents.end());
25391 MVLI.VarBaseDeclarations.push_back(Elt: isa<MemberExpr>(Val: BE) ? nullptr
25392 : CurDeclaration);
25393 }
25394}
25395
25396OMPClause *SemaOpenMP::ActOnOpenMPMapClause(
25397 Expr *IteratorModifier, ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
25398 ArrayRef<SourceLocation> MapTypeModifiersLoc,
25399 CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId,
25400 OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc,
25401 SourceLocation ColonLoc, ArrayRef<Expr *> VarList,
25402 const OMPVarListLocTy &Locs, bool NoDiagnose,
25403 ArrayRef<Expr *> UnresolvedMappers) {
25404 OpenMPMapModifierKind Modifiers[] = {
25405 OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown,
25406 OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown,
25407 OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown,
25408 OMPC_MAP_MODIFIER_unknown};
25409 SourceLocation ModifiersLoc[NumberOfOMPMapClauseModifiers];
25410
25411 if (IteratorModifier && !IteratorModifier->getType()->isSpecificBuiltinType(
25412 K: BuiltinType::OMPIterator))
25413 Diag(Loc: IteratorModifier->getExprLoc(),
25414 DiagID: diag::err_omp_map_modifier_not_iterator);
25415
25416 // Process map-type-modifiers, flag errors for duplicate modifiers.
25417 unsigned Count = 0;
25418 for (unsigned I = 0, E = MapTypeModifiers.size(); I < E; ++I) {
25419 if (MapTypeModifiers[I] != OMPC_MAP_MODIFIER_unknown &&
25420 llvm::is_contained(Range&: Modifiers, Element: MapTypeModifiers[I])) {
25421 Diag(Loc: MapTypeModifiersLoc[I], DiagID: diag::err_omp_duplicate_map_type_modifier);
25422 continue;
25423 }
25424 assert(Count < NumberOfOMPMapClauseModifiers &&
25425 "Modifiers exceed the allowed number of map type modifiers");
25426 Modifiers[Count] = MapTypeModifiers[I];
25427 ModifiersLoc[Count] = MapTypeModifiersLoc[I];
25428 ++Count;
25429 }
25430
25431 MappableVarListInfo MVLI(VarList);
25432 // Per OpenMP 6.0 p299 lines 3-4, a list item with the const specifier and
25433 // no mutable members is ignored for 'from' clauses. A const-qualified
25434 // variable cannot be modified on the device, so copying back to the host
25435 // is unnecessary and potentially unsafe. Strip the FROM component:
25436 // map(tofrom:) -> map(to:), map(from:) -> map(alloc:).
25437 for (auto *E : VarList) {
25438 if ((MapType == OMPC_MAP_from || MapType == OMPC_MAP_tofrom) &&
25439 hasConstQualifiedMappingType(T: E->getType()))
25440 MapType = (MapType == OMPC_MAP_tofrom) ? OMPC_MAP_to : OMPC_MAP_alloc;
25441 }
25442 checkMappableExpressionList(SemaRef, DSAStack, CKind: OMPC_map, MVLI, StartLoc: Locs.StartLoc,
25443 MapperIdScopeSpec, MapperId, UnresolvedMappers,
25444 MapType, Modifiers, IsMapTypeImplicit,
25445 NoDiagnose);
25446
25447 // We need to produce a map clause even if we don't have variables so that
25448 // other diagnostics related with non-existing map clauses are accurate.
25449 return OMPMapClause::Create(
25450 C: getASTContext(), Locs, Vars: MVLI.ProcessedVarList, Declarations: MVLI.VarBaseDeclarations,
25451 ComponentLists: MVLI.VarComponents, UDMapperRefs: MVLI.UDMapperList, IteratorModifier, MapModifiers: Modifiers,
25452 MapModifiersLoc: ModifiersLoc, UDMQualifierLoc: MapperIdScopeSpec.getWithLocInContext(Context&: getASTContext()),
25453 MapperId, Type: MapType, TypeIsImplicit: IsMapTypeImplicit, TypeLoc: MapLoc);
25454}
25455
25456QualType SemaOpenMP::ActOnOpenMPDeclareReductionType(SourceLocation TyLoc,
25457 TypeResult ParsedType) {
25458 assert(ParsedType.isUsable());
25459
25460 QualType ReductionType = SemaRef.GetTypeFromParser(Ty: ParsedType.get());
25461 if (ReductionType.isNull())
25462 return QualType();
25463
25464 // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions, C\C++
25465 // A type name in a declare reduction directive cannot be a function type, an
25466 // array type, a reference type, or a type qualified with const, volatile or
25467 // restrict.
25468 if (ReductionType.hasQualifiers()) {
25469 Diag(Loc: TyLoc, DiagID: diag::err_omp_reduction_wrong_type) << 0;
25470 return QualType();
25471 }
25472
25473 if (ReductionType->isFunctionType()) {
25474 Diag(Loc: TyLoc, DiagID: diag::err_omp_reduction_wrong_type) << 1;
25475 return QualType();
25476 }
25477 if (ReductionType->isReferenceType()) {
25478 Diag(Loc: TyLoc, DiagID: diag::err_omp_reduction_wrong_type) << 2;
25479 return QualType();
25480 }
25481 if (ReductionType->isArrayType()) {
25482 Diag(Loc: TyLoc, DiagID: diag::err_omp_reduction_wrong_type) << 3;
25483 return QualType();
25484 }
25485 return ReductionType;
25486}
25487
25488SemaOpenMP::DeclGroupPtrTy
25489SemaOpenMP::ActOnOpenMPDeclareReductionDirectiveStart(
25490 Scope *S, DeclContext *DC, DeclarationName Name,
25491 ArrayRef<std::pair<QualType, SourceLocation>> ReductionTypes,
25492 AccessSpecifier AS, Decl *PrevDeclInScope) {
25493 SmallVector<Decl *, 8> Decls;
25494 Decls.reserve(N: ReductionTypes.size());
25495
25496 LookupResult Lookup(SemaRef, Name, SourceLocation(),
25497 Sema::LookupOMPReductionName,
25498 SemaRef.forRedeclarationInCurContext());
25499 // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions
25500 // A reduction-identifier may not be re-declared in the current scope for the
25501 // same type or for a type that is compatible according to the base language
25502 // rules.
25503 llvm::DenseMap<QualType, SourceLocation> PreviousRedeclTypes;
25504 OMPDeclareReductionDecl *PrevDRD = nullptr;
25505 bool InCompoundScope = true;
25506 if (S != nullptr) {
25507 // Find previous declaration with the same name not referenced in other
25508 // declarations.
25509 FunctionScopeInfo *ParentFn = SemaRef.getEnclosingFunction();
25510 InCompoundScope =
25511 (ParentFn != nullptr) && !ParentFn->CompoundScopes.empty();
25512 SemaRef.LookupName(R&: Lookup, S);
25513 SemaRef.FilterLookupForScope(R&: Lookup, Ctx: DC, S, /*ConsiderLinkage=*/false,
25514 /*AllowInlineNamespace=*/false);
25515 llvm::DenseMap<OMPDeclareReductionDecl *, bool> UsedAsPrevious;
25516 LookupResult::Filter Filter = Lookup.makeFilter();
25517 while (Filter.hasNext()) {
25518 auto *PrevDecl = cast<OMPDeclareReductionDecl>(Val: Filter.next());
25519 if (InCompoundScope) {
25520 UsedAsPrevious.try_emplace(Key: PrevDecl, Args: false);
25521 if (OMPDeclareReductionDecl *D = PrevDecl->getPrevDeclInScope())
25522 UsedAsPrevious[D] = true;
25523 }
25524 PreviousRedeclTypes[PrevDecl->getType().getCanonicalType()] =
25525 PrevDecl->getLocation();
25526 }
25527 Filter.done();
25528 if (InCompoundScope) {
25529 for (const auto &PrevData : UsedAsPrevious) {
25530 if (!PrevData.second) {
25531 PrevDRD = PrevData.first;
25532 break;
25533 }
25534 }
25535 }
25536 } else if (PrevDeclInScope != nullptr) {
25537 auto *PrevDRDInScope = PrevDRD =
25538 cast<OMPDeclareReductionDecl>(Val: PrevDeclInScope);
25539 do {
25540 PreviousRedeclTypes[PrevDRDInScope->getType().getCanonicalType()] =
25541 PrevDRDInScope->getLocation();
25542 PrevDRDInScope = PrevDRDInScope->getPrevDeclInScope();
25543 } while (PrevDRDInScope != nullptr);
25544 }
25545 for (const auto &TyData : ReductionTypes) {
25546 const auto I = PreviousRedeclTypes.find(Val: TyData.first.getCanonicalType());
25547 bool Invalid = false;
25548 if (I != PreviousRedeclTypes.end()) {
25549 Diag(Loc: TyData.second, DiagID: diag::err_omp_declare_reduction_redefinition)
25550 << TyData.first;
25551 Diag(Loc: I->second, DiagID: diag::note_previous_definition);
25552 Invalid = true;
25553 }
25554 PreviousRedeclTypes[TyData.first.getCanonicalType()] = TyData.second;
25555 auto *DRD = OMPDeclareReductionDecl::Create(
25556 C&: getASTContext(), DC, L: TyData.second, Name, T: TyData.first, PrevDeclInScope: PrevDRD);
25557 DC->addDecl(D: DRD);
25558 DRD->setAccess(AS);
25559 Decls.push_back(Elt: DRD);
25560 if (Invalid)
25561 DRD->setInvalidDecl();
25562 else
25563 PrevDRD = DRD;
25564 }
25565
25566 return DeclGroupPtrTy::make(
25567 P: DeclGroupRef::Create(C&: getASTContext(), Decls: Decls.begin(), NumDecls: Decls.size()));
25568}
25569
25570void SemaOpenMP::ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D) {
25571 auto *DRD = cast<OMPDeclareReductionDecl>(Val: D);
25572
25573 // Enter new function scope.
25574 SemaRef.PushFunctionScope();
25575 SemaRef.setFunctionHasBranchProtectedScope();
25576 SemaRef.getCurFunction()->setHasOMPDeclareReductionCombiner();
25577
25578 if (S != nullptr)
25579 SemaRef.PushDeclContext(S, DC: DRD);
25580 else
25581 SemaRef.CurContext = DRD;
25582
25583 SemaRef.PushExpressionEvaluationContext(
25584 NewContext: Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
25585
25586 QualType ReductionType = DRD->getType();
25587 // Create 'T* omp_parm;T omp_in;'. All references to 'omp_in' will
25588 // be replaced by '*omp_parm' during codegen. This required because 'omp_in'
25589 // uses semantics of argument handles by value, but it should be passed by
25590 // reference. C lang does not support references, so pass all parameters as
25591 // pointers.
25592 // Create 'T omp_in;' variable.
25593 VarDecl *OmpInParm =
25594 buildVarDecl(SemaRef, Loc: D->getLocation(), Type: ReductionType, Name: "omp_in");
25595 // Create 'T* omp_parm;T omp_out;'. All references to 'omp_out' will
25596 // be replaced by '*omp_parm' during codegen. This required because 'omp_out'
25597 // uses semantics of argument handles by value, but it should be passed by
25598 // reference. C lang does not support references, so pass all parameters as
25599 // pointers.
25600 // Create 'T omp_out;' variable.
25601 VarDecl *OmpOutParm =
25602 buildVarDecl(SemaRef, Loc: D->getLocation(), Type: ReductionType, Name: "omp_out");
25603 if (S != nullptr) {
25604 SemaRef.PushOnScopeChains(D: OmpInParm, S);
25605 SemaRef.PushOnScopeChains(D: OmpOutParm, S);
25606 } else {
25607 DRD->addDecl(D: OmpInParm);
25608 DRD->addDecl(D: OmpOutParm);
25609 }
25610 Expr *InE =
25611 ::buildDeclRefExpr(S&: SemaRef, D: OmpInParm, Ty: ReductionType, Loc: D->getLocation());
25612 Expr *OutE =
25613 ::buildDeclRefExpr(S&: SemaRef, D: OmpOutParm, Ty: ReductionType, Loc: D->getLocation());
25614 DRD->setCombinerData(InE, OutE);
25615}
25616
25617void SemaOpenMP::ActOnOpenMPDeclareReductionCombinerEnd(Decl *D,
25618 Expr *Combiner) {
25619 auto *DRD = cast<OMPDeclareReductionDecl>(Val: D);
25620 SemaRef.DiscardCleanupsInEvaluationContext();
25621 SemaRef.PopExpressionEvaluationContext();
25622
25623 SemaRef.PopDeclContext();
25624 SemaRef.PopFunctionScopeInfo();
25625
25626 if (Combiner != nullptr)
25627 DRD->setCombiner(Combiner);
25628 else
25629 DRD->setInvalidDecl();
25630}
25631
25632VarDecl *SemaOpenMP::ActOnOpenMPDeclareReductionInitializerStart(Scope *S,
25633 Decl *D) {
25634 auto *DRD = cast<OMPDeclareReductionDecl>(Val: D);
25635
25636 // Enter new function scope.
25637 SemaRef.PushFunctionScope();
25638 SemaRef.setFunctionHasBranchProtectedScope();
25639
25640 if (S != nullptr)
25641 SemaRef.PushDeclContext(S, DC: DRD);
25642 else
25643 SemaRef.CurContext = DRD;
25644
25645 SemaRef.PushExpressionEvaluationContext(
25646 NewContext: Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
25647
25648 QualType ReductionType = DRD->getType();
25649 // Create 'T* omp_parm;T omp_priv;'. All references to 'omp_priv' will
25650 // be replaced by '*omp_parm' during codegen. This required because 'omp_priv'
25651 // uses semantics of argument handles by value, but it should be passed by
25652 // reference. C lang does not support references, so pass all parameters as
25653 // pointers.
25654 // Create 'T omp_priv;' variable.
25655 VarDecl *OmpPrivParm =
25656 buildVarDecl(SemaRef, Loc: D->getLocation(), Type: ReductionType, Name: "omp_priv");
25657 // Create 'T* omp_parm;T omp_orig;'. All references to 'omp_orig' will
25658 // be replaced by '*omp_parm' during codegen. This required because 'omp_orig'
25659 // uses semantics of argument handles by value, but it should be passed by
25660 // reference. C lang does not support references, so pass all parameters as
25661 // pointers.
25662 // Create 'T omp_orig;' variable.
25663 VarDecl *OmpOrigParm =
25664 buildVarDecl(SemaRef, Loc: D->getLocation(), Type: ReductionType, Name: "omp_orig");
25665 if (S != nullptr) {
25666 SemaRef.PushOnScopeChains(D: OmpPrivParm, S);
25667 SemaRef.PushOnScopeChains(D: OmpOrigParm, S);
25668 } else {
25669 DRD->addDecl(D: OmpPrivParm);
25670 DRD->addDecl(D: OmpOrigParm);
25671 }
25672 Expr *OrigE =
25673 ::buildDeclRefExpr(S&: SemaRef, D: OmpOrigParm, Ty: ReductionType, Loc: D->getLocation());
25674 Expr *PrivE =
25675 ::buildDeclRefExpr(S&: SemaRef, D: OmpPrivParm, Ty: ReductionType, Loc: D->getLocation());
25676 DRD->setInitializerData(OrigE, PrivE);
25677 return OmpPrivParm;
25678}
25679
25680void SemaOpenMP::ActOnOpenMPDeclareReductionInitializerEnd(
25681 Decl *D, Expr *Initializer, VarDecl *OmpPrivParm) {
25682 auto *DRD = cast<OMPDeclareReductionDecl>(Val: D);
25683
25684 // Ensure OmpPrivParm is default-constructed before the user initializer runs
25685 // (required for class types with non-trivial default constructors).
25686 if (Initializer && !DRD->getDeclContext()->isDependentContext()) {
25687 QualType ReductionType = DRD->getType();
25688 if (CXXRecordDecl *RD = ReductionType->getAsCXXRecordDecl()) {
25689 if (!RD->hasTrivialDefaultConstructor())
25690 SemaRef.ActOnUninitializedDecl(dcl: OmpPrivParm);
25691 }
25692 }
25693
25694 SemaRef.DiscardCleanupsInEvaluationContext();
25695 SemaRef.PopExpressionEvaluationContext();
25696
25697 SemaRef.PopDeclContext();
25698 SemaRef.PopFunctionScopeInfo();
25699
25700 if (Initializer != nullptr) {
25701 DRD->setInitializer(E: Initializer, IK: OMPDeclareReductionInitKind::Call);
25702 } else if (OmpPrivParm->hasInit()) {
25703 DRD->setInitializer(E: OmpPrivParm->getInit(),
25704 IK: OmpPrivParm->isDirectInit()
25705 ? OMPDeclareReductionInitKind::Direct
25706 : OMPDeclareReductionInitKind::Copy);
25707 } else {
25708 DRD->setInvalidDecl();
25709 }
25710}
25711
25712SemaOpenMP::DeclGroupPtrTy SemaOpenMP::ActOnOpenMPDeclareReductionDirectiveEnd(
25713 Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid) {
25714 for (Decl *D : DeclReductions.get()) {
25715 if (IsValid) {
25716 if (S)
25717 SemaRef.PushOnScopeChains(D: cast<OMPDeclareReductionDecl>(Val: D), S,
25718 /*AddToContext=*/false);
25719 } else {
25720 D->setInvalidDecl();
25721 }
25722 }
25723 return DeclReductions;
25724}
25725
25726TypeResult SemaOpenMP::ActOnOpenMPDeclareMapperVarDecl(Scope *S,
25727 Declarator &D) {
25728 TypeSourceInfo *TInfo = SemaRef.GetTypeForDeclarator(D);
25729 QualType T = TInfo->getType();
25730 if (D.isInvalidType())
25731 return true;
25732
25733 if (getLangOpts().CPlusPlus) {
25734 // Check that there are no default arguments (C++ only).
25735 SemaRef.CheckExtraCXXDefaultArguments(D);
25736 }
25737
25738 return SemaRef.CreateParsedType(T, TInfo);
25739}
25740
25741QualType SemaOpenMP::ActOnOpenMPDeclareMapperType(SourceLocation TyLoc,
25742 TypeResult ParsedType) {
25743 assert(ParsedType.isUsable() && "Expect usable parsed mapper type");
25744
25745 QualType MapperType = SemaRef.GetTypeFromParser(Ty: ParsedType.get());
25746 assert(!MapperType.isNull() && "Expect valid mapper type");
25747
25748 // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions
25749 // The type must be of struct, union or class type in C and C++
25750 if (!MapperType->isStructureOrClassType() && !MapperType->isUnionType()) {
25751 Diag(Loc: TyLoc, DiagID: diag::err_omp_mapper_wrong_type);
25752 return QualType();
25753 }
25754 return MapperType;
25755}
25756
25757SemaOpenMP::DeclGroupPtrTy SemaOpenMP::ActOnOpenMPDeclareMapperDirective(
25758 Scope *S, DeclContext *DC, DeclarationName Name, QualType MapperType,
25759 SourceLocation StartLoc, DeclarationName VN, AccessSpecifier AS,
25760 Expr *MapperVarRef, ArrayRef<OMPClause *> Clauses, Decl *PrevDeclInScope) {
25761 LookupResult Lookup(SemaRef, Name, SourceLocation(),
25762 Sema::LookupOMPMapperName,
25763 SemaRef.forRedeclarationInCurContext());
25764 // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions
25765 // A mapper-identifier may not be redeclared in the current scope for the
25766 // same type or for a type that is compatible according to the base language
25767 // rules.
25768 llvm::DenseMap<QualType, SourceLocation> PreviousRedeclTypes;
25769 OMPDeclareMapperDecl *PrevDMD = nullptr;
25770 bool InCompoundScope = true;
25771 if (S != nullptr) {
25772 // Find previous declaration with the same name not referenced in other
25773 // declarations.
25774 FunctionScopeInfo *ParentFn = SemaRef.getEnclosingFunction();
25775 InCompoundScope =
25776 (ParentFn != nullptr) && !ParentFn->CompoundScopes.empty();
25777 SemaRef.LookupName(R&: Lookup, S);
25778 SemaRef.FilterLookupForScope(R&: Lookup, Ctx: DC, S, /*ConsiderLinkage=*/false,
25779 /*AllowInlineNamespace=*/false);
25780 llvm::DenseMap<OMPDeclareMapperDecl *, bool> UsedAsPrevious;
25781 LookupResult::Filter Filter = Lookup.makeFilter();
25782 while (Filter.hasNext()) {
25783 auto *PrevDecl = cast<OMPDeclareMapperDecl>(Val: Filter.next());
25784 if (InCompoundScope) {
25785 UsedAsPrevious.try_emplace(Key: PrevDecl, Args: false);
25786 if (OMPDeclareMapperDecl *D = PrevDecl->getPrevDeclInScope())
25787 UsedAsPrevious[D] = true;
25788 }
25789 PreviousRedeclTypes[PrevDecl->getType().getCanonicalType()] =
25790 PrevDecl->getLocation();
25791 }
25792 Filter.done();
25793 if (InCompoundScope) {
25794 for (const auto &PrevData : UsedAsPrevious) {
25795 if (!PrevData.second) {
25796 PrevDMD = PrevData.first;
25797 break;
25798 }
25799 }
25800 }
25801 } else if (PrevDeclInScope) {
25802 auto *PrevDMDInScope = PrevDMD =
25803 cast<OMPDeclareMapperDecl>(Val: PrevDeclInScope);
25804 do {
25805 PreviousRedeclTypes[PrevDMDInScope->getType().getCanonicalType()] =
25806 PrevDMDInScope->getLocation();
25807 PrevDMDInScope = PrevDMDInScope->getPrevDeclInScope();
25808 } while (PrevDMDInScope != nullptr);
25809 }
25810 const auto I = PreviousRedeclTypes.find(Val: MapperType.getCanonicalType());
25811 bool Invalid = false;
25812 if (I != PreviousRedeclTypes.end()) {
25813 Diag(Loc: StartLoc, DiagID: diag::err_omp_declare_mapper_redefinition)
25814 << MapperType << Name;
25815 Diag(Loc: I->second, DiagID: diag::note_previous_definition);
25816 Invalid = true;
25817 }
25818 // Build expressions for implicit maps of data members with 'default'
25819 // mappers.
25820 SmallVector<OMPClause *, 4> ClausesWithImplicit(Clauses);
25821 if (getLangOpts().OpenMP >= 50)
25822 processImplicitMapsWithDefaultMappers(S&: SemaRef, DSAStack,
25823 Clauses&: ClausesWithImplicit);
25824 auto *DMD = OMPDeclareMapperDecl::Create(C&: getASTContext(), DC, L: StartLoc, Name,
25825 T: MapperType, VarName: VN, Clauses: ClausesWithImplicit,
25826 PrevDeclInScope: PrevDMD);
25827 if (S)
25828 SemaRef.PushOnScopeChains(D: DMD, S);
25829 else
25830 DC->addDecl(D: DMD);
25831 DMD->setAccess(AS);
25832 if (Invalid)
25833 DMD->setInvalidDecl();
25834
25835 auto *VD = cast<DeclRefExpr>(Val: MapperVarRef)->getDecl();
25836 VD->setDeclContext(DMD);
25837 VD->setLexicalDeclContext(DMD);
25838 DMD->addDecl(D: VD);
25839 DMD->setMapperVarRef(MapperVarRef);
25840
25841 return DeclGroupPtrTy::make(P: DeclGroupRef(DMD));
25842}
25843
25844ExprResult SemaOpenMP::ActOnOpenMPDeclareMapperDirectiveVarDecl(
25845 Scope *S, QualType MapperType, SourceLocation StartLoc,
25846 DeclarationName VN) {
25847 TypeSourceInfo *TInfo =
25848 getASTContext().getTrivialTypeSourceInfo(T: MapperType, Loc: StartLoc);
25849 auto *VD = VarDecl::Create(
25850 C&: getASTContext(), DC: getASTContext().getTranslationUnitDecl(), StartLoc,
25851 IdLoc: StartLoc, Id: VN.getAsIdentifierInfo(), T: MapperType, TInfo, S: SC_None);
25852 if (S)
25853 SemaRef.PushOnScopeChains(D: VD, S, /*AddToContext=*/false);
25854 Expr *E = buildDeclRefExpr(S&: SemaRef, D: VD, Ty: MapperType, Loc: StartLoc);
25855 DSAStack->addDeclareMapperVarRef(Ref: E);
25856 return E;
25857}
25858
25859void SemaOpenMP::ActOnOpenMPIteratorVarDecl(VarDecl *VD) {
25860 bool IsGlobalVar =
25861 !VD->isLocalVarDecl() && VD->getDeclContext()->isTranslationUnit();
25862 if (DSAStack->getDeclareMapperVarRef()) {
25863 if (IsGlobalVar)
25864 SemaRef.Consumer.HandleTopLevelDecl(D: DeclGroupRef(VD));
25865 DSAStack->addIteratorVarDecl(VD);
25866 } else {
25867 // Currently, only declare mapper handles global-scope iterator vars.
25868 assert(!IsGlobalVar && "Only declare mapper handles TU-scope iterators.");
25869 }
25870}
25871
25872bool SemaOpenMP::isOpenMPDeclareMapperVarDeclAllowed(const VarDecl *VD) const {
25873 assert(getLangOpts().OpenMP && "Expected OpenMP mode.");
25874 const Expr *Ref = DSAStack->getDeclareMapperVarRef();
25875 if (const auto *DRE = cast_or_null<DeclRefExpr>(Val: Ref)) {
25876 if (VD->getCanonicalDecl() == DRE->getDecl()->getCanonicalDecl())
25877 return true;
25878 if (VD->isUsableInConstantExpressions(C: getASTContext()))
25879 return true;
25880 if (getLangOpts().OpenMP >= 52 && DSAStack->isIteratorVarDecl(VD))
25881 return true;
25882 return false;
25883 }
25884 return true;
25885}
25886
25887const ValueDecl *SemaOpenMP::getOpenMPDeclareMapperVarName() const {
25888 assert(getLangOpts().OpenMP && "Expected OpenMP mode.");
25889 return cast<DeclRefExpr>(DSAStack->getDeclareMapperVarRef())->getDecl();
25890}
25891
25892ExprResult SemaOpenMP::ActOnOpenMPDimsModifier(OpenMPClauseKind ClauseKind,
25893 int Modifier, Expr *ModifierExpr,
25894 SourceLocation ModifierLoc,
25895 ArrayRef<Expr *> VarList,
25896 SourceLocation VarListEndLoc) {
25897 assert(ModifierExpr && "Unexpected modifier expression.");
25898
25899 if (getLangOpts().OpenMP < 61) {
25900 Diag(Loc: ModifierLoc, DiagID: diag::err_omp_modifier_requires_version)
25901 << getOpenMPSimpleClauseTypeName(Kind: ClauseKind, Type: Modifier)
25902 << getOpenMPClauseName(C: ClauseKind) << "6.1";
25903 return ExprError();
25904 }
25905
25906 ExprResult DimsRes = VerifyPositiveIntegerConstantInClause(
25907 E: ModifierExpr, CKind: ClauseKind, /*StrictlyPositive=*/true,
25908 /*SuppressExprDiags=*/false);
25909 if (DimsRes.isInvalid())
25910 return ExprError();
25911
25912 ModifierExpr = DimsRes.get();
25913 if (ModifierExpr->isInstantiationDependent())
25914 return DimsRes;
25915
25916 uint64_t NumDims =
25917 ModifierExpr->EvaluateKnownConstInt(Ctx: getASTContext()).getExtValue();
25918 if (NumDims == VarList.size())
25919 return DimsRes;
25920
25921 Diag(Loc: VarListEndLoc, DiagID: diag::err_omp_unexpected_num_exprs)
25922 << getOpenMPClauseName(C: ClauseKind) << NumDims << VarList.size();
25923 return ExprError();
25924}
25925
25926OMPClause *SemaOpenMP::ActOnOpenMPNumTeamsClause(
25927 ArrayRef<Expr *> VarList, OpenMPNumTeamsClauseModifier Modifier,
25928 Expr *ModifierExpr, SourceLocation ModifierLoc,
25929 OpenMPNumTeamsClauseModifier ModifierExtra, Expr *,
25930 SourceLocation ModifierExtraLoc, SourceLocation StartLoc,
25931 SourceLocation LParenLoc, SourceLocation EndLoc) {
25932 if (VarList.empty())
25933 return nullptr;
25934
25935 for (Expr *ValExpr : VarList) {
25936 // OpenMP [teams Construct, Restrictions]
25937 // The num_teams expression must evaluate to a positive integer value.
25938 if (!isNonNegativeIntegerValue(ValExpr, SemaRef, CKind: OMPC_num_teams,
25939 /*StrictlyPositive=*/true))
25940 return nullptr;
25941 }
25942
25943 // OpenMP [teams Construct, Restrictions]
25944 // The lower-bound modifier cannot be specified if the dims modifier is
25945 // specified.
25946 if (Modifier != OMPC_NUMTEAMS_unknown &&
25947 ModifierExtra != OMPC_NUMTEAMS_unknown) {
25948 Diag(Loc: ModifierExtraLoc, DiagID: diag::err_omp_incompatible_modifiers)
25949 << getOpenMPSimpleClauseTypeName(Kind: llvm::omp::OMPC_num_teams,
25950 Type: ModifierExtra)
25951 << getOpenMPSimpleClauseTypeName(Kind: llvm::omp::OMPC_num_teams, Type: Modifier)
25952 << getOpenMPClauseName(C: llvm::omp::OMPC_num_teams);
25953 ModifierExtra = OMPC_NUMTEAMS_unknown;
25954 ModifierExtraLoc = SourceLocation();
25955 }
25956
25957 if (Modifier == OMPC_NUMTEAMS_dims) {
25958 ExprResult Res = ActOnOpenMPDimsModifier(
25959 ClauseKind: OMPC_num_teams, Modifier, ModifierExpr, ModifierLoc, VarList, VarListEndLoc: EndLoc);
25960 if (Res.isInvalid())
25961 return nullptr;
25962 ModifierExpr = Res.get();
25963 } else if (Modifier == OMPC_NUMTEAMS_lower_bound) {
25964 assert(ModifierExpr && "Unexpected modifier expression.");
25965
25966 if (getLangOpts().OpenMP < 51) {
25967 Diag(Loc: ModifierLoc, DiagID: diag::err_omp_modifier_requires_version)
25968 << getOpenMPSimpleClauseTypeName(Kind: llvm::omp::OMPC_num_teams, Type: Modifier)
25969 << getOpenMPClauseName(C: llvm::omp::OMPC_num_teams) << "5.1";
25970 return nullptr;
25971 }
25972
25973 // OpenMP [teams Construct, Restrictions]
25974 // The lower-bound expression in num_teams must evaluate to a positive
25975 // integer value.
25976 if (!isNonNegativeIntegerValue(ValExpr&: ModifierExpr, SemaRef, CKind: OMPC_num_teams,
25977 /*StrictlyPositive=*/true))
25978 return nullptr;
25979
25980 // OpenMP 5.2: Validate lower-bound is less than or equal to upper-bound.
25981 Expr *LowerBound = ModifierExpr;
25982 Expr *UpperBound = VarList[0];
25983
25984 // Check if both are compile-time constants for validation.
25985 if (!LowerBound->isValueDependent() && !UpperBound->isValueDependent() &&
25986 LowerBound->isIntegerConstantExpr(Ctx: getASTContext()) &&
25987 UpperBound->isIntegerConstantExpr(Ctx: getASTContext())) {
25988
25989 // Get the actual constant values.
25990 llvm::APSInt LowerVal =
25991 LowerBound->EvaluateKnownConstInt(Ctx: getASTContext());
25992 llvm::APSInt UpperVal =
25993 UpperBound->EvaluateKnownConstInt(Ctx: getASTContext());
25994
25995 if (LowerVal > UpperVal) {
25996 Diag(Loc: LowerBound->getExprLoc(),
25997 DiagID: diag::err_omp_num_teams_lower_bound_larger)
25998 << LowerBound->getSourceRange() << UpperBound->getSourceRange();
25999 return nullptr;
26000 }
26001 }
26002 }
26003
26004 OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
26005 OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause(
26006 DKind, CKind: OMPC_num_teams, OMPVersion: getLangOpts().getOpenMPVersion());
26007 if (CaptureRegion == OMPD_unknown || SemaRef.CurContext->isDependentContext())
26008 return OMPNumTeamsClause::Create(C: getASTContext(), CaptureRegion, StartLoc,
26009 LParenLoc, EndLoc, VL: VarList, Modifier,
26010 ModifierExpr, ModifierLoc,
26011 /*PreInit=*/nullptr);
26012
26013 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
26014 SmallVector<Expr *, 3> Vars;
26015 for (Expr *ValExpr : VarList) {
26016 ValExpr = SemaRef.MakeFullExpr(Arg: ValExpr).get();
26017 ValExpr = tryBuildCapture(SemaRef, Capture: ValExpr, Captures).get();
26018 Vars.push_back(Elt: ValExpr);
26019 }
26020
26021 if (ModifierExpr) {
26022 ModifierExpr = SemaRef.MakeFullExpr(Arg: ModifierExpr).get();
26023 ModifierExpr = tryBuildCapture(SemaRef, Capture: ModifierExpr, Captures).get();
26024 }
26025
26026 Stmt *PreInit = buildPreInits(Context&: getASTContext(), Captures);
26027 return OMPNumTeamsClause::Create(C: getASTContext(), CaptureRegion, StartLoc,
26028 LParenLoc, EndLoc, VL: Vars, Modifier,
26029 ModifierExpr, ModifierLoc, PreInit);
26030}
26031
26032OMPClause *SemaOpenMP::ActOnOpenMPThreadLimitClause(
26033 ArrayRef<Expr *> VarList, OpenMPThreadLimitClauseModifier Modifier,
26034 Expr *ModifierExpr, SourceLocation ModifierLoc, SourceLocation StartLoc,
26035 SourceLocation LParenLoc, SourceLocation EndLoc) {
26036 if (VarList.empty())
26037 return nullptr;
26038
26039 for (Expr *ValExpr : VarList) {
26040 // OpenMP [teams Constrcut, Restrictions]
26041 // The thread_limit expression must evaluate to a positive integer value.
26042 if (!isNonNegativeIntegerValue(ValExpr, SemaRef, CKind: OMPC_thread_limit,
26043 /*StrictlyPositive=*/true))
26044 return nullptr;
26045 }
26046
26047 if (Modifier == OMPC_THREADLIMIT_dims) {
26048 ExprResult Res =
26049 ActOnOpenMPDimsModifier(ClauseKind: OMPC_thread_limit, Modifier, ModifierExpr,
26050 ModifierLoc, VarList, VarListEndLoc: EndLoc);
26051 if (Res.isInvalid())
26052 return nullptr;
26053 ModifierExpr = Res.get();
26054 }
26055
26056 OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
26057 OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause(
26058 DKind, CKind: OMPC_thread_limit, OMPVersion: getLangOpts().getOpenMPVersion());
26059 if (CaptureRegion == OMPD_unknown || SemaRef.CurContext->isDependentContext())
26060 return OMPThreadLimitClause::Create(C: getASTContext(), CaptureRegion,
26061 StartLoc, LParenLoc, EndLoc, VL: VarList,
26062 Modifier, ModifierExpr, ModifierLoc,
26063 /*PreInit=*/nullptr);
26064
26065 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
26066 SmallVector<Expr *, 3> Vars;
26067 for (Expr *ValExpr : VarList) {
26068 ValExpr = SemaRef.MakeFullExpr(Arg: ValExpr).get();
26069 ValExpr = tryBuildCapture(SemaRef, Capture: ValExpr, Captures).get();
26070 Vars.push_back(Elt: ValExpr);
26071 }
26072
26073 if (ModifierExpr) {
26074 ModifierExpr = SemaRef.MakeFullExpr(Arg: ModifierExpr).get();
26075 ModifierExpr = tryBuildCapture(SemaRef, Capture: ModifierExpr, Captures).get();
26076 }
26077
26078 Stmt *PreInit = buildPreInits(Context&: getASTContext(), Captures);
26079 return OMPThreadLimitClause::Create(C: getASTContext(), CaptureRegion, StartLoc,
26080 LParenLoc, EndLoc, VL: Vars, Modifier,
26081 ModifierExpr, ModifierLoc, PreInit);
26082}
26083
26084OMPClause *SemaOpenMP::ActOnOpenMPPriorityClause(Expr *Priority,
26085 SourceLocation StartLoc,
26086 SourceLocation LParenLoc,
26087 SourceLocation EndLoc) {
26088 Expr *ValExpr = Priority;
26089 Stmt *HelperValStmt = nullptr;
26090 OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
26091
26092 // OpenMP [2.9.1, task Constrcut]
26093 // The priority-value is a non-negative numerical scalar expression.
26094 if (!isNonNegativeIntegerValue(
26095 ValExpr, SemaRef, CKind: OMPC_priority,
26096 /*StrictlyPositive=*/false, /*BuildCapture=*/true,
26097 DSAStack->getCurrentDirective(), CaptureRegion: &CaptureRegion, HelperValStmt: &HelperValStmt))
26098 return nullptr;
26099
26100 return new (getASTContext()) OMPPriorityClause(
26101 ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
26102}
26103
26104OMPClause *SemaOpenMP::ActOnOpenMPGrainsizeClause(
26105 OpenMPGrainsizeClauseModifier Modifier, Expr *Grainsize,
26106 SourceLocation StartLoc, SourceLocation LParenLoc,
26107 SourceLocation ModifierLoc, SourceLocation EndLoc) {
26108 assert((ModifierLoc.isInvalid() || getLangOpts().OpenMP >= 51) &&
26109 "Unexpected grainsize modifier in OpenMP < 51.");
26110
26111 if (ModifierLoc.isValid() && Modifier == OMPC_GRAINSIZE_unknown) {
26112 std::string Values = getListOfPossibleValues(K: OMPC_grainsize, /*First=*/0,
26113 Last: OMPC_GRAINSIZE_unknown);
26114 Diag(Loc: ModifierLoc, DiagID: diag::err_omp_unexpected_clause_value)
26115 << Values << getOpenMPClauseNameForDiag(C: OMPC_grainsize);
26116 return nullptr;
26117 }
26118
26119 Expr *ValExpr = Grainsize;
26120 Stmt *HelperValStmt = nullptr;
26121 OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
26122
26123 // OpenMP [2.9.2, taskloop Constrcut]
26124 // The parameter of the grainsize clause must be a positive integer
26125 // expression.
26126 if (!isNonNegativeIntegerValue(ValExpr, SemaRef, CKind: OMPC_grainsize,
26127 /*StrictlyPositive=*/true,
26128 /*BuildCapture=*/true,
26129 DSAStack->getCurrentDirective(),
26130 CaptureRegion: &CaptureRegion, HelperValStmt: &HelperValStmt))
26131 return nullptr;
26132
26133 return new (getASTContext())
26134 OMPGrainsizeClause(Modifier, ValExpr, HelperValStmt, CaptureRegion,
26135 StartLoc, LParenLoc, ModifierLoc, EndLoc);
26136}
26137
26138OMPClause *SemaOpenMP::ActOnOpenMPNumTasksClause(
26139 OpenMPNumTasksClauseModifier Modifier, Expr *NumTasks,
26140 SourceLocation StartLoc, SourceLocation LParenLoc,
26141 SourceLocation ModifierLoc, SourceLocation EndLoc) {
26142 assert((ModifierLoc.isInvalid() || getLangOpts().OpenMP >= 51) &&
26143 "Unexpected num_tasks modifier in OpenMP < 51.");
26144
26145 if (ModifierLoc.isValid() && Modifier == OMPC_NUMTASKS_unknown) {
26146 std::string Values = getListOfPossibleValues(K: OMPC_num_tasks, /*First=*/0,
26147 Last: OMPC_NUMTASKS_unknown);
26148 Diag(Loc: ModifierLoc, DiagID: diag::err_omp_unexpected_clause_value)
26149 << Values << getOpenMPClauseNameForDiag(C: OMPC_num_tasks);
26150 return nullptr;
26151 }
26152
26153 Expr *ValExpr = NumTasks;
26154 Stmt *HelperValStmt = nullptr;
26155 OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
26156
26157 // OpenMP [2.9.2, taskloop Constrcut]
26158 // The parameter of the num_tasks clause must be a positive integer
26159 // expression.
26160 if (!isNonNegativeIntegerValue(
26161 ValExpr, SemaRef, CKind: OMPC_num_tasks,
26162 /*StrictlyPositive=*/true, /*BuildCapture=*/true,
26163 DSAStack->getCurrentDirective(), CaptureRegion: &CaptureRegion, HelperValStmt: &HelperValStmt))
26164 return nullptr;
26165
26166 return new (getASTContext())
26167 OMPNumTasksClause(Modifier, ValExpr, HelperValStmt, CaptureRegion,
26168 StartLoc, LParenLoc, ModifierLoc, EndLoc);
26169}
26170
26171OMPClause *SemaOpenMP::ActOnOpenMPHintClause(Expr *Hint,
26172 SourceLocation StartLoc,
26173 SourceLocation LParenLoc,
26174 SourceLocation EndLoc) {
26175 // OpenMP [2.13.2, critical construct, Description]
26176 // ... where hint-expression is an integer constant expression that evaluates
26177 // to a valid lock hint.
26178 ExprResult HintExpr =
26179 VerifyPositiveIntegerConstantInClause(E: Hint, CKind: OMPC_hint, StrictlyPositive: false);
26180 if (HintExpr.isInvalid())
26181 return nullptr;
26182 return new (getASTContext())
26183 OMPHintClause(HintExpr.get(), StartLoc, LParenLoc, EndLoc);
26184}
26185
26186/// Tries to find omp_event_handle_t type.
26187static bool findOMPEventHandleT(Sema &S, SourceLocation Loc,
26188 DSAStackTy *Stack) {
26189 QualType OMPEventHandleT = Stack->getOMPEventHandleT();
26190 if (!OMPEventHandleT.isNull())
26191 return true;
26192 IdentifierInfo *II = &S.PP.getIdentifierTable().get(Name: "omp_event_handle_t");
26193 ParsedType PT = S.getTypeName(II: *II, NameLoc: Loc, S: S.getCurScope());
26194 if (!PT.getAsOpaquePtr() || PT.get().isNull()) {
26195 S.Diag(Loc, DiagID: diag::err_omp_implied_type_not_found) << "omp_event_handle_t";
26196 return false;
26197 }
26198 Stack->setOMPEventHandleT(PT.get());
26199 return true;
26200}
26201
26202OMPClause *SemaOpenMP::ActOnOpenMPDetachClause(Expr *Evt,
26203 SourceLocation StartLoc,
26204 SourceLocation LParenLoc,
26205 SourceLocation EndLoc) {
26206 if (!Evt->isValueDependent() && !Evt->isTypeDependent() &&
26207 !Evt->isInstantiationDependent() &&
26208 !Evt->containsUnexpandedParameterPack()) {
26209 if (!findOMPEventHandleT(S&: SemaRef, Loc: Evt->getExprLoc(), DSAStack))
26210 return nullptr;
26211 // OpenMP 5.0, 2.10.1 task Construct.
26212 // event-handle is a variable of the omp_event_handle_t type.
26213 auto *Ref = dyn_cast<DeclRefExpr>(Val: Evt->IgnoreParenImpCasts());
26214 if (!Ref) {
26215 Diag(Loc: Evt->getExprLoc(), DiagID: diag::err_omp_var_expected)
26216 << "omp_event_handle_t" << 0 << Evt->getSourceRange();
26217 return nullptr;
26218 }
26219 auto *VD = dyn_cast_or_null<VarDecl>(Val: Ref->getDecl());
26220 if (!VD) {
26221 Diag(Loc: Evt->getExprLoc(), DiagID: diag::err_omp_var_expected)
26222 << "omp_event_handle_t" << 0 << Evt->getSourceRange();
26223 return nullptr;
26224 }
26225 if (!getASTContext().hasSameUnqualifiedType(DSAStack->getOMPEventHandleT(),
26226 T2: VD->getType()) ||
26227 VD->getType().isConstant(Ctx: getASTContext())) {
26228 Diag(Loc: Evt->getExprLoc(), DiagID: diag::err_omp_var_expected)
26229 << "omp_event_handle_t" << 1 << VD->getType()
26230 << Evt->getSourceRange();
26231 return nullptr;
26232 }
26233 // OpenMP 5.0, 2.10.1 task Construct
26234 // [detach clause]... The event-handle will be considered as if it was
26235 // specified on a firstprivate clause.
26236 DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D: VD, /*FromParent=*/false);
26237 if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate &&
26238 DVar.RefExpr) {
26239 Diag(Loc: Evt->getExprLoc(), DiagID: diag::err_omp_wrong_dsa)
26240 << getOpenMPClauseNameForDiag(C: DVar.CKind)
26241 << getOpenMPClauseNameForDiag(C: OMPC_firstprivate);
26242 reportOriginalDsa(SemaRef, DSAStack, D: VD, DVar);
26243 return nullptr;
26244 }
26245 }
26246
26247 return new (getASTContext())
26248 OMPDetachClause(Evt, StartLoc, LParenLoc, EndLoc);
26249}
26250
26251OMPClause *SemaOpenMP::ActOnOpenMPDistScheduleClause(
26252 OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc,
26253 SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc,
26254 SourceLocation EndLoc) {
26255 if (Kind == OMPC_DIST_SCHEDULE_unknown) {
26256 std::string Values;
26257 Values += "'";
26258 Values += getOpenMPSimpleClauseTypeName(Kind: OMPC_dist_schedule, Type: 0);
26259 Values += "'";
26260 Diag(Loc: KindLoc, DiagID: diag::err_omp_unexpected_clause_value)
26261 << Values << getOpenMPClauseNameForDiag(C: OMPC_dist_schedule);
26262 return nullptr;
26263 }
26264 Expr *ValExpr = ChunkSize;
26265 Stmt *HelperValStmt = nullptr;
26266 if (ChunkSize) {
26267 if (!ChunkSize->isValueDependent() && !ChunkSize->isTypeDependent() &&
26268 !ChunkSize->isInstantiationDependent() &&
26269 !ChunkSize->containsUnexpandedParameterPack()) {
26270 SourceLocation ChunkSizeLoc = ChunkSize->getBeginLoc();
26271 ExprResult Val =
26272 PerformOpenMPImplicitIntegerConversion(Loc: ChunkSizeLoc, Op: ChunkSize);
26273 if (Val.isInvalid())
26274 return nullptr;
26275
26276 ValExpr = Val.get();
26277
26278 // OpenMP [2.7.1, Restrictions]
26279 // chunk_size must be a loop invariant integer expression with a positive
26280 // value.
26281 if (std::optional<llvm::APSInt> Result =
26282 ValExpr->getIntegerConstantExpr(Ctx: getASTContext())) {
26283 if (Result->isSigned() && !Result->isStrictlyPositive()) {
26284 Diag(Loc: ChunkSizeLoc, DiagID: diag::err_omp_negative_expression_in_clause)
26285 << "dist_schedule" << /*strictly positive*/ 1
26286 << ChunkSize->getSourceRange();
26287 return nullptr;
26288 }
26289 } else if (getOpenMPCaptureRegionForClause(
26290 DSAStack->getCurrentDirective(), CKind: OMPC_dist_schedule,
26291 OMPVersion: getLangOpts().getOpenMPVersion()) != OMPD_unknown &&
26292 !SemaRef.CurContext->isDependentContext()) {
26293 ValExpr = SemaRef.MakeFullExpr(Arg: ValExpr).get();
26294 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
26295 ValExpr = tryBuildCapture(SemaRef, Capture: ValExpr, Captures).get();
26296 HelperValStmt = buildPreInits(Context&: getASTContext(), Captures);
26297 }
26298 }
26299 }
26300
26301 return new (getASTContext())
26302 OMPDistScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc,
26303 Kind, ValExpr, HelperValStmt);
26304}
26305
26306OMPClause *SemaOpenMP::ActOnOpenMPDefaultmapClause(
26307 OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind,
26308 SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc,
26309 SourceLocation KindLoc, SourceLocation EndLoc) {
26310 if (getLangOpts().OpenMP < 50) {
26311 if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom ||
26312 Kind != OMPC_DEFAULTMAP_scalar) {
26313 std::string Value;
26314 SourceLocation Loc;
26315 Value += "'";
26316 if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom) {
26317 Value += getOpenMPSimpleClauseTypeName(Kind: OMPC_defaultmap,
26318 Type: OMPC_DEFAULTMAP_MODIFIER_tofrom);
26319 Loc = MLoc;
26320 } else {
26321 Value += getOpenMPSimpleClauseTypeName(Kind: OMPC_defaultmap,
26322 Type: OMPC_DEFAULTMAP_scalar);
26323 Loc = KindLoc;
26324 }
26325 Value += "'";
26326 Diag(Loc, DiagID: diag::err_omp_unexpected_clause_value)
26327 << Value << getOpenMPClauseNameForDiag(C: OMPC_defaultmap);
26328 return nullptr;
26329 }
26330 } else {
26331 bool isDefaultmapModifier = (M != OMPC_DEFAULTMAP_MODIFIER_unknown);
26332 bool isDefaultmapKind = (Kind != OMPC_DEFAULTMAP_unknown) ||
26333 (getLangOpts().OpenMP >= 50 && KindLoc.isInvalid());
26334 if (!isDefaultmapKind || !isDefaultmapModifier) {
26335 StringRef KindValue = getLangOpts().OpenMP < 52
26336 ? "'scalar', 'aggregate', 'pointer'"
26337 : "'scalar', 'aggregate', 'pointer', 'all'";
26338 if (getLangOpts().OpenMP == 50) {
26339 StringRef ModifierValue = "'alloc', 'from', 'to', 'tofrom', "
26340 "'firstprivate', 'none', 'default'";
26341 if (!isDefaultmapKind && isDefaultmapModifier) {
26342 Diag(Loc: KindLoc, DiagID: diag::err_omp_unexpected_clause_value)
26343 << KindValue << getOpenMPClauseNameForDiag(C: OMPC_defaultmap);
26344 } else if (isDefaultmapKind && !isDefaultmapModifier) {
26345 Diag(Loc: MLoc, DiagID: diag::err_omp_unexpected_clause_value)
26346 << ModifierValue << getOpenMPClauseNameForDiag(C: OMPC_defaultmap);
26347 } else {
26348 Diag(Loc: MLoc, DiagID: diag::err_omp_unexpected_clause_value)
26349 << ModifierValue << getOpenMPClauseNameForDiag(C: OMPC_defaultmap);
26350 Diag(Loc: KindLoc, DiagID: diag::err_omp_unexpected_clause_value)
26351 << KindValue << getOpenMPClauseNameForDiag(C: OMPC_defaultmap);
26352 }
26353 } else {
26354 StringRef ModifierValue =
26355 getLangOpts().OpenMP < 60
26356 ? "'alloc', 'from', 'to', 'tofrom', "
26357 "'firstprivate', 'none', 'default', 'present'"
26358 : "'storage', 'from', 'to', 'tofrom', "
26359 "'firstprivate', 'private', 'none', 'default', 'present'";
26360 if (!isDefaultmapKind && isDefaultmapModifier) {
26361 Diag(Loc: KindLoc, DiagID: diag::err_omp_unexpected_clause_value)
26362 << KindValue << getOpenMPClauseNameForDiag(C: OMPC_defaultmap);
26363 } else if (isDefaultmapKind && !isDefaultmapModifier) {
26364 Diag(Loc: MLoc, DiagID: diag::err_omp_unexpected_clause_value)
26365 << ModifierValue << getOpenMPClauseNameForDiag(C: OMPC_defaultmap);
26366 } else {
26367 Diag(Loc: MLoc, DiagID: diag::err_omp_unexpected_clause_value)
26368 << ModifierValue << getOpenMPClauseNameForDiag(C: OMPC_defaultmap);
26369 Diag(Loc: KindLoc, DiagID: diag::err_omp_unexpected_clause_value)
26370 << KindValue << getOpenMPClauseNameForDiag(C: OMPC_defaultmap);
26371 }
26372 }
26373 return nullptr;
26374 }
26375
26376 // OpenMP [5.0, 2.12.5, Restrictions, p. 174]
26377 // At most one defaultmap clause for each category can appear on the
26378 // directive.
26379 if (DSAStack->checkDefaultmapCategory(VariableCategory: Kind)) {
26380 Diag(Loc: StartLoc, DiagID: diag::err_omp_one_defaultmap_each_category);
26381 return nullptr;
26382 }
26383 }
26384 if (Kind == OMPC_DEFAULTMAP_unknown || Kind == OMPC_DEFAULTMAP_all) {
26385 // Variable category is not specified - mark all categories.
26386 DSAStack->setDefaultDMAAttr(M, Kind: OMPC_DEFAULTMAP_aggregate, Loc: StartLoc);
26387 DSAStack->setDefaultDMAAttr(M, Kind: OMPC_DEFAULTMAP_scalar, Loc: StartLoc);
26388 DSAStack->setDefaultDMAAttr(M, Kind: OMPC_DEFAULTMAP_pointer, Loc: StartLoc);
26389 } else {
26390 DSAStack->setDefaultDMAAttr(M, Kind, Loc: StartLoc);
26391 }
26392
26393 return new (getASTContext())
26394 OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M);
26395}
26396
26397bool SemaOpenMP::ActOnStartOpenMPDeclareTargetContext(
26398 DeclareTargetContextInfo &DTCI) {
26399 DeclContext *CurLexicalContext = SemaRef.getCurLexicalContext();
26400 if (!CurLexicalContext->isFileContext() &&
26401 !CurLexicalContext->isExternCContext() &&
26402 !CurLexicalContext->isExternCXXContext() &&
26403 !isa<CXXRecordDecl>(Val: CurLexicalContext) &&
26404 !isa<ClassTemplateDecl>(Val: CurLexicalContext) &&
26405 !isa<ClassTemplatePartialSpecializationDecl>(Val: CurLexicalContext) &&
26406 !isa<ClassTemplateSpecializationDecl>(Val: CurLexicalContext)) {
26407 Diag(Loc: DTCI.Loc, DiagID: diag::err_omp_region_not_file_context);
26408 return false;
26409 }
26410
26411 // Report affected OpenMP target offloading behavior when in HIP lang-mode.
26412 if (getLangOpts().HIP)
26413 Diag(Loc: DTCI.Loc, DiagID: diag::warn_hip_omp_target_directives);
26414
26415 DeclareTargetNesting.push_back(Elt: DTCI);
26416 return true;
26417}
26418
26419const SemaOpenMP::DeclareTargetContextInfo
26420SemaOpenMP::ActOnOpenMPEndDeclareTargetDirective() {
26421 assert(!DeclareTargetNesting.empty() &&
26422 "check isInOpenMPDeclareTargetContext() first!");
26423 return DeclareTargetNesting.pop_back_val();
26424}
26425
26426void SemaOpenMP::ActOnFinishedOpenMPDeclareTargetContext(
26427 DeclareTargetContextInfo &DTCI) {
26428 for (auto &It : DTCI.ExplicitlyMapped)
26429 ActOnOpenMPDeclareTargetName(ND: It.first, Loc: It.second.Loc, MT: It.second.MT, DTCI);
26430}
26431
26432void SemaOpenMP::DiagnoseUnterminatedOpenMPDeclareTarget() {
26433 if (DeclareTargetNesting.empty())
26434 return;
26435 DeclareTargetContextInfo &DTCI = DeclareTargetNesting.back();
26436 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
26437 Diag(Loc: DTCI.Loc, DiagID: diag::warn_omp_unterminated_declare_target)
26438 << getOpenMPDirectiveName(D: DTCI.Kind, V: OMPVersion);
26439}
26440
26441NamedDecl *SemaOpenMP::lookupOpenMPDeclareTargetName(
26442 Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id) {
26443 LookupResult Lookup(SemaRef, Id, Sema::LookupOrdinaryName);
26444 SemaRef.LookupParsedName(R&: Lookup, S: CurScope, SS: &ScopeSpec,
26445 /*ObjectType=*/QualType(),
26446 /*AllowBuiltinCreation=*/true);
26447
26448 if (Lookup.isAmbiguous())
26449 return nullptr;
26450 Lookup.suppressDiagnostics();
26451
26452 if (!Lookup.isSingleResult()) {
26453 VarOrFuncDeclFilterCCC CCC(SemaRef);
26454 if (TypoCorrection Corrected =
26455 SemaRef.CorrectTypo(Typo: Id, LookupKind: Sema::LookupOrdinaryName, S: CurScope, SS: nullptr,
26456 CCC, Mode: CorrectTypoKind::ErrorRecovery)) {
26457 SemaRef.diagnoseTypo(Correction: Corrected,
26458 TypoDiag: SemaRef.PDiag(DiagID: diag::err_undeclared_var_use_suggest)
26459 << Id.getName());
26460 checkDeclIsAllowedInOpenMPTarget(E: nullptr, D: Corrected.getCorrectionDecl());
26461 return nullptr;
26462 }
26463
26464 Diag(Loc: Id.getLoc(), DiagID: diag::err_undeclared_var_use) << Id.getName();
26465 return nullptr;
26466 }
26467
26468 NamedDecl *ND = Lookup.getAsSingle<NamedDecl>();
26469 if (!isa<VarDecl>(Val: ND) && !isa<FunctionDecl>(Val: ND) &&
26470 !isa<FunctionTemplateDecl>(Val: ND)) {
26471 Diag(Loc: Id.getLoc(), DiagID: diag::err_omp_invalid_target_decl) << Id.getName();
26472 return nullptr;
26473 }
26474 return ND;
26475}
26476
26477void SemaOpenMP::ActOnOpenMPDeclareTargetName(
26478 NamedDecl *ND, SourceLocation Loc, OMPDeclareTargetDeclAttr::MapTypeTy MT,
26479 DeclareTargetContextInfo &DTCI) {
26480 assert((isa<VarDecl>(ND) || isa<FunctionDecl>(ND) ||
26481 isa<FunctionTemplateDecl>(ND)) &&
26482 "Expected variable, function or function template.");
26483
26484 if (auto *VD = dyn_cast<VarDecl>(Val: ND)) {
26485 // Only global variables can be marked as declare target.
26486 if (!VD->isFileVarDecl() && !VD->isStaticLocal() &&
26487 !VD->isStaticDataMember()) {
26488 Diag(Loc, DiagID: diag::err_omp_declare_target_has_local_vars)
26489 << VD->getNameAsString();
26490 return;
26491 }
26492 }
26493 // Diagnose marking after use as it may lead to incorrect diagnosis and
26494 // codegen.
26495 if (getLangOpts().OpenMP >= 50 &&
26496 (ND->isUsed(/*CheckUsedAttr=*/false) || ND->isReferenced()))
26497 Diag(Loc, DiagID: diag::warn_omp_declare_target_after_first_use);
26498
26499 // Report affected OpenMP target offloading behavior when in HIP lang-mode.
26500 if (getLangOpts().HIP)
26501 Diag(Loc, DiagID: diag::warn_hip_omp_target_directives);
26502
26503 // 'local' is incompatible with 'device_type(host)' because 'local'
26504 // variables exist only on the device.
26505 if (MT == OMPDeclareTargetDeclAttr::MT_Local &&
26506 DTCI.DT == OMPDeclareTargetDeclAttr::DT_Host) {
26507 Diag(Loc, DiagID: diag::err_omp_declare_target_local_host_only);
26508 return;
26509 }
26510
26511 // Explicit declare target lists have precedence.
26512 const unsigned Level = -1;
26513
26514 auto *VD = cast<ValueDecl>(Val: ND);
26515 std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
26516 OMPDeclareTargetDeclAttr::getActiveAttr(VD);
26517 if (ActiveAttr && (*ActiveAttr)->getDevType() != DTCI.DT &&
26518 (*ActiveAttr)->getLevel() == Level) {
26519 Diag(Loc, DiagID: diag::err_omp_device_type_mismatch)
26520 << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(Val: DTCI.DT)
26521 << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(
26522 Val: (*ActiveAttr)->getDevType());
26523 return;
26524 }
26525 if (ActiveAttr && (*ActiveAttr)->getMapType() != MT &&
26526 (*ActiveAttr)->getLevel() == Level) {
26527 Diag(Loc, DiagID: diag::err_omp_declare_target_var_in_both_clauses)
26528 << ND
26529 << OMPDeclareTargetDeclAttr::ConvertMapTypeTyToStr(
26530 Val: (*ActiveAttr)->getMapType())
26531 << OMPDeclareTargetDeclAttr::ConvertMapTypeTyToStr(Val: MT);
26532 return;
26533 }
26534
26535 if (ActiveAttr && (*ActiveAttr)->getLevel() == Level)
26536 return;
26537
26538 Expr *IndirectE = nullptr;
26539 bool IsIndirect = false;
26540 if (DTCI.Indirect) {
26541 IndirectE = *DTCI.Indirect;
26542 if (!IndirectE)
26543 IsIndirect = true;
26544 }
26545 // FIXME: 'local' with 'device_type(nohost)' is not yet fully supported
26546 // in codegen. Treat as 'device_type(any)' for now. The variable will
26547 // exist on both host and device, but the host copy is unused.
26548 auto DT = DTCI.DT;
26549 if (MT == OMPDeclareTargetDeclAttr::MT_Local &&
26550 DT == OMPDeclareTargetDeclAttr::DT_NoHost) {
26551 Diag(Loc, DiagID: diag::warn_omp_declare_target_local_nohost);
26552 DT = OMPDeclareTargetDeclAttr::DT_Any;
26553 }
26554
26555 auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(
26556 Ctx&: getASTContext(), MapType: MT, DevType: DT, IndirectExpr: IndirectE, Indirect: IsIndirect, Level,
26557 Range: SourceRange(Loc, Loc));
26558 ND->addAttr(A);
26559 if (ASTMutationListener *ML = getASTContext().getASTMutationListener())
26560 ML->DeclarationMarkedOpenMPDeclareTarget(D: ND, Attr: A);
26561 checkDeclIsAllowedInOpenMPTarget(E: nullptr, D: ND, IdLoc: Loc);
26562 if (auto *VD = dyn_cast<VarDecl>(Val: ND);
26563 getLangOpts().OpenMP && VD && VD->hasAttr<OMPDeclareTargetDeclAttr>() &&
26564 VD->hasGlobalStorage())
26565 ActOnOpenMPDeclareTargetInitializer(D: ND);
26566}
26567
26568static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR,
26569 Sema &SemaRef, Decl *D) {
26570 if (!D || !isa<VarDecl>(Val: D))
26571 return;
26572 auto *VD = cast<VarDecl>(Val: D);
26573 std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy =
26574 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
26575 if (SemaRef.LangOpts.OpenMP >= 50 &&
26576 (SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true) ||
26577 SemaRef.getCurBlock() || SemaRef.getCurCapturedRegion()) &&
26578 VD->hasGlobalStorage()) {
26579 if (!MapTy || (*MapTy != OMPDeclareTargetDeclAttr::MT_To &&
26580 *MapTy != OMPDeclareTargetDeclAttr::MT_Enter &&
26581 *MapTy != OMPDeclareTargetDeclAttr::MT_Local)) {
26582 // OpenMP 5.0, 2.12.7 declare target Directive, Restrictions
26583 // If a lambda declaration and definition appears between a
26584 // declare target directive and the matching end declare target
26585 // directive, all variables that are captured by the lambda
26586 // expression must also appear in a to clause.
26587 SemaRef.Diag(Loc: VD->getLocation(),
26588 DiagID: diag::err_omp_lambda_capture_in_declare_target_not_to);
26589 SemaRef.Diag(Loc: SL, DiagID: diag::note_var_explicitly_captured_here)
26590 << VD << 0 << SR;
26591 return;
26592 }
26593 }
26594 if (MapTy)
26595 return;
26596 SemaRef.Diag(Loc: VD->getLocation(), DiagID: diag::warn_omp_not_in_target_context);
26597 SemaRef.Diag(Loc: SL, DiagID: diag::note_used_here) << SR;
26598}
26599
26600static bool checkValueDeclInTarget(SourceLocation SL, SourceRange SR,
26601 Sema &SemaRef, DSAStackTy *Stack,
26602 ValueDecl *VD) {
26603 return OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) ||
26604 checkTypeMappable(SL, SR, SemaRef, Stack, QTy: VD->getType(),
26605 /*FullCheck=*/false);
26606}
26607
26608void SemaOpenMP::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
26609 SourceLocation IdLoc) {
26610 if (!D || D->isInvalidDecl())
26611 return;
26612 SourceRange SR = E ? E->getSourceRange() : D->getSourceRange();
26613 SourceLocation SL = E ? E->getBeginLoc() : D->getLocation();
26614 if (auto *VD = dyn_cast<VarDecl>(Val: D)) {
26615 // Only global variables can be marked as declare target.
26616 if (!VD->isFileVarDecl() && !VD->isStaticLocal() &&
26617 !VD->isStaticDataMember())
26618 return;
26619 // 2.10.6: threadprivate variable cannot appear in a declare target
26620 // directive.
26621 if (DSAStack->isThreadPrivate(D: VD)) {
26622 Diag(Loc: SL, DiagID: diag::err_omp_threadprivate_in_target);
26623 reportOriginalDsa(SemaRef, DSAStack, D: VD, DSAStack->getTopDSA(D: VD, FromParent: false));
26624 return;
26625 }
26626 }
26627 if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(Val: D))
26628 D = FTD->getTemplatedDecl();
26629 if (auto *FD = dyn_cast<FunctionDecl>(Val: D)) {
26630 std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
26631 OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD: FD);
26632 if (IdLoc.isValid() && Res &&
26633 (*Res == OMPDeclareTargetDeclAttr::MT_Link ||
26634 *Res == OMPDeclareTargetDeclAttr::MT_Local)) {
26635 Diag(Loc: IdLoc, DiagID: diag::err_omp_function_in_target_clause_list)
26636 << OMPDeclareTargetDeclAttr::ConvertMapTypeTyToStr(Val: *Res);
26637 Diag(Loc: FD->getLocation(), DiagID: diag::note_defined_here) << FD;
26638 return;
26639 }
26640 }
26641 if (auto *VD = dyn_cast<ValueDecl>(Val: D)) {
26642 // Problem if any with var declared with incomplete type will be reported
26643 // as normal, so no need to check it here.
26644 if ((E || !VD->getType()->isIncompleteType()) &&
26645 !checkValueDeclInTarget(SL, SR, SemaRef, DSAStack, VD))
26646 return;
26647 if (!E && isInOpenMPDeclareTargetContext()) {
26648 // Checking declaration inside declare target region.
26649 if (isa<VarDecl>(Val: D) || isa<FunctionDecl>(Val: D) ||
26650 isa<FunctionTemplateDecl>(Val: D)) {
26651 std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
26652 OMPDeclareTargetDeclAttr::getActiveAttr(VD);
26653 unsigned Level = DeclareTargetNesting.size();
26654 if (ActiveAttr && (*ActiveAttr)->getLevel() >= Level)
26655 return;
26656 DeclareTargetContextInfo &DTCI = DeclareTargetNesting.back();
26657 Expr *IndirectE = nullptr;
26658 bool IsIndirect = false;
26659 if (DTCI.Indirect) {
26660 IndirectE = *DTCI.Indirect;
26661 if (!IndirectE)
26662 IsIndirect = true;
26663 }
26664 auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(
26665 Ctx&: getASTContext(),
26666 MapType: getLangOpts().OpenMP >= 52 ? OMPDeclareTargetDeclAttr::MT_Enter
26667 : OMPDeclareTargetDeclAttr::MT_To,
26668 DevType: DTCI.DT, IndirectExpr: IndirectE, Indirect: IsIndirect, Level,
26669 Range: SourceRange(DTCI.Loc, DTCI.Loc));
26670 D->addAttr(A);
26671 if (ASTMutationListener *ML = getASTContext().getASTMutationListener())
26672 ML->DeclarationMarkedOpenMPDeclareTarget(D, Attr: A);
26673 }
26674 return;
26675 }
26676 }
26677 if (!E)
26678 return;
26679 checkDeclInTargetContext(SL: E->getExprLoc(), SR: E->getSourceRange(), SemaRef, D);
26680}
26681
26682/// This class visits every VarDecl that the initializer references and adds
26683/// OMPDeclareTargetDeclAttr to each of them.
26684class GlobalDeclRefChecker final : public StmtVisitor<GlobalDeclRefChecker> {
26685 SmallVector<VarDecl *> DeclVector;
26686 Attr *A;
26687
26688public:
26689 /// A StmtVisitor class function that visits all DeclRefExpr and adds
26690 /// OMPDeclareTargetDeclAttr to them.
26691 void VisitDeclRefExpr(DeclRefExpr *Node) {
26692 if (auto *VD = dyn_cast<VarDecl>(Val: Node->getDecl())) {
26693 VD->addAttr(A);
26694 DeclVector.push_back(Elt: VD);
26695 }
26696 }
26697 /// A function that iterates across each of the Expr's children.
26698 void VisitExpr(Expr *Ex) {
26699 for (auto *Child : Ex->children()) {
26700 Visit(S: Child);
26701 }
26702 }
26703 /// A function that keeps a record of all the Decls that are variables, has
26704 /// OMPDeclareTargetDeclAttr, and has global storage in the DeclVector. Pop
26705 /// each Decl one at a time and use the inherited 'visit' functions to look
26706 /// for DeclRefExpr.
26707 void declareTargetInitializer(Decl *TD) {
26708 A = TD->getAttr<OMPDeclareTargetDeclAttr>();
26709 DeclVector.push_back(Elt: cast<VarDecl>(Val: TD));
26710 llvm::SmallDenseSet<Decl *> Visited;
26711 while (!DeclVector.empty()) {
26712 VarDecl *TargetVarDecl = DeclVector.pop_back_val();
26713 if (!Visited.insert(V: TargetVarDecl).second)
26714 continue;
26715
26716 if (TargetVarDecl->hasAttr<OMPDeclareTargetDeclAttr>() &&
26717 TargetVarDecl->hasInit() && TargetVarDecl->hasGlobalStorage()) {
26718 if (Expr *Ex = TargetVarDecl->getInit())
26719 Visit(S: Ex);
26720 }
26721 }
26722 }
26723};
26724
26725/// Adding OMPDeclareTargetDeclAttr to variables with static storage
26726/// duration that are referenced in the initializer expression list of
26727/// variables with static storage duration in declare target directive.
26728void SemaOpenMP::ActOnOpenMPDeclareTargetInitializer(Decl *TargetDecl) {
26729 GlobalDeclRefChecker Checker;
26730 if (isa<VarDecl>(Val: TargetDecl))
26731 Checker.declareTargetInitializer(TD: TargetDecl);
26732}
26733
26734OMPClause *SemaOpenMP::ActOnOpenMPToClause(
26735 ArrayRef<OpenMPMotionModifierKind> MotionModifiers,
26736 ArrayRef<SourceLocation> MotionModifiersLoc, Expr *IteratorExpr,
26737 CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId,
26738 SourceLocation ColonLoc, ArrayRef<Expr *> VarList,
26739 const OMPVarListLocTy &Locs, ArrayRef<Expr *> UnresolvedMappers) {
26740 OpenMPMotionModifierKind Modifiers[] = {OMPC_MOTION_MODIFIER_unknown,
26741 OMPC_MOTION_MODIFIER_unknown,
26742 OMPC_MOTION_MODIFIER_unknown};
26743 SourceLocation ModifiersLoc[NumberOfOMPMotionModifiers];
26744
26745 // Process motion-modifiers, flag errors for duplicate modifiers.
26746 unsigned Count = 0;
26747 for (unsigned I = 0, E = MotionModifiers.size(); I < E; ++I) {
26748 if (MotionModifiers[I] != OMPC_MOTION_MODIFIER_unknown &&
26749 llvm::is_contained(Range&: Modifiers, Element: MotionModifiers[I])) {
26750 Diag(Loc: MotionModifiersLoc[I], DiagID: diag::err_omp_duplicate_motion_modifier);
26751 continue;
26752 }
26753 assert(Count < NumberOfOMPMotionModifiers &&
26754 "Modifiers exceed the allowed number of motion modifiers");
26755 Modifiers[Count] = MotionModifiers[I];
26756 ModifiersLoc[Count] = MotionModifiersLoc[I];
26757 ++Count;
26758 }
26759
26760 MappableVarListInfo MVLI(VarList);
26761 checkMappableExpressionList(SemaRef, DSAStack, CKind: OMPC_to, MVLI, StartLoc: Locs.StartLoc,
26762 MapperIdScopeSpec, MapperId, UnresolvedMappers);
26763 if (MVLI.ProcessedVarList.empty())
26764 return nullptr;
26765 if (IteratorExpr)
26766 if (auto *DRE = dyn_cast<DeclRefExpr>(Val: IteratorExpr))
26767 if (auto *VD = dyn_cast<VarDecl>(Val: DRE->getDecl()))
26768 DSAStack->addIteratorVarDecl(VD);
26769 return OMPToClause::Create(
26770 C: getASTContext(), Locs, Vars: MVLI.ProcessedVarList, Declarations: MVLI.VarBaseDeclarations,
26771 ComponentLists: MVLI.VarComponents, UDMapperRefs: MVLI.UDMapperList, IteratorModifier: IteratorExpr, MotionModifiers: Modifiers,
26772 MotionModifiersLoc: ModifiersLoc, UDMQualifierLoc: MapperIdScopeSpec.getWithLocInContext(Context&: getASTContext()),
26773 MapperId);
26774}
26775
26776OMPClause *SemaOpenMP::ActOnOpenMPFromClause(
26777 ArrayRef<OpenMPMotionModifierKind> MotionModifiers,
26778 ArrayRef<SourceLocation> MotionModifiersLoc, Expr *IteratorExpr,
26779 CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId,
26780 SourceLocation ColonLoc, ArrayRef<Expr *> VarList,
26781 const OMPVarListLocTy &Locs, ArrayRef<Expr *> UnresolvedMappers) {
26782 OpenMPMotionModifierKind Modifiers[] = {OMPC_MOTION_MODIFIER_unknown,
26783 OMPC_MOTION_MODIFIER_unknown,
26784 OMPC_MOTION_MODIFIER_unknown};
26785 SourceLocation ModifiersLoc[NumberOfOMPMotionModifiers];
26786
26787 // Process motion-modifiers, flag errors for duplicate modifiers.
26788 unsigned Count = 0;
26789 for (unsigned I = 0, E = MotionModifiers.size(); I < E; ++I) {
26790 if (MotionModifiers[I] != OMPC_MOTION_MODIFIER_unknown &&
26791 llvm::is_contained(Range&: Modifiers, Element: MotionModifiers[I])) {
26792 Diag(Loc: MotionModifiersLoc[I], DiagID: diag::err_omp_duplicate_motion_modifier);
26793 continue;
26794 }
26795 assert(Count < NumberOfOMPMotionModifiers &&
26796 "Modifiers exceed the allowed number of motion modifiers");
26797 Modifiers[Count] = MotionModifiers[I];
26798 ModifiersLoc[Count] = MotionModifiersLoc[I];
26799 ++Count;
26800 }
26801
26802 MappableVarListInfo MVLI(VarList);
26803 checkMappableExpressionList(SemaRef, DSAStack, CKind: OMPC_from, MVLI, StartLoc: Locs.StartLoc,
26804 MapperIdScopeSpec, MapperId, UnresolvedMappers);
26805 if (MVLI.ProcessedVarList.empty())
26806 return nullptr;
26807 if (IteratorExpr)
26808 if (auto *DRE = dyn_cast<DeclRefExpr>(Val: IteratorExpr))
26809 if (auto *VD = dyn_cast<VarDecl>(Val: DRE->getDecl()))
26810 DSAStack->addIteratorVarDecl(VD);
26811 return OMPFromClause::Create(
26812 C: getASTContext(), Locs, Vars: MVLI.ProcessedVarList, Declarations: MVLI.VarBaseDeclarations,
26813 ComponentLists: MVLI.VarComponents, UDMapperRefs: MVLI.UDMapperList, IteratorExpr, MotionModifiers: Modifiers,
26814 MotionModifiersLoc: ModifiersLoc, UDMQualifierLoc: MapperIdScopeSpec.getWithLocInContext(Context&: getASTContext()),
26815 MapperId);
26816}
26817
26818OMPClause *SemaOpenMP::ActOnOpenMPUseDevicePtrClause(
26819 ArrayRef<Expr *> VarList, const OMPVarListLocTy &Locs,
26820 OpenMPUseDevicePtrFallbackModifier FallbackModifier,
26821 SourceLocation FallbackModifierLoc) {
26822 MappableVarListInfo MVLI(VarList);
26823 SmallVector<Expr *, 8> PrivateCopies;
26824 SmallVector<Expr *, 8> Inits;
26825
26826 for (Expr *RefExpr : VarList) {
26827 assert(RefExpr && "NULL expr in OpenMP use_device_ptr clause.");
26828 SourceLocation ELoc;
26829 SourceRange ERange;
26830 Expr *SimpleRefExpr = RefExpr;
26831 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange);
26832 if (Res.second) {
26833 // It will be analyzed later.
26834 MVLI.ProcessedVarList.push_back(Elt: RefExpr);
26835 PrivateCopies.push_back(Elt: nullptr);
26836 Inits.push_back(Elt: nullptr);
26837 }
26838 ValueDecl *D = Res.first;
26839 if (!D)
26840 continue;
26841
26842 QualType Type = D->getType();
26843 Type = Type.getNonReferenceType().getUnqualifiedType();
26844
26845 auto *VD = dyn_cast<VarDecl>(Val: D);
26846
26847 // Item should be a pointer or reference to pointer.
26848 if (!Type->isPointerType()) {
26849 Diag(Loc: ELoc, DiagID: diag::err_omp_usedeviceptr_not_a_pointer)
26850 << 0 << RefExpr->getSourceRange();
26851 continue;
26852 }
26853
26854 // Build the private variable and the expression that refers to it.
26855 auto VDPrivate =
26856 buildVarDecl(SemaRef, Loc: ELoc, Type, Name: D->getName(),
26857 Attrs: D->hasAttrs() ? &D->getAttrs() : nullptr,
26858 OrigRef: VD ? cast<DeclRefExpr>(Val: SimpleRefExpr) : nullptr);
26859 if (VDPrivate->isInvalidDecl())
26860 continue;
26861
26862 SemaRef.CurContext->addDecl(D: VDPrivate);
26863 DeclRefExpr *VDPrivateRefExpr = buildDeclRefExpr(
26864 S&: SemaRef, D: VDPrivate, Ty: RefExpr->getType().getUnqualifiedType(), Loc: ELoc);
26865
26866 // Add temporary variable to initialize the private copy of the pointer.
26867 VarDecl *VDInit =
26868 buildVarDecl(SemaRef, Loc: RefExpr->getExprLoc(), Type, Name: ".devptr.temp");
26869 DeclRefExpr *VDInitRefExpr = buildDeclRefExpr(
26870 S&: SemaRef, D: VDInit, Ty: RefExpr->getType(), Loc: RefExpr->getExprLoc());
26871 SemaRef.AddInitializerToDecl(
26872 dcl: VDPrivate, init: SemaRef.DefaultLvalueConversion(E: VDInitRefExpr).get(),
26873 /*DirectInit=*/false);
26874
26875 // If required, build a capture to implement the privatization initialized
26876 // with the current list item value.
26877 DeclRefExpr *Ref = nullptr;
26878 if (!VD)
26879 Ref = buildCapture(S&: SemaRef, D, CaptureExpr: SimpleRefExpr, /*WithInit=*/true);
26880 MVLI.ProcessedVarList.push_back(Elt: VD ? RefExpr->IgnoreParens() : Ref);
26881 PrivateCopies.push_back(Elt: VDPrivateRefExpr);
26882 Inits.push_back(Elt: VDInitRefExpr);
26883
26884 // We need to add a data sharing attribute for this variable to make sure it
26885 // is correctly captured. A variable that shows up in a use_device_ptr has
26886 // similar properties of a first private variable.
26887 DSAStack->addDSA(D, E: RefExpr->IgnoreParens(), A: OMPC_firstprivate, PrivateCopy: Ref);
26888
26889 // Create a mappable component for the list item. List items in this clause
26890 // only need a component.
26891 MVLI.VarBaseDeclarations.push_back(Elt: D);
26892 MVLI.VarComponents.resize(N: MVLI.VarComponents.size() + 1);
26893 MVLI.VarComponents.back().emplace_back(Args&: SimpleRefExpr, Args&: D,
26894 /*IsNonContiguous=*/Args: false);
26895 }
26896
26897 if (MVLI.ProcessedVarList.empty())
26898 return nullptr;
26899
26900 return OMPUseDevicePtrClause::Create(
26901 C: getASTContext(), Locs, Vars: MVLI.ProcessedVarList, PrivateVars: PrivateCopies, Inits,
26902 Declarations: MVLI.VarBaseDeclarations, ComponentLists: MVLI.VarComponents, FallbackModifier,
26903 FallbackModifierLoc);
26904}
26905
26906OMPClause *
26907SemaOpenMP::ActOnOpenMPUseDeviceAddrClause(ArrayRef<Expr *> VarList,
26908 const OMPVarListLocTy &Locs) {
26909 MappableVarListInfo MVLI(VarList);
26910
26911 for (Expr *RefExpr : VarList) {
26912 assert(RefExpr && "NULL expr in OpenMP use_device_addr clause.");
26913 SourceLocation ELoc;
26914 SourceRange ERange;
26915 Expr *SimpleRefExpr = RefExpr;
26916 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange,
26917 /*AllowArraySection=*/true,
26918 /*AllowAssumedSizeArray=*/true);
26919 if (Res.second) {
26920 // It will be analyzed later.
26921 MVLI.ProcessedVarList.push_back(Elt: RefExpr);
26922 }
26923 ValueDecl *D = Res.first;
26924 if (!D)
26925 continue;
26926 auto *VD = dyn_cast<VarDecl>(Val: D);
26927
26928 // If required, build a capture to implement the privatization initialized
26929 // with the current list item value.
26930 DeclRefExpr *Ref = nullptr;
26931 if (!VD)
26932 Ref = buildCapture(S&: SemaRef, D, CaptureExpr: SimpleRefExpr, /*WithInit=*/true);
26933 MVLI.ProcessedVarList.push_back(Elt: VD ? RefExpr->IgnoreParens() : Ref);
26934
26935 // We need to add a data sharing attribute for this variable to make sure it
26936 // is correctly captured. A variable that shows up in a use_device_addr has
26937 // similar properties of a first private variable.
26938 DSAStack->addDSA(D, E: RefExpr->IgnoreParens(), A: OMPC_firstprivate, PrivateCopy: Ref);
26939
26940 // Use the map-like approach to fully populate VarComponents
26941 OMPClauseMappableExprCommon::MappableExprComponentList CurComponents;
26942
26943 const Expr *BE = checkMapClauseExpressionBase(
26944 SemaRef, E: RefExpr, CurComponents, CKind: OMPC_use_device_addr,
26945 DSAStack->getCurrentDirective(),
26946 /*NoDiagnose=*/false);
26947
26948 if (!BE)
26949 continue;
26950
26951 assert(!CurComponents.empty() &&
26952 "use_device_addr clause expression with no components!");
26953
26954 // OpenMP use_device_addr: If a list item is an array section, the array
26955 // base must be a base language identifier. We caught the cases where
26956 // the array-section has a base-variable in getPrivateItem. e.g.
26957 // struct S {
26958 // int a[10];
26959 // }; S s1;
26960 // ... use_device_addr(s1.a[0]) // not ok, caught already
26961 //
26962 // But we still neeed to verify that the base-pointer is also a
26963 // base-language identifier, and catch cases like:
26964 // int *pa[10]; *p;
26965 // ... use_device_addr(pa[1][2]) // not ok, base-pointer is pa[1]
26966 // ... use_device_addr(p[1]) // ok
26967 // ... use_device_addr(this->p[1]) // ok
26968 auto AttachPtrResult = OMPClauseMappableExprCommon::findAttachPtrExpr(
26969 Components: CurComponents, DSAStack->getCurrentDirective());
26970 const Expr *AttachPtrExpr = AttachPtrResult.first;
26971
26972 if (AttachPtrExpr) {
26973 const Expr *BaseExpr = AttachPtrExpr->IgnoreParenImpCasts();
26974 bool IsValidBase = false;
26975
26976 if (isa<DeclRefExpr>(Val: BaseExpr))
26977 IsValidBase = true;
26978 else if (const auto *ME = dyn_cast<MemberExpr>(Val: BaseExpr);
26979 ME && isa<CXXThisExpr>(Val: ME->getBase()->IgnoreParenImpCasts()))
26980 IsValidBase = true;
26981
26982 if (!IsValidBase) {
26983 SemaRef.Diag(Loc: ELoc,
26984 DiagID: diag::err_omp_expected_base_pointer_var_name_member_expr)
26985 << (SemaRef.getCurrentThisType().isNull() ? 0 : 1)
26986 << AttachPtrExpr->getSourceRange();
26987 continue;
26988 }
26989 }
26990
26991 // Get the declaration from the components
26992 ValueDecl *CurDeclaration = CurComponents.back().getAssociatedDeclaration();
26993 assert((isa<CXXThisExpr>(BE) || CurDeclaration) &&
26994 "Unexpected null decl for use_device_addr clause.");
26995
26996 MVLI.VarBaseDeclarations.push_back(Elt: CurDeclaration);
26997 MVLI.VarComponents.resize(N: MVLI.VarComponents.size() + 1);
26998 MVLI.VarComponents.back().append(in_start: CurComponents.begin(),
26999 in_end: CurComponents.end());
27000 }
27001
27002 if (MVLI.ProcessedVarList.empty())
27003 return nullptr;
27004
27005 return OMPUseDeviceAddrClause::Create(
27006 C: getASTContext(), Locs, Vars: MVLI.ProcessedVarList, Declarations: MVLI.VarBaseDeclarations,
27007 ComponentLists: MVLI.VarComponents);
27008}
27009
27010OMPClause *
27011SemaOpenMP::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList,
27012 const OMPVarListLocTy &Locs) {
27013 MappableVarListInfo MVLI(VarList);
27014 for (Expr *RefExpr : VarList) {
27015 assert(RefExpr && "NULL expr in OpenMP is_device_ptr clause.");
27016 SourceLocation ELoc;
27017 SourceRange ERange;
27018 Expr *SimpleRefExpr = RefExpr;
27019 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange);
27020 if (Res.second) {
27021 // It will be analyzed later.
27022 MVLI.ProcessedVarList.push_back(Elt: RefExpr);
27023 }
27024 ValueDecl *D = Res.first;
27025 if (!D)
27026 continue;
27027
27028 QualType Type = D->getType();
27029 // item should be a pointer or array or reference to pointer or array
27030 if (!Type.getNonReferenceType()->isPointerType() &&
27031 !Type.getNonReferenceType()->isArrayType()) {
27032 Diag(Loc: ELoc, DiagID: diag::err_omp_argument_type_isdeviceptr)
27033 << 0 << RefExpr->getSourceRange();
27034 continue;
27035 }
27036
27037 // Check if the declaration in the clause does not show up in any data
27038 // sharing attribute.
27039 DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false);
27040 if (isOpenMPPrivate(Kind: DVar.CKind)) {
27041 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
27042 Diag(Loc: ELoc, DiagID: diag::err_omp_variable_in_given_clause_and_dsa)
27043 << getOpenMPClauseNameForDiag(C: DVar.CKind)
27044 << getOpenMPClauseNameForDiag(C: OMPC_is_device_ptr)
27045 << getOpenMPDirectiveName(DSAStack->getCurrentDirective(),
27046 V: OMPVersion);
27047 reportOriginalDsa(SemaRef, DSAStack, D, DVar);
27048 continue;
27049 }
27050
27051 const Expr *ConflictExpr;
27052 if (DSAStack->checkMappableExprComponentListsForDecl(
27053 VD: D, /*CurrentRegionOnly=*/true,
27054 Check: [&ConflictExpr](
27055 OMPClauseMappableExprCommon::MappableExprComponentListRef R,
27056 OpenMPClauseKind) -> bool {
27057 ConflictExpr = R.front().getAssociatedExpression();
27058 return true;
27059 })) {
27060 Diag(Loc: ELoc, DiagID: diag::err_omp_map_shared_storage) << RefExpr->getSourceRange();
27061 Diag(Loc: ConflictExpr->getExprLoc(), DiagID: diag::note_used_here)
27062 << ConflictExpr->getSourceRange();
27063 continue;
27064 }
27065
27066 // Store the components in the stack so that they can be used to check
27067 // against other clauses later on.
27068 OMPClauseMappableExprCommon::MappableComponent MC(
27069 SimpleRefExpr, D, /*IsNonContiguous=*/false);
27070 DSAStack->addMappableExpressionComponents(
27071 VD: D, Components: MC, /*WhereFoundClauseKind=*/OMPC_is_device_ptr);
27072
27073 // Record the expression we've just processed.
27074 MVLI.ProcessedVarList.push_back(Elt: SimpleRefExpr);
27075
27076 // Create a mappable component for the list item. List items in this clause
27077 // only need a component. We use a null declaration to signal fields in
27078 // 'this'.
27079 assert((isa<DeclRefExpr>(SimpleRefExpr) ||
27080 isa<CXXThisExpr>(cast<MemberExpr>(SimpleRefExpr)->getBase())) &&
27081 "Unexpected device pointer expression!");
27082 MVLI.VarBaseDeclarations.push_back(
27083 Elt: isa<DeclRefExpr>(Val: SimpleRefExpr) ? D : nullptr);
27084 MVLI.VarComponents.resize(N: MVLI.VarComponents.size() + 1);
27085 MVLI.VarComponents.back().push_back(Elt: MC);
27086 }
27087
27088 if (MVLI.ProcessedVarList.empty())
27089 return nullptr;
27090
27091 return OMPIsDevicePtrClause::Create(
27092 C: getASTContext(), Locs, Vars: MVLI.ProcessedVarList, Declarations: MVLI.VarBaseDeclarations,
27093 ComponentLists: MVLI.VarComponents);
27094}
27095
27096OMPClause *
27097SemaOpenMP::ActOnOpenMPHasDeviceAddrClause(ArrayRef<Expr *> VarList,
27098 const OMPVarListLocTy &Locs) {
27099 MappableVarListInfo MVLI(VarList);
27100 for (Expr *RefExpr : VarList) {
27101 assert(RefExpr && "NULL expr in OpenMP has_device_addr clause.");
27102 SourceLocation ELoc;
27103 SourceRange ERange;
27104 Expr *SimpleRefExpr = RefExpr;
27105 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange,
27106 /*AllowArraySection=*/true);
27107 if (Res.second) {
27108 // It will be analyzed later.
27109 MVLI.ProcessedVarList.push_back(Elt: RefExpr);
27110 }
27111 ValueDecl *D = Res.first;
27112 if (!D)
27113 continue;
27114
27115 // Check if the declaration in the clause does not show up in any data
27116 // sharing attribute.
27117 DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false);
27118 if (isOpenMPPrivate(Kind: DVar.CKind)) {
27119 llvm::omp::Version OMPVersion = getLangOpts().getOpenMPVersion();
27120 Diag(Loc: ELoc, DiagID: diag::err_omp_variable_in_given_clause_and_dsa)
27121 << getOpenMPClauseNameForDiag(C: DVar.CKind)
27122 << getOpenMPClauseNameForDiag(C: OMPC_has_device_addr)
27123 << getOpenMPDirectiveName(DSAStack->getCurrentDirective(),
27124 V: OMPVersion);
27125 reportOriginalDsa(SemaRef, DSAStack, D, DVar);
27126 continue;
27127 }
27128
27129 const Expr *ConflictExpr;
27130 if (DSAStack->checkMappableExprComponentListsForDecl(
27131 VD: D, /*CurrentRegionOnly=*/true,
27132 Check: [&ConflictExpr](
27133 OMPClauseMappableExprCommon::MappableExprComponentListRef R,
27134 OpenMPClauseKind) -> bool {
27135 ConflictExpr = R.front().getAssociatedExpression();
27136 return true;
27137 })) {
27138 Diag(Loc: ELoc, DiagID: diag::err_omp_map_shared_storage) << RefExpr->getSourceRange();
27139 Diag(Loc: ConflictExpr->getExprLoc(), DiagID: diag::note_used_here)
27140 << ConflictExpr->getSourceRange();
27141 continue;
27142 }
27143
27144 // Store the components in the stack so that they can be used to check
27145 // against other clauses later on.
27146 Expr *Component = SimpleRefExpr;
27147 auto *VD = dyn_cast<VarDecl>(Val: D);
27148 if (VD && (isa<ArraySectionExpr>(Val: RefExpr->IgnoreParenImpCasts()) ||
27149 isa<ArraySubscriptExpr>(Val: RefExpr->IgnoreParenImpCasts())))
27150 Component =
27151 SemaRef.DefaultFunctionArrayLvalueConversion(E: SimpleRefExpr).get();
27152 OMPClauseMappableExprCommon::MappableComponent MC(
27153 Component, D, /*IsNonContiguous=*/false);
27154 DSAStack->addMappableExpressionComponents(
27155 VD: D, Components: MC, /*WhereFoundClauseKind=*/OMPC_has_device_addr);
27156
27157 // Record the expression we've just processed.
27158 if (!VD && !SemaRef.CurContext->isDependentContext()) {
27159 DeclRefExpr *Ref =
27160 buildCapture(S&: SemaRef, D, CaptureExpr: SimpleRefExpr, /*WithInit=*/true);
27161 assert(Ref && "has_device_addr capture failed");
27162 MVLI.ProcessedVarList.push_back(Elt: Ref);
27163 } else
27164 MVLI.ProcessedVarList.push_back(Elt: RefExpr->IgnoreParens());
27165
27166 // Create a mappable component for the list item. List items in this clause
27167 // only need a component. We use a null declaration to signal fields in
27168 // 'this'.
27169 assert((isa<DeclRefExpr>(SimpleRefExpr) ||
27170 isa<CXXThisExpr>(cast<MemberExpr>(SimpleRefExpr)->getBase())) &&
27171 "Unexpected device pointer expression!");
27172 MVLI.VarBaseDeclarations.push_back(
27173 Elt: isa<DeclRefExpr>(Val: SimpleRefExpr) ? D : nullptr);
27174 MVLI.VarComponents.resize(N: MVLI.VarComponents.size() + 1);
27175 MVLI.VarComponents.back().push_back(Elt: MC);
27176 }
27177
27178 if (MVLI.ProcessedVarList.empty())
27179 return nullptr;
27180
27181 return OMPHasDeviceAddrClause::Create(
27182 C: getASTContext(), Locs, Vars: MVLI.ProcessedVarList, Declarations: MVLI.VarBaseDeclarations,
27183 ComponentLists: MVLI.VarComponents);
27184}
27185
27186OMPClause *SemaOpenMP::ActOnOpenMPAllocateClause(
27187 Expr *Allocator, Expr *Alignment,
27188 OpenMPAllocateClauseModifier FirstAllocateModifier,
27189 SourceLocation FirstAllocateModifierLoc,
27190 OpenMPAllocateClauseModifier SecondAllocateModifier,
27191 SourceLocation SecondAllocateModifierLoc, ArrayRef<Expr *> VarList,
27192 SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
27193 SourceLocation EndLoc) {
27194 if (Allocator) {
27195 // Allocator expression is dependent - skip it for now and build the
27196 // allocator when instantiated.
27197 bool AllocDependent =
27198 (Allocator->isTypeDependent() || Allocator->isValueDependent() ||
27199 Allocator->isInstantiationDependent() ||
27200 Allocator->containsUnexpandedParameterPack());
27201 if (!AllocDependent) {
27202 // OpenMP [2.11.4 allocate Clause, Description]
27203 // allocator is an expression of omp_allocator_handle_t type.
27204 if (!findOMPAllocatorHandleT(S&: SemaRef, Loc: Allocator->getExprLoc(), DSAStack))
27205 return nullptr;
27206
27207 ExprResult AllocatorRes = SemaRef.DefaultLvalueConversion(E: Allocator);
27208 if (AllocatorRes.isInvalid())
27209 return nullptr;
27210 AllocatorRes = SemaRef.PerformImplicitConversion(
27211 From: AllocatorRes.get(), DSAStack->getOMPAllocatorHandleT(),
27212 Action: AssignmentAction::Initializing,
27213 /*AllowExplicit=*/true);
27214 if (AllocatorRes.isInvalid())
27215 return nullptr;
27216 Allocator = AllocatorRes.isUsable() ? AllocatorRes.get() : nullptr;
27217 }
27218 } else {
27219 // OpenMP 5.0, 2.11.4 allocate Clause, Restrictions.
27220 // allocate clauses that appear on a target construct or on constructs in a
27221 // target region must specify an allocator expression unless a requires
27222 // directive with the dynamic_allocators clause is present in the same
27223 // compilation unit.
27224 if (getLangOpts().OpenMPIsTargetDevice &&
27225 !DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>())
27226 SemaRef.targetDiag(Loc: StartLoc, DiagID: diag::err_expected_allocator_expression);
27227 }
27228 if (Alignment) {
27229 bool AlignmentDependent = Alignment->isTypeDependent() ||
27230 Alignment->isValueDependent() ||
27231 Alignment->isInstantiationDependent() ||
27232 Alignment->containsUnexpandedParameterPack();
27233 if (!AlignmentDependent) {
27234 ExprResult AlignResult =
27235 VerifyPositiveIntegerConstantInClause(E: Alignment, CKind: OMPC_allocate);
27236 Alignment = AlignResult.isUsable() ? AlignResult.get() : nullptr;
27237 }
27238 }
27239 // Analyze and build list of variables.
27240 SmallVector<Expr *, 8> Vars;
27241 for (Expr *RefExpr : VarList) {
27242 assert(RefExpr && "NULL expr in OpenMP allocate clause.");
27243 SourceLocation ELoc;
27244 SourceRange ERange;
27245 Expr *SimpleRefExpr = RefExpr;
27246 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange);
27247 if (Res.second) {
27248 // It will be analyzed later.
27249 Vars.push_back(Elt: RefExpr);
27250 }
27251 ValueDecl *D = Res.first;
27252 if (!D)
27253 continue;
27254
27255 auto *VD = dyn_cast<VarDecl>(Val: D);
27256 DeclRefExpr *Ref = nullptr;
27257 if (!VD && !SemaRef.CurContext->isDependentContext())
27258 Ref = buildCapture(S&: SemaRef, D, CaptureExpr: SimpleRefExpr, /*WithInit=*/false);
27259 Vars.push_back(Elt: (VD || SemaRef.CurContext->isDependentContext())
27260 ? RefExpr->IgnoreParens()
27261 : Ref);
27262 }
27263
27264 if (Vars.empty())
27265 return nullptr;
27266
27267 if (Allocator)
27268 DSAStack->addInnerAllocatorExpr(E: Allocator);
27269
27270 return OMPAllocateClause::Create(
27271 C: getASTContext(), StartLoc, LParenLoc, Allocator, Alignment, ColonLoc,
27272 Modifier1: FirstAllocateModifier, Modifier1Loc: FirstAllocateModifierLoc, Modifier2: SecondAllocateModifier,
27273 Modifier2Loc: SecondAllocateModifierLoc, EndLoc, VL: Vars);
27274}
27275
27276OMPClause *SemaOpenMP::ActOnOpenMPNontemporalClause(ArrayRef<Expr *> VarList,
27277 SourceLocation StartLoc,
27278 SourceLocation LParenLoc,
27279 SourceLocation EndLoc) {
27280 SmallVector<Expr *, 8> Vars;
27281 for (Expr *RefExpr : VarList) {
27282 assert(RefExpr && "NULL expr in OpenMP nontemporal clause.");
27283 SourceLocation ELoc;
27284 SourceRange ERange;
27285 Expr *SimpleRefExpr = RefExpr;
27286 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange);
27287 if (Res.second)
27288 // It will be analyzed later.
27289 Vars.push_back(Elt: RefExpr);
27290 ValueDecl *D = Res.first;
27291 if (!D)
27292 continue;
27293
27294 // OpenMP 5.0, 2.9.3.1 simd Construct, Restrictions.
27295 // A list-item cannot appear in more than one nontemporal clause.
27296 if (const Expr *PrevRef =
27297 DSAStack->addUniqueNontemporal(D, NewDE: SimpleRefExpr)) {
27298 Diag(Loc: ELoc, DiagID: diag::err_omp_used_in_clause_twice)
27299 << 0 << getOpenMPClauseNameForDiag(C: OMPC_nontemporal) << ERange;
27300 Diag(Loc: PrevRef->getExprLoc(), DiagID: diag::note_omp_explicit_dsa)
27301 << getOpenMPClauseNameForDiag(C: OMPC_nontemporal);
27302 continue;
27303 }
27304
27305 Vars.push_back(Elt: RefExpr);
27306 }
27307
27308 if (Vars.empty())
27309 return nullptr;
27310
27311 return OMPNontemporalClause::Create(C: getASTContext(), StartLoc, LParenLoc,
27312 EndLoc, VL: Vars);
27313}
27314
27315StmtResult SemaOpenMP::ActOnOpenMPScopeDirective(ArrayRef<OMPClause *> Clauses,
27316 Stmt *AStmt,
27317 SourceLocation StartLoc,
27318 SourceLocation EndLoc) {
27319 if (!AStmt)
27320 return StmtError();
27321
27322 SemaRef.setFunctionHasBranchProtectedScope();
27323
27324 return OMPScopeDirective::Create(C: getASTContext(), StartLoc, EndLoc, Clauses,
27325 AssociatedStmt: AStmt);
27326}
27327
27328OMPClause *SemaOpenMP::ActOnOpenMPInclusiveClause(ArrayRef<Expr *> VarList,
27329 SourceLocation StartLoc,
27330 SourceLocation LParenLoc,
27331 SourceLocation EndLoc) {
27332 SmallVector<Expr *, 8> Vars;
27333 for (Expr *RefExpr : VarList) {
27334 assert(RefExpr && "NULL expr in OpenMP inclusive clause.");
27335 SourceLocation ELoc;
27336 SourceRange ERange;
27337 Expr *SimpleRefExpr = RefExpr;
27338 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange,
27339 /*AllowArraySection=*/true);
27340 if (Res.second)
27341 // It will be analyzed later.
27342 Vars.push_back(Elt: RefExpr);
27343 ValueDecl *D = Res.first;
27344 if (!D)
27345 continue;
27346
27347 const DSAStackTy::DSAVarData DVar =
27348 DSAStack->getTopDSA(D, /*FromParent=*/true);
27349 // OpenMP 5.0, 2.9.6, scan Directive, Restrictions.
27350 // A list item that appears in the inclusive or exclusive clause must appear
27351 // in a reduction clause with the inscan modifier on the enclosing
27352 // worksharing-loop, worksharing-loop SIMD, or simd construct.
27353 if (DVar.CKind != OMPC_reduction || DVar.Modifier != OMPC_REDUCTION_inscan)
27354 Diag(Loc: ELoc, DiagID: diag::err_omp_inclusive_exclusive_not_reduction)
27355 << RefExpr->getSourceRange();
27356
27357 if (DSAStack->getParentDirective() != OMPD_unknown)
27358 DSAStack->markDeclAsUsedInScanDirective(D);
27359 Vars.push_back(Elt: RefExpr);
27360 }
27361
27362 if (Vars.empty())
27363 return nullptr;
27364
27365 return OMPInclusiveClause::Create(C: getASTContext(), StartLoc, LParenLoc,
27366 EndLoc, VL: Vars);
27367}
27368
27369OMPClause *SemaOpenMP::ActOnOpenMPExclusiveClause(ArrayRef<Expr *> VarList,
27370 SourceLocation StartLoc,
27371 SourceLocation LParenLoc,
27372 SourceLocation EndLoc) {
27373 SmallVector<Expr *, 8> Vars;
27374 for (Expr *RefExpr : VarList) {
27375 assert(RefExpr && "NULL expr in OpenMP exclusive clause.");
27376 SourceLocation ELoc;
27377 SourceRange ERange;
27378 Expr *SimpleRefExpr = RefExpr;
27379 auto Res = getPrivateItem(S&: SemaRef, RefExpr&: SimpleRefExpr, ELoc, ERange,
27380 /*AllowArraySection=*/true);
27381 if (Res.second)
27382 // It will be analyzed later.
27383 Vars.push_back(Elt: RefExpr);
27384 ValueDecl *D = Res.first;
27385 if (!D)
27386 continue;
27387
27388 OpenMPDirectiveKind ParentDirective = DSAStack->getParentDirective();
27389 DSAStackTy::DSAVarData DVar;
27390 if (ParentDirective != OMPD_unknown)
27391 DVar = DSAStack->getTopDSA(D, /*FromParent=*/true);
27392 // OpenMP 5.0, 2.9.6, scan Directive, Restrictions.
27393 // A list item that appears in the inclusive or exclusive clause must appear
27394 // in a reduction clause with the inscan modifier on the enclosing
27395 // worksharing-loop, worksharing-loop SIMD, or simd construct.
27396 if (ParentDirective == OMPD_unknown || DVar.CKind != OMPC_reduction ||
27397 DVar.Modifier != OMPC_REDUCTION_inscan) {
27398 Diag(Loc: ELoc, DiagID: diag::err_omp_inclusive_exclusive_not_reduction)
27399 << RefExpr->getSourceRange();
27400 } else {
27401 DSAStack->markDeclAsUsedInScanDirective(D);
27402 }
27403 Vars.push_back(Elt: RefExpr);
27404 }
27405
27406 if (Vars.empty())
27407 return nullptr;
27408
27409 return OMPExclusiveClause::Create(C: getASTContext(), StartLoc, LParenLoc,
27410 EndLoc, VL: Vars);
27411}
27412
27413/// Tries to find omp_alloctrait_t type.
27414static bool findOMPAlloctraitT(Sema &S, SourceLocation Loc, DSAStackTy *Stack) {
27415 QualType OMPAlloctraitT = Stack->getOMPAlloctraitT();
27416 if (!OMPAlloctraitT.isNull())
27417 return true;
27418 IdentifierInfo &II = S.PP.getIdentifierTable().get(Name: "omp_alloctrait_t");
27419 ParsedType PT = S.getTypeName(II, NameLoc: Loc, S: S.getCurScope());
27420 if (!PT.getAsOpaquePtr() || PT.get().isNull()) {
27421 S.Diag(Loc, DiagID: diag::err_omp_implied_type_not_found) << "omp_alloctrait_t";
27422 return false;
27423 }
27424 Stack->setOMPAlloctraitT(PT.get());
27425 return true;
27426}
27427
27428OMPClause *SemaOpenMP::ActOnOpenMPUsesAllocatorClause(
27429 SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc,
27430 ArrayRef<UsesAllocatorsData> Data) {
27431 ASTContext &Context = getASTContext();
27432 // OpenMP [2.12.5, target Construct]
27433 // allocator is an identifier of omp_allocator_handle_t type.
27434 if (!findOMPAllocatorHandleT(S&: SemaRef, Loc: StartLoc, DSAStack))
27435 return nullptr;
27436 // OpenMP [2.12.5, target Construct]
27437 // allocator-traits-array is an identifier of const omp_alloctrait_t * type.
27438 if (llvm::any_of(
27439 Range&: Data,
27440 P: [](const UsesAllocatorsData &D) { return D.AllocatorTraits; }) &&
27441 !findOMPAlloctraitT(S&: SemaRef, Loc: StartLoc, DSAStack))
27442 return nullptr;
27443 llvm::SmallPtrSet<CanonicalDeclPtr<Decl>, 4> PredefinedAllocators;
27444 for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
27445 auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
27446 StringRef Allocator =
27447 OMPAllocateDeclAttr::ConvertAllocatorTypeTyToStr(Val: AllocatorKind);
27448 DeclarationName AllocatorName = &Context.Idents.get(Name: Allocator);
27449 PredefinedAllocators.insert(Ptr: SemaRef.LookupSingleName(
27450 S: SemaRef.TUScope, Name: AllocatorName, Loc: StartLoc, NameKind: Sema::LookupAnyName));
27451 }
27452
27453 SmallVector<OMPUsesAllocatorsClause::Data, 4> NewData;
27454 for (const UsesAllocatorsData &D : Data) {
27455 Expr *AllocatorExpr = nullptr;
27456 // Check allocator expression.
27457 if (D.Allocator->isTypeDependent()) {
27458 AllocatorExpr = D.Allocator;
27459 } else {
27460 // Traits were specified - need to assign new allocator to the specified
27461 // allocator, so it must be an lvalue.
27462 AllocatorExpr = D.Allocator->IgnoreParenImpCasts();
27463 auto *DRE = dyn_cast<DeclRefExpr>(Val: AllocatorExpr);
27464 bool IsPredefinedAllocator = false;
27465 if (DRE) {
27466 OMPAllocateDeclAttr::AllocatorTypeTy AllocatorTy =
27467 getAllocatorKind(S&: SemaRef, DSAStack, Allocator: AllocatorExpr);
27468 IsPredefinedAllocator =
27469 AllocatorTy !=
27470 OMPAllocateDeclAttr::AllocatorTypeTy::OMPUserDefinedMemAlloc;
27471 }
27472 QualType OMPAllocatorHandleT = DSAStack->getOMPAllocatorHandleT();
27473 QualType AllocatorExprType = AllocatorExpr->getType();
27474 bool IsTypeCompatible = IsPredefinedAllocator;
27475 IsTypeCompatible = IsTypeCompatible ||
27476 Context.hasSameUnqualifiedType(T1: AllocatorExprType,
27477 T2: OMPAllocatorHandleT);
27478 IsTypeCompatible =
27479 IsTypeCompatible ||
27480 Context.typesAreCompatible(T1: AllocatorExprType, T2: OMPAllocatorHandleT);
27481 bool IsNonConstantLValue =
27482 !AllocatorExprType.isConstant(Ctx: Context) && AllocatorExpr->isLValue();
27483 if (!DRE || !IsTypeCompatible ||
27484 (!IsPredefinedAllocator && !IsNonConstantLValue)) {
27485 Diag(Loc: D.Allocator->getExprLoc(), DiagID: diag::err_omp_var_expected)
27486 << "omp_allocator_handle_t" << (DRE ? 1 : 0)
27487 << AllocatorExpr->getType() << D.Allocator->getSourceRange();
27488 continue;
27489 }
27490 // OpenMP [2.12.5, target Construct]
27491 // Predefined allocators appearing in a uses_allocators clause cannot have
27492 // traits specified.
27493 if (IsPredefinedAllocator && D.AllocatorTraits) {
27494 Diag(Loc: D.AllocatorTraits->getExprLoc(),
27495 DiagID: diag::err_omp_predefined_allocator_with_traits)
27496 << D.AllocatorTraits->getSourceRange();
27497 Diag(Loc: D.Allocator->getExprLoc(), DiagID: diag::note_omp_predefined_allocator)
27498 << cast<NamedDecl>(Val: DRE->getDecl())->getName()
27499 << D.Allocator->getSourceRange();
27500 continue;
27501 }
27502 // OpenMP [2.12.5, target Construct]
27503 // Non-predefined allocators appearing in a uses_allocators clause must
27504 // have traits specified.
27505 if (getLangOpts().OpenMP < 52) {
27506 if (!IsPredefinedAllocator && !D.AllocatorTraits) {
27507 Diag(Loc: D.Allocator->getExprLoc(),
27508 DiagID: diag::err_omp_nonpredefined_allocator_without_traits);
27509 continue;
27510 }
27511 }
27512 // No allocator traits - just convert it to rvalue.
27513 if (!D.AllocatorTraits)
27514 AllocatorExpr = SemaRef.DefaultLvalueConversion(E: AllocatorExpr).get();
27515 DSAStack->addUsesAllocatorsDecl(
27516 D: DRE->getDecl(),
27517 Kind: IsPredefinedAllocator
27518 ? DSAStackTy::UsesAllocatorsDeclKind::PredefinedAllocator
27519 : DSAStackTy::UsesAllocatorsDeclKind::UserDefinedAllocator);
27520 }
27521 Expr *AllocatorTraitsExpr = nullptr;
27522 if (D.AllocatorTraits) {
27523 if (D.AllocatorTraits->isTypeDependent()) {
27524 AllocatorTraitsExpr = D.AllocatorTraits;
27525 } else {
27526 // OpenMP [2.12.5, target Construct]
27527 // Arrays that contain allocator traits that appear in a uses_allocators
27528 // clause must be constant arrays, have constant values and be defined
27529 // in the same scope as the construct in which the clause appears.
27530 AllocatorTraitsExpr = D.AllocatorTraits->IgnoreParenImpCasts();
27531 // Check that traits expr is a constant array.
27532 QualType TraitTy;
27533 if (const ArrayType *Ty =
27534 AllocatorTraitsExpr->getType()->getAsArrayTypeUnsafe())
27535 if (const auto *ConstArrayTy = dyn_cast<ConstantArrayType>(Val: Ty))
27536 TraitTy = ConstArrayTy->getElementType();
27537 if (TraitTy.isNull() ||
27538 !(Context.hasSameUnqualifiedType(T1: TraitTy,
27539 DSAStack->getOMPAlloctraitT()) ||
27540 Context.typesAreCompatible(T1: TraitTy, DSAStack->getOMPAlloctraitT(),
27541 /*CompareUnqualified=*/true))) {
27542 Diag(Loc: D.AllocatorTraits->getExprLoc(),
27543 DiagID: diag::err_omp_expected_array_alloctraits)
27544 << AllocatorTraitsExpr->getType();
27545 continue;
27546 }
27547 // Do not map by default allocator traits if it is a standalone
27548 // variable.
27549 if (auto *DRE = dyn_cast<DeclRefExpr>(Val: AllocatorTraitsExpr))
27550 DSAStack->addUsesAllocatorsDecl(
27551 D: DRE->getDecl(),
27552 Kind: DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait);
27553 }
27554 }
27555 OMPUsesAllocatorsClause::Data &NewD = NewData.emplace_back();
27556 NewD.Allocator = AllocatorExpr;
27557 NewD.AllocatorTraits = AllocatorTraitsExpr;
27558 NewD.LParenLoc = D.LParenLoc;
27559 NewD.RParenLoc = D.RParenLoc;
27560 }
27561 return OMPUsesAllocatorsClause::Create(C: getASTContext(), StartLoc, LParenLoc,
27562 EndLoc, Data: NewData);
27563}
27564
27565OMPClause *SemaOpenMP::ActOnOpenMPAffinityClause(
27566 SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
27567 SourceLocation EndLoc, Expr *Modifier, ArrayRef<Expr *> Locators) {
27568 SmallVector<Expr *, 8> Vars;
27569 for (Expr *RefExpr : Locators) {
27570 assert(RefExpr && "NULL expr in OpenMP affinity clause.");
27571 if (isa<DependentScopeDeclRefExpr>(Val: RefExpr) || RefExpr->isTypeDependent()) {
27572 // It will be analyzed later.
27573 Vars.push_back(Elt: RefExpr);
27574 continue;
27575 }
27576
27577 SourceLocation ELoc = RefExpr->getExprLoc();
27578 Expr *SimpleExpr = RefExpr->IgnoreParenImpCasts();
27579
27580 if (!SimpleExpr->isLValue()) {
27581 Diag(Loc: ELoc, DiagID: diag::err_omp_expected_addressable_lvalue_or_array_item)
27582 << 1 << 0 << RefExpr->getSourceRange();
27583 continue;
27584 }
27585
27586 ExprResult Res;
27587 {
27588 Sema::TentativeAnalysisScope Trap(SemaRef);
27589 Res = SemaRef.CreateBuiltinUnaryOp(OpLoc: ELoc, Opc: UO_AddrOf, InputExpr: SimpleExpr);
27590 }
27591 if (!Res.isUsable() && !isa<ArraySectionExpr>(Val: SimpleExpr) &&
27592 !isa<OMPArrayShapingExpr>(Val: SimpleExpr)) {
27593 Diag(Loc: ELoc, DiagID: diag::err_omp_expected_addressable_lvalue_or_array_item)
27594 << 1 << 0 << RefExpr->getSourceRange();
27595 continue;
27596 }
27597 Vars.push_back(Elt: SimpleExpr);
27598 }
27599
27600 return OMPAffinityClause::Create(C: getASTContext(), StartLoc, LParenLoc,
27601 ColonLoc, EndLoc, Modifier, Locators: Vars);
27602}
27603
27604OMPClause *SemaOpenMP::ActOnOpenMPBindClause(OpenMPBindClauseKind Kind,
27605 SourceLocation KindLoc,
27606 SourceLocation StartLoc,
27607 SourceLocation LParenLoc,
27608 SourceLocation EndLoc) {
27609 if (Kind == OMPC_BIND_unknown) {
27610 Diag(Loc: KindLoc, DiagID: diag::err_omp_unexpected_clause_value)
27611 << getListOfPossibleValues(K: OMPC_bind, /*First=*/0,
27612 /*Last=*/unsigned(OMPC_BIND_unknown))
27613 << getOpenMPClauseNameForDiag(C: OMPC_bind);
27614 return nullptr;
27615 }
27616
27617 return new (getASTContext())
27618 OMPBindClause(Kind, KindLoc, StartLoc, LParenLoc, EndLoc);
27619}
27620
27621OMPClause *SemaOpenMP::ActOnOpenMPXDynCGroupMemClause(Expr *Size,
27622 SourceLocation StartLoc,
27623 SourceLocation LParenLoc,
27624 SourceLocation EndLoc) {
27625 Expr *ValExpr = Size;
27626 Stmt *HelperValStmt = nullptr;
27627
27628 // OpenMP [2.5, Restrictions]
27629 // The ompx_dyn_cgroup_mem expression must evaluate to a positive integer
27630 // value.
27631 if (!isNonNegativeIntegerValue(ValExpr, SemaRef, CKind: OMPC_ompx_dyn_cgroup_mem,
27632 /*StrictlyPositive=*/false))
27633 return nullptr;
27634
27635 OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
27636 OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause(
27637 DKind, CKind: OMPC_ompx_dyn_cgroup_mem, OMPVersion: getLangOpts().getOpenMPVersion());
27638 if (CaptureRegion != OMPD_unknown &&
27639 !SemaRef.CurContext->isDependentContext()) {
27640 ValExpr = SemaRef.MakeFullExpr(Arg: ValExpr).get();
27641 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
27642 ValExpr = tryBuildCapture(SemaRef, Capture: ValExpr, Captures).get();
27643 HelperValStmt = buildPreInits(Context&: getASTContext(), Captures);
27644 }
27645
27646 return new (getASTContext()) OMPXDynCGroupMemClause(
27647 ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
27648}
27649
27650OMPClause *SemaOpenMP::ActOnOpenMPDynGroupprivateClause(
27651 OpenMPDynGroupprivateClauseModifier M1,
27652 OpenMPDynGroupprivateClauseFallbackModifier M2, Expr *Size,
27653 SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation M1Loc,
27654 SourceLocation M2Loc, SourceLocation EndLoc) {
27655
27656 if ((M1Loc.isValid() && M1 == OMPC_DYN_GROUPPRIVATE_unknown) ||
27657 (M2Loc.isValid() && M2 == OMPC_DYN_GROUPPRIVATE_FALLBACK_unknown)) {
27658 std::string Values = getListOfPossibleValues(
27659 K: OMPC_dyn_groupprivate, /*First=*/0, Last: OMPC_DYN_GROUPPRIVATE_unknown);
27660 Diag(Loc: (M1Loc.isValid() && M1 == OMPC_DYN_GROUPPRIVATE_unknown) ? M1Loc
27661 : M2Loc,
27662 DiagID: diag::err_omp_unexpected_clause_value)
27663 << Values << getOpenMPClauseName(C: OMPC_dyn_groupprivate);
27664 return nullptr;
27665 }
27666
27667 Expr *ValExpr = Size;
27668 Stmt *HelperValStmt = nullptr;
27669
27670 // OpenMP [2.5, Restrictions]
27671 // The dyn_groupprivate expression must evaluate to a positive integer
27672 // value.
27673 if (!isNonNegativeIntegerValue(ValExpr, SemaRef, CKind: OMPC_dyn_groupprivate,
27674 /*StrictlyPositive=*/false))
27675 return nullptr;
27676
27677 OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
27678 OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause(
27679 DKind, CKind: OMPC_dyn_groupprivate, OMPVersion: getLangOpts().getOpenMPVersion());
27680 if (CaptureRegion != OMPD_unknown &&
27681 !SemaRef.CurContext->isDependentContext()) {
27682 ValExpr = SemaRef.MakeFullExpr(Arg: ValExpr).get();
27683 llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
27684 ValExpr = tryBuildCapture(SemaRef, Capture: ValExpr, Captures).get();
27685 HelperValStmt = buildPreInits(Context&: getASTContext(), Captures);
27686 }
27687
27688 return new (getASTContext()) OMPDynGroupprivateClause(
27689 StartLoc, LParenLoc, EndLoc, ValExpr, HelperValStmt, CaptureRegion, M1,
27690 M1Loc, M2, M2Loc);
27691}
27692
27693OMPClause *SemaOpenMP::ActOnOpenMPDoacrossClause(
27694 OpenMPDoacrossClauseModifier DepType, SourceLocation DepLoc,
27695 SourceLocation ColonLoc, ArrayRef<Expr *> VarList, SourceLocation StartLoc,
27696 SourceLocation LParenLoc, SourceLocation EndLoc) {
27697
27698 if (DSAStack->getCurrentDirective() == OMPD_ordered_standalone &&
27699 DepType != OMPC_DOACROSS_source && DepType != OMPC_DOACROSS_sink &&
27700 DepType != OMPC_DOACROSS_sink_omp_cur_iteration &&
27701 DepType != OMPC_DOACROSS_source_omp_cur_iteration) {
27702 Diag(Loc: DepLoc, DiagID: diag::err_omp_unexpected_clause_value)
27703 << "'source' or 'sink'" << getOpenMPClauseNameForDiag(C: OMPC_doacross);
27704 return nullptr;
27705 }
27706
27707 SmallVector<Expr *, 8> Vars;
27708 DSAStackTy::OperatorOffsetTy OpsOffs;
27709 llvm::APSInt TotalDepCount(/*BitWidth=*/32);
27710 DoacrossDataInfoTy VarOffset = ProcessOpenMPDoacrossClauseCommon(
27711 SemaRef,
27712 IsSource: DepType == OMPC_DOACROSS_source ||
27713 DepType == OMPC_DOACROSS_source_omp_cur_iteration ||
27714 DepType == OMPC_DOACROSS_sink_omp_cur_iteration,
27715 VarList, DSAStack, EndLoc);
27716 Vars = VarOffset.Vars;
27717 OpsOffs = VarOffset.OpsOffs;
27718 TotalDepCount = VarOffset.TotalDepCount;
27719 auto *C = OMPDoacrossClause::Create(C: getASTContext(), StartLoc, LParenLoc,
27720 EndLoc, DepType, DepLoc, ColonLoc, VL: Vars,
27721 NumLoops: TotalDepCount.getZExtValue());
27722 if (DSAStack->isParentOrderedRegion())
27723 DSAStack->addDoacrossDependClause(C, OpsOffs);
27724 return C;
27725}
27726
27727OMPClause *SemaOpenMP::ActOnOpenMPXAttributeClause(ArrayRef<const Attr *> Attrs,
27728 SourceLocation StartLoc,
27729 SourceLocation LParenLoc,
27730 SourceLocation EndLoc) {
27731 return new (getASTContext())
27732 OMPXAttributeClause(Attrs, StartLoc, LParenLoc, EndLoc);
27733}
27734
27735OMPClause *SemaOpenMP::ActOnOpenMPXBareClause(SourceLocation StartLoc,
27736 SourceLocation EndLoc) {
27737 return new (getASTContext()) OMPXBareClause(StartLoc, EndLoc);
27738}
27739
27740OMPClause *SemaOpenMP::ActOnOpenMPHoldsClause(Expr *E, SourceLocation StartLoc,
27741 SourceLocation LParenLoc,
27742 SourceLocation EndLoc) {
27743 if (E->HasSideEffects(Ctx: getASTContext()))
27744 Diag(Loc: E->getBeginLoc(), DiagID: diag::warn_assume_side_effects)
27745 << "holds" << E->getSourceRange();
27746 return new (getASTContext()) OMPHoldsClause(E, StartLoc, LParenLoc, EndLoc);
27747}
27748
27749OMPClause *SemaOpenMP::ActOnOpenMPDirectivePresenceClause(
27750 OpenMPClauseKind CK, llvm::ArrayRef<OpenMPDirectiveKind> DKVec,
27751 SourceLocation Loc, SourceLocation LLoc, SourceLocation RLoc) {
27752 switch (CK) {
27753 case OMPC_absent:
27754 return OMPAbsentClause::Create(C: getASTContext(), DKVec, Loc, LLoc, RLoc);
27755 case OMPC_contains:
27756 return OMPContainsClause::Create(C: getASTContext(), DKVec, Loc, LLoc, RLoc);
27757 default:
27758 llvm_unreachable("Unexpected OpenMP clause");
27759 }
27760}
27761
27762OMPClause *SemaOpenMP::ActOnOpenMPNullaryAssumptionClause(OpenMPClauseKind CK,
27763 SourceLocation Loc,
27764 SourceLocation RLoc) {
27765 switch (CK) {
27766 case OMPC_no_openmp:
27767 return new (getASTContext()) OMPNoOpenMPClause(Loc, RLoc);
27768 case OMPC_no_openmp_routines:
27769 return new (getASTContext()) OMPNoOpenMPRoutinesClause(Loc, RLoc);
27770 case OMPC_no_parallelism:
27771 return new (getASTContext()) OMPNoParallelismClause(Loc, RLoc);
27772 case OMPC_no_openmp_constructs:
27773 return new (getASTContext()) OMPNoOpenMPConstructsClause(Loc, RLoc);
27774 default:
27775 llvm_unreachable("Unexpected OpenMP clause");
27776 }
27777}
27778
27779ExprResult SemaOpenMP::ActOnOMPArraySectionExpr(
27780 Expr *Base, SourceLocation LBLoc, Expr *LowerBound,
27781 SourceLocation ColonLocFirst, SourceLocation ColonLocSecond, Expr *Length,
27782 Expr *Stride, SourceLocation RBLoc) {
27783 ASTContext &Context = getASTContext();
27784 if (Base->hasPlaceholderType() &&
27785 !Base->hasPlaceholderType(K: BuiltinType::ArraySection)) {
27786 ExprResult Result = SemaRef.CheckPlaceholderExpr(E: Base);
27787 if (Result.isInvalid())
27788 return ExprError();
27789 Base = Result.get();
27790 }
27791 if (LowerBound && LowerBound->getType()->isNonOverloadPlaceholderType()) {
27792 ExprResult Result = SemaRef.CheckPlaceholderExpr(E: LowerBound);
27793 if (Result.isInvalid())
27794 return ExprError();
27795 Result = SemaRef.DefaultLvalueConversion(E: Result.get());
27796 if (Result.isInvalid())
27797 return ExprError();
27798 LowerBound = Result.get();
27799 }
27800 if (Length && Length->getType()->isNonOverloadPlaceholderType()) {
27801 ExprResult Result = SemaRef.CheckPlaceholderExpr(E: Length);
27802 if (Result.isInvalid())
27803 return ExprError();
27804 Result = SemaRef.DefaultLvalueConversion(E: Result.get());
27805 if (Result.isInvalid())
27806 return ExprError();
27807 Length = Result.get();
27808 }
27809 if (Stride && Stride->getType()->isNonOverloadPlaceholderType()) {
27810 ExprResult Result = SemaRef.CheckPlaceholderExpr(E: Stride);
27811 if (Result.isInvalid())
27812 return ExprError();
27813 Result = SemaRef.DefaultLvalueConversion(E: Result.get());
27814 if (Result.isInvalid())
27815 return ExprError();
27816 Stride = Result.get();
27817 }
27818
27819 // Build an unanalyzed expression if either operand is type-dependent.
27820 if (Base->isTypeDependent() ||
27821 (LowerBound &&
27822 (LowerBound->isTypeDependent() || LowerBound->isValueDependent())) ||
27823 (Length && (Length->isTypeDependent() || Length->isValueDependent())) ||
27824 (Stride && (Stride->isTypeDependent() || Stride->isValueDependent()))) {
27825 return new (Context) ArraySectionExpr(
27826 Base, LowerBound, Length, Stride, Context.DependentTy, VK_LValue,
27827 OK_Ordinary, ColonLocFirst, ColonLocSecond, RBLoc);
27828 }
27829
27830 // Perform default conversions.
27831 QualType OriginalTy = ArraySectionExpr::getBaseOriginalType(Base);
27832 QualType ResultTy;
27833 if (OriginalTy->isAnyPointerType()) {
27834 ResultTy = OriginalTy->getPointeeType();
27835 } else if (OriginalTy->isArrayType()) {
27836 ResultTy = OriginalTy->getAsArrayTypeUnsafe()->getElementType();
27837 } else {
27838 return ExprError(
27839 Diag(Loc: Base->getExprLoc(), DiagID: diag::err_omp_typecheck_section_value)
27840 << Base->getSourceRange());
27841 }
27842 // C99 6.5.2.1p1
27843 if (LowerBound) {
27844 auto Res = PerformOpenMPImplicitIntegerConversion(Loc: LowerBound->getExprLoc(),
27845 Op: LowerBound);
27846 if (Res.isInvalid())
27847 return ExprError(Diag(Loc: LowerBound->getExprLoc(),
27848 DiagID: diag::err_omp_typecheck_section_not_integer)
27849 << 0 << LowerBound->getSourceRange());
27850 LowerBound = Res.get();
27851
27852 if (LowerBound->getType()->isSpecificBuiltinType(K: BuiltinType::Char_S) ||
27853 LowerBound->getType()->isSpecificBuiltinType(K: BuiltinType::Char_U))
27854 Diag(Loc: LowerBound->getExprLoc(), DiagID: diag::warn_omp_section_is_char)
27855 << 0 << LowerBound->getSourceRange();
27856 }
27857 if (Length) {
27858 auto Res =
27859 PerformOpenMPImplicitIntegerConversion(Loc: Length->getExprLoc(), Op: Length);
27860 if (Res.isInvalid())
27861 return ExprError(Diag(Loc: Length->getExprLoc(),
27862 DiagID: diag::err_omp_typecheck_section_not_integer)
27863 << 1 << Length->getSourceRange());
27864 Length = Res.get();
27865
27866 if (Length->getType()->isSpecificBuiltinType(K: BuiltinType::Char_S) ||
27867 Length->getType()->isSpecificBuiltinType(K: BuiltinType::Char_U))
27868 Diag(Loc: Length->getExprLoc(), DiagID: diag::warn_omp_section_is_char)
27869 << 1 << Length->getSourceRange();
27870 }
27871 if (Stride) {
27872 ExprResult Res =
27873 PerformOpenMPImplicitIntegerConversion(Loc: Stride->getExprLoc(), Op: Stride);
27874 if (Res.isInvalid())
27875 return ExprError(Diag(Loc: Stride->getExprLoc(),
27876 DiagID: diag::err_omp_typecheck_section_not_integer)
27877 << 1 << Stride->getSourceRange());
27878 Stride = Res.get();
27879
27880 if (Stride->getType()->isSpecificBuiltinType(K: BuiltinType::Char_S) ||
27881 Stride->getType()->isSpecificBuiltinType(K: BuiltinType::Char_U))
27882 Diag(Loc: Stride->getExprLoc(), DiagID: diag::warn_omp_section_is_char)
27883 << 1 << Stride->getSourceRange();
27884 }
27885
27886 // C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly,
27887 // C++ [expr.sub]p1: The type "T" shall be a completely-defined object
27888 // type. Note that functions are not objects, and that (in C99 parlance)
27889 // incomplete types are not object types.
27890 if (ResultTy->isFunctionType()) {
27891 Diag(Loc: Base->getExprLoc(), DiagID: diag::err_omp_section_function_type)
27892 << ResultTy << Base->getSourceRange();
27893 return ExprError();
27894 }
27895
27896 if (SemaRef.RequireCompleteType(Loc: Base->getExprLoc(), T: ResultTy,
27897 DiagID: diag::err_omp_section_incomplete_type, Args: Base))
27898 return ExprError();
27899
27900 if (LowerBound && !OriginalTy->isAnyPointerType()) {
27901 Expr::EvalResult Result;
27902 if (LowerBound->EvaluateAsInt(Result, Ctx: Context)) {
27903 // OpenMP 5.0, [2.1.5 Array Sections]
27904 // The array section must be a subset of the original array.
27905 llvm::APSInt LowerBoundValue = Result.Val.getInt();
27906 if (LowerBoundValue.isNegative()) {
27907 Diag(Loc: LowerBound->getExprLoc(),
27908 DiagID: diag::err_omp_section_not_subset_of_array)
27909 << LowerBound->getSourceRange();
27910 return ExprError();
27911 }
27912 }
27913 }
27914
27915 if (Length) {
27916 Expr::EvalResult Result;
27917 if (Length->EvaluateAsInt(Result, Ctx: Context)) {
27918 // OpenMP 5.0, [2.1.5 Array Sections]
27919 // The length must evaluate to non-negative integers.
27920 llvm::APSInt LengthValue = Result.Val.getInt();
27921 if (LengthValue.isNegative()) {
27922 Diag(Loc: Length->getExprLoc(), DiagID: diag::err_omp_section_length_negative)
27923 << toString(I: LengthValue, /*Radix=*/10, /*Signed=*/true)
27924 << Length->getSourceRange();
27925 return ExprError();
27926 }
27927 }
27928 } else if (SemaRef.getLangOpts().OpenMP < 60 && ColonLocFirst.isValid() &&
27929 (OriginalTy.isNull() || (!OriginalTy->isConstantArrayType() &&
27930 !OriginalTy->isVariableArrayType()))) {
27931 // OpenMP 5.0, [2.1.5 Array Sections]
27932 // When the size of the array dimension is not known, the length must be
27933 // specified explicitly.
27934 Diag(Loc: ColonLocFirst, DiagID: diag::err_omp_section_length_undefined)
27935 << (!OriginalTy.isNull() && OriginalTy->isArrayType());
27936 return ExprError();
27937 }
27938
27939 if (Stride) {
27940 Expr::EvalResult Result;
27941 if (Stride->EvaluateAsInt(Result, Ctx: Context)) {
27942 // OpenMP 5.0, [2.1.5 Array Sections]
27943 // The stride must evaluate to a positive integer.
27944 llvm::APSInt StrideValue = Result.Val.getInt();
27945 if (!StrideValue.isStrictlyPositive()) {
27946 Diag(Loc: Stride->getExprLoc(), DiagID: diag::err_omp_section_stride_non_positive)
27947 << toString(I: StrideValue, /*Radix=*/10, /*Signed=*/true)
27948 << Stride->getSourceRange();
27949 return ExprError();
27950 }
27951 }
27952 }
27953
27954 if (!Base->hasPlaceholderType(K: BuiltinType::ArraySection)) {
27955 ExprResult Result = SemaRef.DefaultFunctionArrayLvalueConversion(E: Base);
27956 if (Result.isInvalid())
27957 return ExprError();
27958 Base = Result.get();
27959 }
27960 return new (Context) ArraySectionExpr(
27961 Base, LowerBound, Length, Stride, Context.ArraySectionTy, VK_LValue,
27962 OK_Ordinary, ColonLocFirst, ColonLocSecond, RBLoc);
27963}
27964
27965ExprResult SemaOpenMP::ActOnOMPArrayShapingExpr(
27966 Expr *Base, SourceLocation LParenLoc, SourceLocation RParenLoc,
27967 ArrayRef<Expr *> Dims, ArrayRef<SourceRange> Brackets) {
27968 ASTContext &Context = getASTContext();
27969 if (Base->hasPlaceholderType()) {
27970 ExprResult Result = SemaRef.CheckPlaceholderExpr(E: Base);
27971 if (Result.isInvalid())
27972 return ExprError();
27973 Result = SemaRef.DefaultLvalueConversion(E: Result.get());
27974 if (Result.isInvalid())
27975 return ExprError();
27976 Base = Result.get();
27977 }
27978 QualType BaseTy = Base->getType();
27979 // Delay analysis of the types/expressions if instantiation/specialization is
27980 // required.
27981 if (!BaseTy->isPointerType() && Base->isTypeDependent())
27982 return OMPArrayShapingExpr::Create(Context, T: Context.DependentTy, Op: Base,
27983 L: LParenLoc, R: RParenLoc, Dims, BracketRanges: Brackets);
27984 if (!BaseTy->isPointerType() ||
27985 (!Base->isTypeDependent() &&
27986 BaseTy->getPointeeType()->isIncompleteType()))
27987 return ExprError(Diag(Loc: Base->getExprLoc(),
27988 DiagID: diag::err_omp_non_pointer_type_array_shaping_base)
27989 << Base->getSourceRange());
27990
27991 SmallVector<Expr *, 4> NewDims;
27992 bool ErrorFound = false;
27993 for (Expr *Dim : Dims) {
27994 if (Dim->hasPlaceholderType()) {
27995 ExprResult Result = SemaRef.CheckPlaceholderExpr(E: Dim);
27996 if (Result.isInvalid()) {
27997 ErrorFound = true;
27998 continue;
27999 }
28000 Result = SemaRef.DefaultLvalueConversion(E: Result.get());
28001 if (Result.isInvalid()) {
28002 ErrorFound = true;
28003 continue;
28004 }
28005 Dim = Result.get();
28006 }
28007 if (!Dim->isTypeDependent()) {
28008 ExprResult Result =
28009 PerformOpenMPImplicitIntegerConversion(Loc: Dim->getExprLoc(), Op: Dim);
28010 if (Result.isInvalid()) {
28011 ErrorFound = true;
28012 Diag(Loc: Dim->getExprLoc(), DiagID: diag::err_omp_typecheck_shaping_not_integer)
28013 << Dim->getSourceRange();
28014 continue;
28015 }
28016 Dim = Result.get();
28017 Expr::EvalResult EvResult;
28018 if (!Dim->isValueDependent() && Dim->EvaluateAsInt(Result&: EvResult, Ctx: Context)) {
28019 // OpenMP 5.0, [2.1.4 Array Shaping]
28020 // Each si is an integral type expression that must evaluate to a
28021 // positive integer.
28022 llvm::APSInt Value = EvResult.Val.getInt();
28023 if (!Value.isStrictlyPositive()) {
28024 Diag(Loc: Dim->getExprLoc(), DiagID: diag::err_omp_shaping_dimension_not_positive)
28025 << toString(I: Value, /*Radix=*/10, /*Signed=*/true)
28026 << Dim->getSourceRange();
28027 ErrorFound = true;
28028 continue;
28029 }
28030 }
28031 }
28032 NewDims.push_back(Elt: Dim);
28033 }
28034 if (ErrorFound)
28035 return ExprError();
28036 return OMPArrayShapingExpr::Create(Context, T: Context.OMPArrayShapingTy, Op: Base,
28037 L: LParenLoc, R: RParenLoc, Dims: NewDims, BracketRanges: Brackets);
28038}
28039
28040ExprResult SemaOpenMP::ActOnOMPIteratorExpr(Scope *S,
28041 SourceLocation IteratorKwLoc,
28042 SourceLocation LLoc,
28043 SourceLocation RLoc,
28044 ArrayRef<OMPIteratorData> Data) {
28045 ASTContext &Context = getASTContext();
28046 SmallVector<OMPIteratorExpr::IteratorDefinition, 4> ID;
28047 bool IsCorrect = true;
28048 for (const OMPIteratorData &D : Data) {
28049 TypeSourceInfo *TInfo = nullptr;
28050 SourceLocation StartLoc;
28051 QualType DeclTy;
28052 if (!D.Type.getAsOpaquePtr()) {
28053 // OpenMP 5.0, 2.1.6 Iterators
28054 // In an iterator-specifier, if the iterator-type is not specified then
28055 // the type of that iterator is of int type.
28056 DeclTy = Context.IntTy;
28057 StartLoc = D.DeclIdentLoc;
28058 } else {
28059 DeclTy = Sema::GetTypeFromParser(Ty: D.Type, TInfo: &TInfo);
28060 StartLoc = TInfo->getTypeLoc().getBeginLoc();
28061 }
28062
28063 bool IsDeclTyDependent = DeclTy->isDependentType() ||
28064 DeclTy->containsUnexpandedParameterPack() ||
28065 DeclTy->isInstantiationDependentType();
28066 if (!IsDeclTyDependent) {
28067 if (!DeclTy->isIntegralType(Ctx: Context) && !DeclTy->isAnyPointerType()) {
28068 // OpenMP 5.0, 2.1.6 Iterators, Restrictions, C/C++
28069 // The iterator-type must be an integral or pointer type.
28070 Diag(Loc: StartLoc, DiagID: diag::err_omp_iterator_not_integral_or_pointer)
28071 << DeclTy;
28072 IsCorrect = false;
28073 continue;
28074 }
28075 if (DeclTy.isConstant(Ctx: Context)) {
28076 // OpenMP 5.0, 2.1.6 Iterators, Restrictions, C/C++
28077 // The iterator-type must not be const qualified.
28078 Diag(Loc: StartLoc, DiagID: diag::err_omp_iterator_not_integral_or_pointer)
28079 << DeclTy;
28080 IsCorrect = false;
28081 continue;
28082 }
28083 }
28084
28085 // Iterator declaration.
28086 assert(D.DeclIdent && "Identifier expected.");
28087 // Always try to create iterator declarator to avoid extra error messages
28088 // about unknown declarations use.
28089 auto *VD =
28090 VarDecl::Create(C&: Context, DC: SemaRef.CurContext, StartLoc, IdLoc: D.DeclIdentLoc,
28091 Id: D.DeclIdent, T: DeclTy, TInfo, S: SC_None);
28092 VD->setImplicit();
28093 if (S) {
28094 // Check for conflicting previous declaration.
28095 DeclarationNameInfo NameInfo(VD->getDeclName(), D.DeclIdentLoc);
28096 LookupResult Previous(SemaRef, NameInfo, Sema::LookupOrdinaryName,
28097 RedeclarationKind::ForVisibleRedeclaration);
28098 Previous.suppressDiagnostics();
28099 SemaRef.LookupName(R&: Previous, S);
28100
28101 SemaRef.FilterLookupForScope(R&: Previous, Ctx: SemaRef.CurContext, S,
28102 /*ConsiderLinkage=*/false,
28103 /*AllowInlineNamespace=*/false);
28104 if (!Previous.empty()) {
28105 NamedDecl *Old = Previous.getRepresentativeDecl();
28106 Diag(Loc: D.DeclIdentLoc, DiagID: diag::err_redefinition) << VD->getDeclName();
28107 Diag(Loc: Old->getLocation(), DiagID: diag::note_previous_definition);
28108 } else {
28109 SemaRef.PushOnScopeChains(D: VD, S);
28110 }
28111 } else {
28112 SemaRef.CurContext->addDecl(D: VD);
28113 }
28114
28115 /// Act on the iterator variable declaration.
28116 ActOnOpenMPIteratorVarDecl(VD);
28117
28118 Expr *Begin = D.Range.Begin;
28119 if (!IsDeclTyDependent && Begin && !Begin->isTypeDependent()) {
28120 ExprResult BeginRes = SemaRef.PerformImplicitConversion(
28121 From: Begin, ToType: DeclTy, Action: AssignmentAction::Converting);
28122 Begin = BeginRes.get();
28123 }
28124 Expr *End = D.Range.End;
28125 if (!IsDeclTyDependent && End && !End->isTypeDependent()) {
28126 ExprResult EndRes = SemaRef.PerformImplicitConversion(
28127 From: End, ToType: DeclTy, Action: AssignmentAction::Converting);
28128 End = EndRes.get();
28129 }
28130 Expr *Step = D.Range.Step;
28131 if (!IsDeclTyDependent && Step && !Step->isTypeDependent()) {
28132 if (!Step->getType()->isIntegralType(Ctx: Context)) {
28133 Diag(Loc: Step->getExprLoc(), DiagID: diag::err_omp_iterator_step_not_integral)
28134 << Step << Step->getSourceRange();
28135 IsCorrect = false;
28136 continue;
28137 }
28138 std::optional<llvm::APSInt> Result =
28139 Step->getIntegerConstantExpr(Ctx: Context);
28140 // OpenMP 5.0, 2.1.6 Iterators, Restrictions
28141 // If the step expression of a range-specification equals zero, the
28142 // behavior is unspecified.
28143 if (Result && Result->isZero()) {
28144 Diag(Loc: Step->getExprLoc(), DiagID: diag::err_omp_iterator_step_constant_zero)
28145 << Step << Step->getSourceRange();
28146 IsCorrect = false;
28147 continue;
28148 }
28149 }
28150 if (!Begin || !End || !IsCorrect) {
28151 IsCorrect = false;
28152 continue;
28153 }
28154 OMPIteratorExpr::IteratorDefinition &IDElem = ID.emplace_back();
28155 IDElem.IteratorDecl = VD;
28156 IDElem.AssignmentLoc = D.AssignLoc;
28157 IDElem.Range.Begin = Begin;
28158 IDElem.Range.End = End;
28159 IDElem.Range.Step = Step;
28160 IDElem.ColonLoc = D.ColonLoc;
28161 IDElem.SecondColonLoc = D.SecColonLoc;
28162 }
28163 if (!IsCorrect) {
28164 // Invalidate all created iterator declarations if error is found.
28165 for (const OMPIteratorExpr::IteratorDefinition &D : ID) {
28166 if (Decl *ID = D.IteratorDecl)
28167 ID->setInvalidDecl();
28168 }
28169 return ExprError();
28170 }
28171 SmallVector<OMPIteratorHelperData, 4> Helpers;
28172 if (!SemaRef.CurContext->isDependentContext()) {
28173 // Build number of ityeration for each iteration range.
28174 // Ni = ((Stepi > 0) ? ((Endi + Stepi -1 - Begini)/Stepi) :
28175 // ((Begini-Stepi-1-Endi) / -Stepi);
28176 for (OMPIteratorExpr::IteratorDefinition &D : ID) {
28177 // (Endi - Begini)
28178 ExprResult Res = SemaRef.CreateBuiltinBinOp(OpLoc: D.AssignmentLoc, Opc: BO_Sub,
28179 LHSExpr: D.Range.End, RHSExpr: D.Range.Begin);
28180 if (!Res.isUsable()) {
28181 IsCorrect = false;
28182 continue;
28183 }
28184 ExprResult St, St1;
28185 if (D.Range.Step) {
28186 St = D.Range.Step;
28187 // (Endi - Begini) + Stepi
28188 Res = SemaRef.CreateBuiltinBinOp(OpLoc: D.AssignmentLoc, Opc: BO_Add, LHSExpr: Res.get(),
28189 RHSExpr: St.get());
28190 if (!Res.isUsable()) {
28191 IsCorrect = false;
28192 continue;
28193 }
28194 // (Endi - Begini) + Stepi - 1
28195 Res = SemaRef.CreateBuiltinBinOp(
28196 OpLoc: D.AssignmentLoc, Opc: BO_Sub, LHSExpr: Res.get(),
28197 RHSExpr: SemaRef.ActOnIntegerConstant(Loc: D.AssignmentLoc, Val: 1).get());
28198 if (!Res.isUsable()) {
28199 IsCorrect = false;
28200 continue;
28201 }
28202 // ((Endi - Begini) + Stepi - 1) / Stepi
28203 Res = SemaRef.CreateBuiltinBinOp(OpLoc: D.AssignmentLoc, Opc: BO_Div, LHSExpr: Res.get(),
28204 RHSExpr: St.get());
28205 if (!Res.isUsable()) {
28206 IsCorrect = false;
28207 continue;
28208 }
28209 St1 = SemaRef.CreateBuiltinUnaryOp(OpLoc: D.AssignmentLoc, Opc: UO_Minus,
28210 InputExpr: D.Range.Step);
28211 // (Begini - Endi)
28212 ExprResult Res1 = SemaRef.CreateBuiltinBinOp(
28213 OpLoc: D.AssignmentLoc, Opc: BO_Sub, LHSExpr: D.Range.Begin, RHSExpr: D.Range.End);
28214 if (!Res1.isUsable()) {
28215 IsCorrect = false;
28216 continue;
28217 }
28218 // (Begini - Endi) - Stepi
28219 Res1 = SemaRef.CreateBuiltinBinOp(OpLoc: D.AssignmentLoc, Opc: BO_Add, LHSExpr: Res1.get(),
28220 RHSExpr: St1.get());
28221 if (!Res1.isUsable()) {
28222 IsCorrect = false;
28223 continue;
28224 }
28225 // (Begini - Endi) - Stepi - 1
28226 Res1 = SemaRef.CreateBuiltinBinOp(
28227 OpLoc: D.AssignmentLoc, Opc: BO_Sub, LHSExpr: Res1.get(),
28228 RHSExpr: SemaRef.ActOnIntegerConstant(Loc: D.AssignmentLoc, Val: 1).get());
28229 if (!Res1.isUsable()) {
28230 IsCorrect = false;
28231 continue;
28232 }
28233 // ((Begini - Endi) - Stepi - 1) / (-Stepi)
28234 Res1 = SemaRef.CreateBuiltinBinOp(OpLoc: D.AssignmentLoc, Opc: BO_Div, LHSExpr: Res1.get(),
28235 RHSExpr: St1.get());
28236 if (!Res1.isUsable()) {
28237 IsCorrect = false;
28238 continue;
28239 }
28240 // Stepi > 0.
28241 ExprResult CmpRes = SemaRef.CreateBuiltinBinOp(
28242 OpLoc: D.AssignmentLoc, Opc: BO_GT, LHSExpr: D.Range.Step,
28243 RHSExpr: SemaRef.ActOnIntegerConstant(Loc: D.AssignmentLoc, Val: 0).get());
28244 if (!CmpRes.isUsable()) {
28245 IsCorrect = false;
28246 continue;
28247 }
28248 Res = SemaRef.ActOnConditionalOp(QuestionLoc: D.AssignmentLoc, ColonLoc: D.AssignmentLoc,
28249 CondExpr: CmpRes.get(), LHSExpr: Res.get(), RHSExpr: Res1.get());
28250 if (!Res.isUsable()) {
28251 IsCorrect = false;
28252 continue;
28253 }
28254 }
28255 Res = SemaRef.ActOnFinishFullExpr(Expr: Res.get(), /*DiscardedValue=*/false);
28256 if (!Res.isUsable()) {
28257 IsCorrect = false;
28258 continue;
28259 }
28260
28261 // Build counter update.
28262 // Build counter.
28263 auto *CounterVD = VarDecl::Create(C&: Context, DC: SemaRef.CurContext,
28264 StartLoc: D.IteratorDecl->getBeginLoc(),
28265 IdLoc: D.IteratorDecl->getBeginLoc(), Id: nullptr,
28266 T: Res.get()->getType(), TInfo: nullptr, S: SC_None);
28267 CounterVD->setImplicit();
28268 ExprResult RefRes =
28269 SemaRef.BuildDeclRefExpr(D: CounterVD, Ty: CounterVD->getType(), VK: VK_LValue,
28270 Loc: D.IteratorDecl->getBeginLoc());
28271 // Build counter update.
28272 // I = Begini + counter * Stepi;
28273 ExprResult UpdateRes;
28274 if (D.Range.Step) {
28275 UpdateRes = SemaRef.CreateBuiltinBinOp(
28276 OpLoc: D.AssignmentLoc, Opc: BO_Mul,
28277 LHSExpr: SemaRef.DefaultLvalueConversion(E: RefRes.get()).get(), RHSExpr: St.get());
28278 } else {
28279 UpdateRes = SemaRef.DefaultLvalueConversion(E: RefRes.get());
28280 }
28281 if (!UpdateRes.isUsable()) {
28282 IsCorrect = false;
28283 continue;
28284 }
28285 UpdateRes = SemaRef.CreateBuiltinBinOp(OpLoc: D.AssignmentLoc, Opc: BO_Add,
28286 LHSExpr: D.Range.Begin, RHSExpr: UpdateRes.get());
28287 if (!UpdateRes.isUsable()) {
28288 IsCorrect = false;
28289 continue;
28290 }
28291 ExprResult VDRes =
28292 SemaRef.BuildDeclRefExpr(D: cast<VarDecl>(Val: D.IteratorDecl),
28293 Ty: cast<VarDecl>(Val: D.IteratorDecl)->getType(),
28294 VK: VK_LValue, Loc: D.IteratorDecl->getBeginLoc());
28295 UpdateRes = SemaRef.CreateBuiltinBinOp(OpLoc: D.AssignmentLoc, Opc: BO_Assign,
28296 LHSExpr: VDRes.get(), RHSExpr: UpdateRes.get());
28297 if (!UpdateRes.isUsable()) {
28298 IsCorrect = false;
28299 continue;
28300 }
28301 UpdateRes =
28302 SemaRef.ActOnFinishFullExpr(Expr: UpdateRes.get(), /*DiscardedValue=*/true);
28303 if (!UpdateRes.isUsable()) {
28304 IsCorrect = false;
28305 continue;
28306 }
28307 ExprResult CounterUpdateRes = SemaRef.CreateBuiltinUnaryOp(
28308 OpLoc: D.AssignmentLoc, Opc: UO_PreInc, InputExpr: RefRes.get());
28309 if (!CounterUpdateRes.isUsable()) {
28310 IsCorrect = false;
28311 continue;
28312 }
28313 CounterUpdateRes = SemaRef.ActOnFinishFullExpr(Expr: CounterUpdateRes.get(),
28314 /*DiscardedValue=*/true);
28315 if (!CounterUpdateRes.isUsable()) {
28316 IsCorrect = false;
28317 continue;
28318 }
28319 OMPIteratorHelperData &HD = Helpers.emplace_back();
28320 HD.CounterVD = CounterVD;
28321 HD.Upper = Res.get();
28322 HD.Update = UpdateRes.get();
28323 HD.CounterUpdate = CounterUpdateRes.get();
28324 }
28325 } else {
28326 Helpers.assign(NumElts: ID.size(), Elt: {});
28327 }
28328 if (!IsCorrect) {
28329 // Invalidate all created iterator declarations if error is found.
28330 for (const OMPIteratorExpr::IteratorDefinition &D : ID) {
28331 if (Decl *ID = D.IteratorDecl)
28332 ID->setInvalidDecl();
28333 }
28334 return ExprError();
28335 }
28336 return OMPIteratorExpr::Create(Context, T: Context.OMPIteratorTy, IteratorKwLoc,
28337 L: LLoc, R: RLoc, Data: ID, Helpers);
28338}
28339
28340/// Check if \p AssumptionStr is a known assumption and warn if not.
28341static void checkOMPAssumeAttr(Sema &S, SourceLocation Loc,
28342 StringRef AssumptionStr) {
28343 if (llvm::getKnownAssumptionStrings().count(Key: AssumptionStr))
28344 return;
28345
28346 unsigned BestEditDistance = 3;
28347 StringRef Suggestion;
28348 for (const auto &KnownAssumptionIt : llvm::getKnownAssumptionStrings()) {
28349 unsigned EditDistance =
28350 AssumptionStr.edit_distance(Other: KnownAssumptionIt.getKey());
28351 if (EditDistance < BestEditDistance) {
28352 Suggestion = KnownAssumptionIt.getKey();
28353 BestEditDistance = EditDistance;
28354 }
28355 }
28356
28357 if (!Suggestion.empty())
28358 S.Diag(Loc, DiagID: diag::warn_omp_assume_attribute_string_unknown_suggested)
28359 << AssumptionStr << Suggestion;
28360 else
28361 S.Diag(Loc, DiagID: diag::warn_omp_assume_attribute_string_unknown)
28362 << AssumptionStr;
28363}
28364
28365void SemaOpenMP::handleOMPAssumeAttr(Decl *D, const ParsedAttr &AL) {
28366 // Handle the case where the attribute has a text message.
28367 StringRef Str;
28368 SourceLocation AttrStrLoc;
28369 if (!SemaRef.checkStringLiteralArgumentAttr(Attr: AL, ArgNum: 0, Str, ArgLocation: &AttrStrLoc))
28370 return;
28371
28372 checkOMPAssumeAttr(S&: SemaRef, Loc: AttrStrLoc, AssumptionStr: Str);
28373
28374 D->addAttr(A: ::new (getASTContext()) OMPAssumeAttr(getASTContext(), AL, Str));
28375}
28376
28377SemaOpenMP::SemaOpenMP(Sema &S)
28378 : SemaBase(S), VarDataSharingAttributesStack(nullptr) {}
28379