Changeset View
Changeset View
Standalone View
Standalone View
clang/lib/Sema/SemaOpenMP.cpp
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
//===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ---------===// | //===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ---------===// | ||||
Lint: Lint: clang-format not found in user's PATH; not linting file. | |||||
// | // | ||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||
// See https://llvm.org/LICENSE.txt for license information. | // See https://llvm.org/LICENSE.txt for license information. | ||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||
// | // | ||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
/// \file | /// \file | ||||
Show All 21 Lines | |||||
#include "clang/Sema/Initialization.h" | #include "clang/Sema/Initialization.h" | ||||
#include "clang/Sema/Lookup.h" | #include "clang/Sema/Lookup.h" | ||||
#include "clang/Sema/Scope.h" | #include "clang/Sema/Scope.h" | ||||
#include "clang/Sema/ScopeInfo.h" | #include "clang/Sema/ScopeInfo.h" | ||||
#include "clang/Sema/SemaInternal.h" | #include "clang/Sema/SemaInternal.h" | ||||
#include "llvm/ADT/IndexedMap.h" | #include "llvm/ADT/IndexedMap.h" | ||||
#include "llvm/ADT/PointerEmbeddedInt.h" | #include "llvm/ADT/PointerEmbeddedInt.h" | ||||
#include "llvm/ADT/STLExtras.h" | #include "llvm/ADT/STLExtras.h" | ||||
#include "llvm/ADT/StringExtras.h" | |||||
#include "llvm/Frontend/OpenMP/OMPConstants.h" | #include "llvm/Frontend/OpenMP/OMPConstants.h" | ||||
#include <set> | #include <set> | ||||
using namespace clang; | using namespace clang; | ||||
using namespace llvm::omp; | using namespace llvm::omp; | ||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
// Stack of data-sharing attributes for variables | // Stack of data-sharing attributes for variables | ||||
▲ Show 20 Lines • Show All 3,207 Lines • ▼ Show 20 Lines | class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> { | ||||
CapturedStmt *CS = nullptr; | CapturedStmt *CS = nullptr; | ||||
llvm::SmallVector<Expr *, 4> ImplicitFirstprivate; | llvm::SmallVector<Expr *, 4> ImplicitFirstprivate; | ||||
llvm::SmallVector<Expr *, 4> ImplicitMap[OMPC_MAP_delete]; | llvm::SmallVector<Expr *, 4> ImplicitMap[OMPC_MAP_delete]; | ||||
Sema::VarsWithInheritedDSAType VarsWithInheritedDSA; | Sema::VarsWithInheritedDSAType VarsWithInheritedDSA; | ||||
llvm::SmallDenseSet<const ValueDecl *, 4> ImplicitDeclarations; | llvm::SmallDenseSet<const ValueDecl *, 4> ImplicitDeclarations; | ||||
void VisitSubCaptures(OMPExecutableDirective *S) { | void VisitSubCaptures(OMPExecutableDirective *S) { | ||||
// Check implicitly captured variables. | // Check implicitly captured variables. | ||||
if (!S->hasAssociatedStmt() || !S->getAssociatedStmt()) | if (!S->hasAssociatedStmt() || !S->getAssociatedStmt() || | ||||
isOpenMPLoopTransformationDirective(S->getDirectiveKind())) | |||||
return; | return; | ||||
visitSubCaptures(S->getInnermostCapturedStmt()); | visitSubCaptures(S->getInnermostCapturedStmt()); | ||||
// Try to capture inner this->member references to generate correct mappings | // Try to capture inner this->member references to generate correct mappings | ||||
// and diagnostics. | // and diagnostics. | ||||
if (TryCaptureCXXThisMembers || | if (TryCaptureCXXThisMembers || | ||||
(isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()) && | (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()) && | ||||
llvm::any_of(S->getInnermostCapturedStmt()->captures(), | llvm::any_of(S->getInnermostCapturedStmt()->captures(), | ||||
[](const CapturedStmt::Capture &C) { | [](const CapturedStmt::Capture &C) { | ||||
▲ Show 20 Lines • Show All 319 Lines • ▼ Show 20 Lines | for (OMPClause *C : S->clauses()) { | ||||
if (CC) | if (CC) | ||||
Visit(CC); | Visit(CC); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Check implicitly captured variables. | // Check implicitly captured variables. | ||||
VisitSubCaptures(S); | VisitSubCaptures(S); | ||||
} | } | ||||
void VisitOMPTileDirective(OMPTileDirective *S) { | |||||
// #pragma omp tile does not introduce data sharing. | |||||
VisitStmt(S); | |||||
} | |||||
void VisitStmt(Stmt *S) { | void VisitStmt(Stmt *S) { | ||||
for (Stmt *C : S->children()) { | for (Stmt *C : S->children()) { | ||||
if (C) { | if (C) { | ||||
// Check implicitly captured variables in the task-based directives to | // Check implicitly captured variables in the task-based directives to | ||||
// check if they must be firstprivatized. | // check if they must be firstprivatized. | ||||
Visit(C); | Visit(C); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 419 Lines • ▼ Show 20 Lines | case OMPD_target_exit_data: { | ||||
// Mark this captured region as inlined, because we don't use outlined | // Mark this captured region as inlined, because we don't use outlined | ||||
// function directly. | // function directly. | ||||
getCurCapturedRegion()->TheCapturedDecl->addAttr( | getCurCapturedRegion()->TheCapturedDecl->addAttr( | ||||
AlwaysInlineAttr::CreateImplicit( | AlwaysInlineAttr::CreateImplicit( | ||||
Context, {}, AttributeCommonInfo::AS_Keyword, | Context, {}, AttributeCommonInfo::AS_Keyword, | ||||
AlwaysInlineAttr::Keyword_forceinline)); | AlwaysInlineAttr::Keyword_forceinline)); | ||||
break; | break; | ||||
} | } | ||||
case OMPD_tile: | |||||
// loop transformations have no captures. | |||||
break; | |||||
case OMPD_threadprivate: | case OMPD_threadprivate: | ||||
case OMPD_allocate: | case OMPD_allocate: | ||||
case OMPD_taskyield: | case OMPD_taskyield: | ||||
case OMPD_barrier: | case OMPD_barrier: | ||||
case OMPD_taskwait: | case OMPD_taskwait: | ||||
case OMPD_cancellation_point: | case OMPD_cancellation_point: | ||||
case OMPD_cancel: | case OMPD_cancel: | ||||
case OMPD_flush: | case OMPD_flush: | ||||
▲ Show 20 Lines • Show All 220 Lines • ▼ Show 20 Lines | if (isOpenMPPrivate(Clause->getClauseKind()) || | ||||
DSAStack->setForceVarCapturing(Clause->getClauseKind() == OMPC_copyin); | DSAStack->setForceVarCapturing(Clause->getClauseKind() == OMPC_copyin); | ||||
// Mark all variables in private list clauses as used in inner region. | // Mark all variables in private list clauses as used in inner region. | ||||
for (Stmt *VarRef : Clause->children()) { | for (Stmt *VarRef : Clause->children()) { | ||||
if (auto *E = cast_or_null<Expr>(VarRef)) { | if (auto *E = cast_or_null<Expr>(VarRef)) { | ||||
MarkDeclarationsReferencedInExpr(E); | MarkDeclarationsReferencedInExpr(E); | ||||
} | } | ||||
} | } | ||||
DSAStack->setForceVarCapturing(/*V=*/false); | DSAStack->setForceVarCapturing(/*V=*/false); | ||||
} else if (isOpenMPLoopTransformationDirective( | |||||
DSAStack->getCurrentDirective())) { | |||||
assert(CaptureRegions.empty()); | |||||
} else if (CaptureRegions.size() > 1 || | } else if (CaptureRegions.size() > 1 || | ||||
CaptureRegions.back() != OMPD_unknown) { | CaptureRegions.back() != OMPD_unknown) { | ||||
if (auto *C = OMPClauseWithPreInit::get(Clause)) | if (auto *C = OMPClauseWithPreInit::get(Clause)) | ||||
PICs.push_back(C); | PICs.push_back(C); | ||||
if (auto *C = OMPClauseWithPostUpdate::get(Clause)) { | if (auto *C = OMPClauseWithPostUpdate::get(Clause)) { | ||||
if (Expr *E = C->getPostUpdateExpr()) | if (Expr *E = C->getPostUpdateExpr()) | ||||
MarkDeclarationsReferencedInExpr(E); | MarkDeclarationsReferencedInExpr(E); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 658 Lines • ▼ Show 20 Lines | if (checkCancelRegion(*this, Kind, CancelRegion, StartLoc) || | ||||
checkNestingOfRegions(*this, DSAStack, Kind, DirName, CancelRegion, | checkNestingOfRegions(*this, DSAStack, Kind, DirName, CancelRegion, | ||||
StartLoc)) | StartLoc)) | ||||
return StmtError(); | return StmtError(); | ||||
llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit; | llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit; | ||||
VarsWithInheritedDSAType VarsWithInheritedDSA; | VarsWithInheritedDSAType VarsWithInheritedDSA; | ||||
bool ErrorFound = false; | bool ErrorFound = false; | ||||
ClausesWithImplicit.append(Clauses.begin(), Clauses.end()); | ClausesWithImplicit.append(Clauses.begin(), Clauses.end()); | ||||
if (AStmt && !CurContext->isDependentContext()) { | if (AStmt && !CurContext->isDependentContext() && | ||||
!isOpenMPLoopTransformationDirective(Kind)) { | |||||
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); | assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); | ||||
// Check default data sharing attributes for referenced variables. | // Check default data sharing attributes for referenced variables. | ||||
DSAAttrChecker DSAChecker(DSAStack, *this, cast<CapturedStmt>(AStmt)); | DSAAttrChecker DSAChecker(DSAStack, *this, cast<CapturedStmt>(AStmt)); | ||||
int ThisCaptureLevel = getOpenMPCaptureLevels(Kind); | int ThisCaptureLevel = getOpenMPCaptureLevels(Kind); | ||||
Stmt *S = AStmt; | Stmt *S = AStmt; | ||||
while (--ThisCaptureLevel >= 0) | while (--ThisCaptureLevel >= 0) | ||||
S = cast<CapturedStmt>(S)->getCapturedStmt(); | S = cast<CapturedStmt>(S)->getCapturedStmt(); | ||||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | case OMPD_parallel: | ||||
AllowedNameModifiers.push_back(OMPD_parallel); | AllowedNameModifiers.push_back(OMPD_parallel); | ||||
break; | break; | ||||
case OMPD_simd: | case OMPD_simd: | ||||
Res = ActOnOpenMPSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, | Res = ActOnOpenMPSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, | ||||
VarsWithInheritedDSA); | VarsWithInheritedDSA); | ||||
if (LangOpts.OpenMP >= 50) | if (LangOpts.OpenMP >= 50) | ||||
AllowedNameModifiers.push_back(OMPD_simd); | AllowedNameModifiers.push_back(OMPD_simd); | ||||
break; | break; | ||||
case OMPD_tile: | |||||
Res = ActOnOpenMPTileDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, | |||||
VarsWithInheritedDSA); | |||||
break; | |||||
case OMPD_for: | case OMPD_for: | ||||
Res = ActOnOpenMPForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, | Res = ActOnOpenMPForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, | ||||
VarsWithInheritedDSA); | VarsWithInheritedDSA); | ||||
break; | break; | ||||
case OMPD_for_simd: | case OMPD_for_simd: | ||||
Res = ActOnOpenMPForSimdDirective(ClausesWithImplicit, AStmt, StartLoc, | Res = ActOnOpenMPForSimdDirective(ClausesWithImplicit, AStmt, StartLoc, | ||||
EndLoc, VarsWithInheritedDSA); | EndLoc, VarsWithInheritedDSA); | ||||
if (LangOpts.OpenMP >= 50) | if (LangOpts.OpenMP >= 50) | ||||
▲ Show 20 Lines • Show All 331 Lines • ▼ Show 20 Lines | for (OMPClause *C : Clauses) { | ||||
case OMPC_ordered: | case OMPC_ordered: | ||||
case OMPC_device: | case OMPC_device: | ||||
case OMPC_num_teams: | case OMPC_num_teams: | ||||
case OMPC_thread_limit: | case OMPC_thread_limit: | ||||
case OMPC_hint: | case OMPC_hint: | ||||
case OMPC_collapse: | case OMPC_collapse: | ||||
case OMPC_safelen: | case OMPC_safelen: | ||||
case OMPC_simdlen: | case OMPC_simdlen: | ||||
case OMPC_sizes: | |||||
case OMPC_default: | case OMPC_default: | ||||
case OMPC_proc_bind: | case OMPC_proc_bind: | ||||
case OMPC_private: | case OMPC_private: | ||||
case OMPC_firstprivate: | case OMPC_firstprivate: | ||||
case OMPC_lastprivate: | case OMPC_lastprivate: | ||||
case OMPC_shared: | case OMPC_shared: | ||||
case OMPC_reduction: | case OMPC_reduction: | ||||
case OMPC_task_reduction: | case OMPC_task_reduction: | ||||
▲ Show 20 Lines • Show All 819 Lines • ▼ Show 20 Lines | StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, | ||||
return OMPParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, | return OMPParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, | ||||
DSAStack->getTaskgroupReductionRef(), | DSAStack->getTaskgroupReductionRef(), | ||||
DSAStack->isCancelRegion()); | DSAStack->isCancelRegion()); | ||||
} | } | ||||
namespace { | namespace { | ||||
/// Iteration space of a single for loop. | /// Iteration space of a single for loop. | ||||
struct LoopIterationSpace final { | struct LoopIterationSpace final { | ||||
/// The loop that has been analyzed. | |||||
Stmt *Loop = nullptr; | |||||
/// The loop's body. | |||||
Stmt *Body = nullptr; | |||||
/// True if the condition operator is the strict compare operator (<, > or | /// True if the condition operator is the strict compare operator (<, > or | ||||
/// !=). | /// !=). | ||||
bool IsStrictCompare = false; | bool IsStrictCompare = false; | ||||
/// Condition of the loop. | /// Condition of the loop. | ||||
Expr *PreCond = nullptr; | Expr *PreCond = nullptr; | ||||
/// This expression calculates the number of iterations in the loop. | /// This expression calculates the number of iterations in the loop. | ||||
/// It is always possible to calculate it before starting the loop. | /// It is always possible to calculate it before starting the loop. | ||||
Expr *NumIterations = nullptr; | Expr *NumIterations = nullptr; | ||||
Show All 36 Lines | |||||
}; | }; | ||||
/// Helper class for checking canonical form of the OpenMP loops and | /// Helper class for checking canonical form of the OpenMP loops and | ||||
/// extracting iteration space of each loop in the loop nest, that will be used | /// extracting iteration space of each loop in the loop nest, that will be used | ||||
/// for IR generation. | /// for IR generation. | ||||
class OpenMPIterationSpaceChecker { | class OpenMPIterationSpaceChecker { | ||||
/// Reference to Sema. | /// Reference to Sema. | ||||
Sema &SemaRef; | Sema &SemaRef; | ||||
/// Is the loop associated directive capturing its referenced variables? | |||||
bool Capturing; | |||||
/// Does the loop associated directive support non-rectangular loops? | |||||
bool SupportsNonRectangular; | |||||
/// Data-sharing stack. | /// Data-sharing stack. | ||||
DSAStackTy &Stack; | DSAStackTy &Stack; | ||||
/// A location for diagnostics (when there is no some better location). | /// A location for diagnostics (when there is no some better location). | ||||
SourceLocation DefaultLoc; | SourceLocation DefaultLoc; | ||||
/// A location for diagnostics (when increment is not compatible). | /// A location for diagnostics (when increment is not compatible). | ||||
SourceLocation ConditionLoc; | SourceLocation ConditionLoc; | ||||
/// A source location for referring to loop init later. | /// A source location for referring to loop init later. | ||||
SourceRange InitSrcRange; | SourceRange InitSrcRange; | ||||
Show All 32 Lines | class OpenMPIterationSpaceChecker { | ||||
Optional<unsigned> CondDependOnLC; | Optional<unsigned> CondDependOnLC; | ||||
/// Checks if the provide statement depends on the loop counter. | /// Checks if the provide statement depends on the loop counter. | ||||
Optional<unsigned> doesDependOnLoopCounter(const Stmt *S, bool IsInitializer); | Optional<unsigned> doesDependOnLoopCounter(const Stmt *S, bool IsInitializer); | ||||
/// Original condition required for checking of the exit condition for | /// Original condition required for checking of the exit condition for | ||||
/// non-rectangular loop. | /// non-rectangular loop. | ||||
Expr *Condition = nullptr; | Expr *Condition = nullptr; | ||||
public: | public: | ||||
OpenMPIterationSpaceChecker(Sema &SemaRef, DSAStackTy &Stack, | OpenMPIterationSpaceChecker(Sema &SemaRef, bool Capturing, | ||||
bool SupportsNonRectangular, DSAStackTy &Stack, | |||||
SourceLocation DefaultLoc) | SourceLocation DefaultLoc) | ||||
: SemaRef(SemaRef), Stack(Stack), DefaultLoc(DefaultLoc), | : SemaRef(SemaRef), Capturing(Capturing), | ||||
ConditionLoc(DefaultLoc) {} | SupportsNonRectangular(SupportsNonRectangular), Stack(Stack), | ||||
DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc) {} | |||||
/// Check init-expr for canonical loop form and save loop counter | /// Check init-expr for canonical loop form and save loop counter | ||||
/// variable - #Var and its initialization value - #LB. | /// variable - #Var and its initialization value - #LB. | ||||
bool checkAndSetInit(Stmt *S, bool EmitDiags = true); | bool checkAndSetInit(Stmt *S, bool EmitDiags = true); | ||||
/// Check test-expr for canonical form, save upper-bound (#UB), flags | /// Check test-expr for canonical form, save upper-bound (#UB), flags | ||||
/// for less/greater and for strict/non-strict comparison. | /// for less/greater and for strict/non-strict comparison. | ||||
bool checkAndSetCond(Expr *S); | bool checkAndSetCond(Expr *S, bool EmitDiags = true); | ||||
/// Check incr-expr for canonical loop form and return true if it | /// Check incr-expr for canonical loop form and return true if it | ||||
/// does not conform, otherwise save loop step (#Step). | /// does not conform, otherwise save loop step (#Step). | ||||
bool checkAndSetInc(Expr *S); | bool checkAndSetInc(Expr *S); | ||||
/// Return the loop counter variable. | /// Return the loop counter variable. | ||||
ValueDecl *getLoopDecl() const { return LCDecl; } | ValueDecl *getLoopDecl() const { return LCDecl; } | ||||
/// Return the reference expression to loop counter variable. | /// Return the reference expression to loop counter variable. | ||||
Expr *getLoopDeclRefExpr() const { return LCRef; } | Expr *getLoopDeclRefExpr() const { return LCRef; } | ||||
/// Source range of the loop init. | /// Source range of the loop init. | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | private: | ||||
/// Check the right-hand side of an assignment in the increment | /// Check the right-hand side of an assignment in the increment | ||||
/// expression. | /// expression. | ||||
bool checkAndSetIncRHS(Expr *RHS); | bool checkAndSetIncRHS(Expr *RHS); | ||||
/// Helper to set loop counter variable and its initializer. | /// Helper to set loop counter variable and its initializer. | ||||
bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB, | bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB, | ||||
bool EmitDiags); | bool EmitDiags); | ||||
/// Helper to set upper bound. | /// Helper to set upper bound. | ||||
bool setUB(Expr *NewUB, llvm::Optional<bool> LessOp, bool StrictOp, | bool setUB(Expr *NewUB, llvm::Optional<bool> LessOp, bool StrictOp, | ||||
SourceRange SR, SourceLocation SL); | SourceRange SR, SourceLocation SL, bool EmitDiags = true); | ||||
/// Helper to set loop increment. | /// Helper to set loop increment. | ||||
bool setStep(Expr *NewStep, bool Subtract); | bool setStep(Expr *NewStep, bool Subtract); | ||||
}; | }; | ||||
bool OpenMPIterationSpaceChecker::dependent() const { | bool OpenMPIterationSpaceChecker::dependent() const { | ||||
if (!LCDecl) { | if (!LCDecl) { | ||||
assert(!LB && !UB && !Step); | assert(!LB && !UB && !Step); | ||||
return false; | return false; | ||||
Show All 23 Lines | bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl, | ||||
if (EmitDiags) | if (EmitDiags) | ||||
InitDependOnLC = doesDependOnLoopCounter(LB, /*IsInitializer=*/true); | InitDependOnLC = doesDependOnLoopCounter(LB, /*IsInitializer=*/true); | ||||
return false; | return false; | ||||
} | } | ||||
bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, | bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, | ||||
llvm::Optional<bool> LessOp, | llvm::Optional<bool> LessOp, | ||||
bool StrictOp, SourceRange SR, | bool StrictOp, SourceRange SR, | ||||
SourceLocation SL) { | SourceLocation SL, bool EmitDiags) { | ||||
// State consistency checking to ensure correct usage. | // State consistency checking to ensure correct usage. | ||||
assert(LCDecl != nullptr && LB != nullptr && UB == nullptr && | assert(LCDecl != nullptr && LB != nullptr && UB == nullptr && | ||||
Step == nullptr && !TestIsLessOp && !TestIsStrictOp); | Step == nullptr && !TestIsLessOp && !TestIsStrictOp); | ||||
if (!NewUB) | if (!NewUB) | ||||
return true; | return true; | ||||
UB = NewUB; | UB = NewUB; | ||||
if (LessOp) | if (LessOp) | ||||
TestIsLessOp = LessOp; | TestIsLessOp = LessOp; | ||||
TestIsStrictOp = StrictOp; | TestIsStrictOp = StrictOp; | ||||
ConditionSrcRange = SR; | ConditionSrcRange = SR; | ||||
ConditionLoc = SL; | ConditionLoc = SL; | ||||
if (EmitDiags) | |||||
CondDependOnLC = doesDependOnLoopCounter(UB, /*IsInitializer=*/false); | CondDependOnLC = doesDependOnLoopCounter(UB, /*IsInitializer=*/false); | ||||
return false; | return false; | ||||
} | } | ||||
bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) { | bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) { | ||||
// State consistency checking to ensure correct usage. | // State consistency checking to ensure correct usage. | ||||
assert(LCDecl != nullptr && LB != nullptr && Step == nullptr); | assert(LCDecl != nullptr && LB != nullptr && Step == nullptr); | ||||
if (!NewStep) | if (!NewStep) | ||||
return true; | return true; | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | |||||
class LoopCounterRefChecker final | class LoopCounterRefChecker final | ||||
: public ConstStmtVisitor<LoopCounterRefChecker, bool> { | : public ConstStmtVisitor<LoopCounterRefChecker, bool> { | ||||
Sema &SemaRef; | Sema &SemaRef; | ||||
DSAStackTy &Stack; | DSAStackTy &Stack; | ||||
const ValueDecl *CurLCDecl = nullptr; | const ValueDecl *CurLCDecl = nullptr; | ||||
const ValueDecl *DepDecl = nullptr; | const ValueDecl *DepDecl = nullptr; | ||||
const ValueDecl *PrevDepDecl = nullptr; | const ValueDecl *PrevDepDecl = nullptr; | ||||
bool IsInitializer = true; | bool IsInitializer = true; | ||||
bool SupportsNonRectangular; | |||||
unsigned BaseLoopId = 0; | unsigned BaseLoopId = 0; | ||||
bool checkDecl(const Expr *E, const ValueDecl *VD) { | bool checkDecl(const Expr *E, const ValueDecl *VD) { | ||||
if (getCanonicalDecl(VD) == getCanonicalDecl(CurLCDecl)) { | if (getCanonicalDecl(VD) == getCanonicalDecl(CurLCDecl)) { | ||||
SemaRef.Diag(E->getExprLoc(), diag::err_omp_stmt_depends_on_loop_counter) | SemaRef.Diag(E->getExprLoc(), diag::err_omp_stmt_depends_on_loop_counter) | ||||
<< (IsInitializer ? 0 : 1); | << (IsInitializer ? 0 : 1); | ||||
return false; | return false; | ||||
} | } | ||||
const auto &&Data = Stack.isLoopControlVariable(VD); | const auto &&Data = Stack.isLoopControlVariable(VD); | ||||
// OpenMP, 2.9.1 Canonical Loop Form, Restrictions. | // OpenMP, 2.9.1 Canonical Loop Form, Restrictions. | ||||
// The type of the loop iterator on which we depend may not have a random | // The type of the loop iterator on which we depend may not have a random | ||||
// access iterator type. | // access iterator type. | ||||
if (Data.first && VD->getType()->isRecordType()) { | if (Data.first && VD->getType()->isRecordType()) { | ||||
SmallString<128> Name; | SmallString<128> Name; | ||||
llvm::raw_svector_ostream OS(Name); | llvm::raw_svector_ostream OS(Name); | ||||
VD->getNameForDiagnostic(OS, SemaRef.getPrintingPolicy(), | VD->getNameForDiagnostic(OS, SemaRef.getPrintingPolicy(), | ||||
/*Qualified=*/true); | /*Qualified=*/true); | ||||
SemaRef.Diag(E->getExprLoc(), | SemaRef.Diag(E->getExprLoc(), | ||||
diag::err_omp_wrong_dependency_iterator_type) | diag::err_omp_wrong_dependency_iterator_type) | ||||
<< OS.str(); | << OS.str(); | ||||
SemaRef.Diag(VD->getLocation(), diag::note_previous_decl) << VD; | SemaRef.Diag(VD->getLocation(), diag::note_previous_decl) << VD; | ||||
return false; | return false; | ||||
} | } | ||||
if (Data.first && !SupportsNonRectangular) { | |||||
SemaRef.Diag(E->getExprLoc(), diag::err_omp_invariant_dependency); | |||||
return false; | |||||
} | |||||
if (Data.first && | if (Data.first && | ||||
(DepDecl || (PrevDepDecl && | (DepDecl || (PrevDepDecl && | ||||
getCanonicalDecl(VD) != getCanonicalDecl(PrevDepDecl)))) { | getCanonicalDecl(VD) != getCanonicalDecl(PrevDepDecl)))) { | ||||
if (!DepDecl && PrevDepDecl) | if (!DepDecl && PrevDepDecl) | ||||
DepDecl = PrevDepDecl; | DepDecl = PrevDepDecl; | ||||
SmallString<128> Name; | SmallString<128> Name; | ||||
llvm::raw_svector_ostream OS(Name); | llvm::raw_svector_ostream OS(Name); | ||||
DepDecl->getNameForDiagnostic(OS, SemaRef.getPrintingPolicy(), | DepDecl->getNameForDiagnostic(OS, SemaRef.getPrintingPolicy(), | ||||
Show All 28 Lines | public: | ||||
bool VisitStmt(const Stmt *S) { | bool VisitStmt(const Stmt *S) { | ||||
bool Res = false; | bool Res = false; | ||||
for (const Stmt *Child : S->children()) | for (const Stmt *Child : S->children()) | ||||
Res = (Child && Visit(Child)) || Res; | Res = (Child && Visit(Child)) || Res; | ||||
return Res; | return Res; | ||||
} | } | ||||
explicit LoopCounterRefChecker(Sema &SemaRef, DSAStackTy &Stack, | explicit LoopCounterRefChecker(Sema &SemaRef, DSAStackTy &Stack, | ||||
const ValueDecl *CurLCDecl, bool IsInitializer, | const ValueDecl *CurLCDecl, bool IsInitializer, | ||||
const ValueDecl *PrevDepDecl = nullptr) | const ValueDecl *PrevDepDecl = nullptr, | ||||
bool SupportsNonRectangular = true) | |||||
: SemaRef(SemaRef), Stack(Stack), CurLCDecl(CurLCDecl), | : SemaRef(SemaRef), Stack(Stack), CurLCDecl(CurLCDecl), | ||||
PrevDepDecl(PrevDepDecl), IsInitializer(IsInitializer) {} | PrevDepDecl(PrevDepDecl), IsInitializer(IsInitializer), | ||||
SupportsNonRectangular(SupportsNonRectangular) {} | |||||
unsigned getBaseLoopId() const { | unsigned getBaseLoopId() const { | ||||
assert(CurLCDecl && "Expected loop dependency."); | assert(CurLCDecl && "Expected loop dependency."); | ||||
return BaseLoopId; | return BaseLoopId; | ||||
} | } | ||||
const ValueDecl *getDepDecl() const { | const ValueDecl *getDepDecl() const { | ||||
assert(CurLCDecl && "Expected loop dependency."); | assert(CurLCDecl && "Expected loop dependency."); | ||||
return DepDecl; | return DepDecl; | ||||
} | } | ||||
}; | }; | ||||
} // namespace | } // namespace | ||||
Optional<unsigned> | Optional<unsigned> | ||||
OpenMPIterationSpaceChecker::doesDependOnLoopCounter(const Stmt *S, | OpenMPIterationSpaceChecker::doesDependOnLoopCounter(const Stmt *S, | ||||
bool IsInitializer) { | bool IsInitializer) { | ||||
// Check for the non-rectangular loops. | // Check for the non-rectangular loops. | ||||
LoopCounterRefChecker LoopStmtChecker(SemaRef, Stack, LCDecl, IsInitializer, | LoopCounterRefChecker LoopStmtChecker(SemaRef, Stack, LCDecl, IsInitializer, | ||||
DepDecl); | DepDecl, SupportsNonRectangular); | ||||
if (LoopStmtChecker.Visit(S)) { | if (LoopStmtChecker.Visit(S)) { | ||||
DepDecl = LoopStmtChecker.getDepDecl(); | DepDecl = LoopStmtChecker.getDepDecl(); | ||||
return LoopStmtChecker.getBaseLoopId(); | return LoopStmtChecker.getBaseLoopId(); | ||||
} | } | ||||
return llvm::None; | return llvm::None; | ||||
} | } | ||||
bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) { | bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) { | ||||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) | ||||
return getCanonicalDecl(VD); | return getCanonicalDecl(VD); | ||||
} | } | ||||
if (const auto *ME = dyn_cast_or_null<MemberExpr>(E)) | if (const auto *ME = dyn_cast_or_null<MemberExpr>(E)) | ||||
if (ME->isArrow() && isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) | if (ME->isArrow() && isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) | ||||
return getCanonicalDecl(ME->getMemberDecl()); | return getCanonicalDecl(ME->getMemberDecl()); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) { | bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S, bool EmitDiags) { | ||||
// Check test-expr for canonical form, save upper-bound UB, flags for | // Check test-expr for canonical form, save upper-bound UB, flags for | ||||
// less/greater and for strict/non-strict comparison. | // less/greater and for strict/non-strict comparison. | ||||
// OpenMP [2.9] Canonical loop form. Test-expr may be one of the following: | // OpenMP [2.9] Canonical loop form. Test-expr may be one of the following: | ||||
// var relational-op b | // var relational-op b | ||||
// b relational-op var | // b relational-op var | ||||
// | // | ||||
bool IneqCondIsCanonical = SemaRef.getLangOpts().OpenMP >= 50; | bool IneqCondIsCanonical = SemaRef.getLangOpts().OpenMP >= 50; | ||||
if (!S) { | if (!S) { | ||||
SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) | SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) | ||||
<< (IneqCondIsCanonical ? 1 : 0) << LCDecl; | << (IneqCondIsCanonical ? 1 : 0) << LCDecl; | ||||
return true; | return true; | ||||
} | } | ||||
Condition = S; | Condition = S; | ||||
S = getExprAsWritten(S); | S = getExprAsWritten(S); | ||||
SourceLocation CondLoc = S->getBeginLoc(); | SourceLocation CondLoc = S->getBeginLoc(); | ||||
if (auto *BO = dyn_cast<BinaryOperator>(S)) { | if (auto *BO = dyn_cast<BinaryOperator>(S)) { | ||||
if (BO->isRelationalOp()) { | if (BO->isRelationalOp()) { | ||||
if (getInitLCDecl(BO->getLHS()) == LCDecl) | if (getInitLCDecl(BO->getLHS()) == LCDecl) | ||||
return setUB(BO->getRHS(), | return setUB(BO->getRHS(), | ||||
(BO->getOpcode() == BO_LT || BO->getOpcode() == BO_LE), | (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_LE), | ||||
(BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), | (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), | ||||
BO->getSourceRange(), BO->getOperatorLoc()); | BO->getSourceRange(), BO->getOperatorLoc(), EmitDiags); | ||||
if (getInitLCDecl(BO->getRHS()) == LCDecl) | if (getInitLCDecl(BO->getRHS()) == LCDecl) | ||||
return setUB(BO->getLHS(), | return setUB(BO->getLHS(), | ||||
(BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE), | (BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE), | ||||
(BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), | (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), | ||||
BO->getSourceRange(), BO->getOperatorLoc()); | BO->getSourceRange(), BO->getOperatorLoc(), EmitDiags); | ||||
} else if (IneqCondIsCanonical && BO->getOpcode() == BO_NE) | } else if (IneqCondIsCanonical && BO->getOpcode() == BO_NE) | ||||
return setUB( | return setUB(getInitLCDecl(BO->getLHS()) == LCDecl ? BO->getRHS() | ||||
getInitLCDecl(BO->getLHS()) == LCDecl ? BO->getRHS() : BO->getLHS(), | : BO->getLHS(), | ||||
/*LessOp=*/llvm::None, | /*LessOp=*/llvm::None, | ||||
/*StrictOp=*/true, BO->getSourceRange(), BO->getOperatorLoc()); | /*StrictOp=*/true, BO->getSourceRange(), | ||||
BO->getOperatorLoc(), EmitDiags); | |||||
} else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(S)) { | } else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(S)) { | ||||
if (CE->getNumArgs() == 2) { | if (CE->getNumArgs() == 2) { | ||||
auto Op = CE->getOperator(); | auto Op = CE->getOperator(); | ||||
switch (Op) { | switch (Op) { | ||||
case OO_Greater: | case OO_Greater: | ||||
case OO_GreaterEqual: | case OO_GreaterEqual: | ||||
case OO_Less: | case OO_Less: | ||||
case OO_LessEqual: | case OO_LessEqual: | ||||
if (getInitLCDecl(CE->getArg(0)) == LCDecl) | if (getInitLCDecl(CE->getArg(0)) == LCDecl) | ||||
return setUB(CE->getArg(1), Op == OO_Less || Op == OO_LessEqual, | return setUB(CE->getArg(1), Op == OO_Less || Op == OO_LessEqual, | ||||
Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), | Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), | ||||
CE->getOperatorLoc()); | CE->getOperatorLoc(), EmitDiags); | ||||
if (getInitLCDecl(CE->getArg(1)) == LCDecl) | if (getInitLCDecl(CE->getArg(1)) == LCDecl) | ||||
return setUB(CE->getArg(0), Op == OO_Greater || Op == OO_GreaterEqual, | return setUB(CE->getArg(0), Op == OO_Greater || Op == OO_GreaterEqual, | ||||
Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), | Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), | ||||
CE->getOperatorLoc()); | CE->getOperatorLoc(), EmitDiags); | ||||
break; | break; | ||||
case OO_ExclaimEqual: | case OO_ExclaimEqual: | ||||
if (IneqCondIsCanonical) | if (IneqCondIsCanonical) | ||||
return setUB(getInitLCDecl(CE->getArg(0)) == LCDecl ? CE->getArg(1) | return setUB(getInitLCDecl(CE->getArg(0)) == LCDecl ? CE->getArg(1) | ||||
: CE->getArg(0), | : CE->getArg(0), | ||||
/*LessOp=*/llvm::None, | /*LessOp=*/llvm::None, | ||||
/*StrictOp=*/true, CE->getSourceRange(), | /*StrictOp=*/true, CE->getSourceRange(), | ||||
CE->getOperatorLoc()); | CE->getOperatorLoc(), EmitDiags); | ||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (dependent() || SemaRef.CurContext->isDependentContext()) | if (dependent() || SemaRef.CurContext->isDependentContext()) | ||||
return false; | return false; | ||||
▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | if (dependent() || SemaRef.CurContext->isDependentContext()) | ||||
return false; | return false; | ||||
SemaRef.Diag(S->getBeginLoc(), diag::err_omp_loop_not_canonical_incr) | SemaRef.Diag(S->getBeginLoc(), diag::err_omp_loop_not_canonical_incr) | ||||
<< S->getSourceRange() << LCDecl; | << S->getSourceRange() << LCDecl; | ||||
return true; | return true; | ||||
} | } | ||||
static ExprResult | static ExprResult | ||||
tryBuildCapture(Sema &SemaRef, Expr *Capture, | tryBuildCapture(Sema &SemaRef, Expr *Capture, | ||||
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { | llvm::MapVector<const Expr *, DeclRefExpr *> &Captures, | ||||
if (SemaRef.CurContext->isDependentContext() || Capture->containsErrors()) | bool Capturing = true) { | ||||
if (!Capturing || SemaRef.CurContext->isDependentContext() || | |||||
Capture->containsErrors()) | |||||
return Capture; | return Capture; | ||||
if (Capture->isEvaluatable(SemaRef.Context, Expr::SE_AllowSideEffects)) | if (Capture->isEvaluatable(SemaRef.Context, Expr::SE_AllowSideEffects)) | ||||
return SemaRef.PerformImplicitConversion( | return SemaRef.PerformImplicitConversion( | ||||
Capture->IgnoreImpCasts(), Capture->getType(), Sema::AA_Converting, | Capture->IgnoreImpCasts(), Capture->getType(), Sema::AA_Converting, | ||||
/*AllowExplicit=*/true); | /*AllowExplicit=*/true); | ||||
auto I = Captures.find(Capture); | auto I = Captures.find(Capture); | ||||
if (I != Captures.end()) | if (I != Captures.end()) | ||||
return buildCapture(SemaRef, Capture, I->second); | return buildCapture(SemaRef, Capture, I->second); | ||||
DeclRefExpr *Ref = nullptr; | DeclRefExpr *Ref = nullptr; | ||||
ExprResult Res = buildCapture(SemaRef, Capture, Ref); | ExprResult Res = buildCapture(SemaRef, Capture, Ref); | ||||
Captures[Capture] = Ref; | Captures[Capture] = Ref; | ||||
return Res; | return Res; | ||||
} | } | ||||
/// Calculate number of iterations, transforming to unsigned, if number of | /// Calculate number of iterations, transforming to unsigned, if number of | ||||
/// iterations may be larger than the original type. | /// iterations may be larger than the original type. | ||||
static Expr * | static Expr * | ||||
calculateNumIters(Sema &SemaRef, Scope *S, SourceLocation DefaultLoc, | calculateNumIters(Sema &SemaRef, Scope *S, SourceLocation DefaultLoc, | ||||
Expr *Lower, Expr *Upper, Expr *Step, QualType LCTy, | Expr *Lower, Expr *Upper, Expr *Step, QualType LCTy, | ||||
bool TestIsStrictOp, bool RoundToStep, | bool TestIsStrictOp, bool RoundToStep, | ||||
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { | llvm::MapVector<const Expr *, DeclRefExpr *> &Captures, | ||||
ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures); | bool Capturing) { | ||||
ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures, Capturing); | |||||
if (!NewStep.isUsable()) | if (!NewStep.isUsable()) | ||||
return nullptr; | return nullptr; | ||||
llvm::APSInt LRes, URes, SRes; | llvm::APSInt LRes, URes, SRes; | ||||
bool IsLowerConst = Lower->isIntegerConstantExpr(LRes, SemaRef.Context); | bool IsLowerConst = Lower->isIntegerConstantExpr(LRes, SemaRef.Context); | ||||
bool IsStepConst = Step->isIntegerConstantExpr(SRes, SemaRef.Context); | bool IsStepConst = Step->isIntegerConstantExpr(SRes, SemaRef.Context); | ||||
bool NoNeedToConvert = IsLowerConst && !RoundToStep && | bool NoNeedToConvert = IsLowerConst && !RoundToStep && | ||||
((!TestIsStrictOp && LRes.isNonNegative()) || | ((!TestIsStrictOp && LRes.isNonNegative()) || | ||||
(TestIsStrictOp && LRes.isStrictlyPositive())); | (TestIsStrictOp && LRes.isStrictlyPositive())); | ||||
▲ Show 20 Lines • Show All 193 Lines • ▼ Show 20 Lines | LBMaxVal = | ||||
SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMaxVal.get(), LBVal); | SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMaxVal.get(), LBVal); | ||||
if (!LBMaxVal.isUsable()) | if (!LBMaxVal.isUsable()) | ||||
return nullptr; | return nullptr; | ||||
// (OuterVar = Max, LBVal) | // (OuterVar = Max, LBVal) | ||||
LBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMaxVal.get()); | LBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMaxVal.get()); | ||||
if (!LBMaxVal.isUsable()) | if (!LBMaxVal.isUsable()) | ||||
return nullptr; | return nullptr; | ||||
Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures).get(); | Expr *LBMin = | ||||
Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures).get(); | tryBuildCapture(SemaRef, LBMinVal.get(), Captures, Capturing).get(); | ||||
Expr *LBMax = | |||||
tryBuildCapture(SemaRef, LBMaxVal.get(), Captures, Capturing).get(); | |||||
if (!LBMin || !LBMax) | if (!LBMin || !LBMax) | ||||
return nullptr; | return nullptr; | ||||
// LB(MinVal) < LB(MaxVal) | // LB(MinVal) < LB(MaxVal) | ||||
ExprResult MinLessMaxRes = | ExprResult MinLessMaxRes = | ||||
SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax); | SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax); | ||||
if (!MinLessMaxRes.isUsable()) | if (!MinLessMaxRes.isUsable()) | ||||
return nullptr; | return nullptr; | ||||
Expr *MinLessMax = | Expr *MinLessMax = | ||||
tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get(); | tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures, Capturing) | ||||
.get(); | |||||
if (!MinLessMax) | if (!MinLessMax) | ||||
return nullptr; | return nullptr; | ||||
if (TestIsLessOp.getValue()) { | if (TestIsLessOp.getValue()) { | ||||
// LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal), | // LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal), | ||||
// LB(MaxVal)) | // LB(MaxVal)) | ||||
ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc, | ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc, | ||||
MinLessMax, LBMin, LBMax); | MinLessMax, LBMin, LBMax); | ||||
if (!MinLB.isUsable()) | if (!MinLB.isUsable()) | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | UBMaxVal = | ||||
SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMaxVal.get(), UBVal); | SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMaxVal.get(), UBVal); | ||||
if (!UBMaxVal.isUsable()) | if (!UBMaxVal.isUsable()) | ||||
return nullptr; | return nullptr; | ||||
// (OuterVar = Max, UBVal) | // (OuterVar = Max, UBVal) | ||||
UBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMaxVal.get()); | UBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMaxVal.get()); | ||||
if (!UBMaxVal.isUsable()) | if (!UBMaxVal.isUsable()) | ||||
return nullptr; | return nullptr; | ||||
Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures).get(); | Expr *UBMin = | ||||
Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures).get(); | tryBuildCapture(SemaRef, UBMinVal.get(), Captures, Capturing).get(); | ||||
Expr *UBMax = | |||||
tryBuildCapture(SemaRef, UBMaxVal.get(), Captures, Capturing).get(); | |||||
if (!UBMin || !UBMax) | if (!UBMin || !UBMax) | ||||
return nullptr; | return nullptr; | ||||
// UB(MinVal) > UB(MaxVal) | // UB(MinVal) > UB(MaxVal) | ||||
ExprResult MinGreaterMaxRes = | ExprResult MinGreaterMaxRes = | ||||
SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax); | SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax); | ||||
if (!MinGreaterMaxRes.isUsable()) | if (!MinGreaterMaxRes.isUsable()) | ||||
return nullptr; | return nullptr; | ||||
Expr *MinGreaterMax = | Expr *MinGreaterMax = | ||||
tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get(); | tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures, Capturing) | ||||
.get(); | |||||
if (!MinGreaterMax) | if (!MinGreaterMax) | ||||
return nullptr; | return nullptr; | ||||
if (TestIsLessOp.getValue()) { | if (TestIsLessOp.getValue()) { | ||||
// UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal), | // UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal), | ||||
// UB(MaxVal)) | // UB(MaxVal)) | ||||
ExprResult MaxUB = SemaRef.ActOnConditionalOp( | ExprResult MaxUB = SemaRef.ActOnConditionalOp( | ||||
DefaultLoc, DefaultLoc, MinGreaterMax, UBMin, UBMax); | DefaultLoc, DefaultLoc, MinGreaterMax, UBMin, UBMax); | ||||
if (!MaxUB.isUsable()) | if (!MaxUB.isUsable()) | ||||
return nullptr; | return nullptr; | ||||
UBVal = MaxUB.get(); | UBVal = MaxUB.get(); | ||||
} else { | } else { | ||||
// UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal), | // UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal), | ||||
// UB(MaxVal)) | // UB(MaxVal)) | ||||
ExprResult MinUB = SemaRef.ActOnConditionalOp( | ExprResult MinUB = SemaRef.ActOnConditionalOp( | ||||
DefaultLoc, DefaultLoc, MinGreaterMax, UBMax, UBMin); | DefaultLoc, DefaultLoc, MinGreaterMax, UBMax, UBMin); | ||||
if (!MinUB.isUsable()) | if (!MinUB.isUsable()) | ||||
return nullptr; | return nullptr; | ||||
UBVal = MinUB.get(); | UBVal = MinUB.get(); | ||||
} | } | ||||
} | } | ||||
Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal; | Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal; | ||||
Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal; | Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal; | ||||
Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get(); | Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures, Capturing).get(); | ||||
Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get(); | Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures, Capturing).get(); | ||||
if (!Upper || !Lower) | if (!Upper || !Lower) | ||||
return nullptr; | return nullptr; | ||||
ExprResult Diff = | ExprResult Diff = calculateNumIters( | ||||
calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper, Step, VarType, | SemaRef, S, DefaultLoc, Lower, Upper, Step, VarType, TestIsStrictOp, | ||||
TestIsStrictOp, /*RoundToStep=*/true, Captures); | /*RoundToStep=*/true, Captures, Capturing); | ||||
if (!Diff.isUsable()) | if (!Diff.isUsable()) | ||||
return nullptr; | return nullptr; | ||||
// OpenMP runtime requires 32-bit or 64-bit loop variables. | // OpenMP runtime requires 32-bit or 64-bit loop variables. | ||||
QualType Type = Diff.get()->getType(); | QualType Type = Diff.get()->getType(); | ||||
ASTContext &C = SemaRef.Context; | ASTContext &C = SemaRef.Context; | ||||
bool UseVarType = VarType->hasIntegerRepresentation() && | bool UseVarType = VarType->hasIntegerRepresentation() && | ||||
C.getTypeSize(Type) > C.getTypeSize(VarType); | C.getTypeSize(Type) > C.getTypeSize(VarType); | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues( | ||||
Expr *MaxExpr = nullptr; | Expr *MaxExpr = nullptr; | ||||
Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB; | Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB; | ||||
Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB; | Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB; | ||||
bool LBNonRect = TestIsLessOp.getValue() ? InitDependOnLC.hasValue() | bool LBNonRect = TestIsLessOp.getValue() ? InitDependOnLC.hasValue() | ||||
: CondDependOnLC.hasValue(); | : CondDependOnLC.hasValue(); | ||||
bool UBNonRect = TestIsLessOp.getValue() ? CondDependOnLC.hasValue() | bool UBNonRect = TestIsLessOp.getValue() ? CondDependOnLC.hasValue() | ||||
: InitDependOnLC.hasValue(); | : InitDependOnLC.hasValue(); | ||||
Expr *Lower = | Expr *Lower = | ||||
LBNonRect ? LBExpr : tryBuildCapture(SemaRef, LBExpr, Captures).get(); | LBNonRect ? LBExpr | ||||
: tryBuildCapture(SemaRef, LBExpr, Captures, Capturing).get(); | |||||
Expr *Upper = | Expr *Upper = | ||||
UBNonRect ? UBExpr : tryBuildCapture(SemaRef, UBExpr, Captures).get(); | UBNonRect ? UBExpr | ||||
: tryBuildCapture(SemaRef, UBExpr, Captures, Capturing).get(); | |||||
if (!Upper || !Lower) | if (!Upper || !Lower) | ||||
return std::make_pair(nullptr, nullptr); | return std::make_pair(nullptr, nullptr); | ||||
if (TestIsLessOp.getValue()) | if (TestIsLessOp.getValue()) | ||||
MinExpr = Lower; | MinExpr = Lower; | ||||
else | else | ||||
MaxExpr = Upper; | MaxExpr = Upper; | ||||
// Build minimum/maximum value based on number of iterations. | // Build minimum/maximum value based on number of iterations. | ||||
QualType VarType = LCDecl->getType().getNonReferenceType(); | QualType VarType = LCDecl->getType().getNonReferenceType(); | ||||
ExprResult Diff = | ExprResult Diff = calculateNumIters( | ||||
calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper, Step, VarType, | SemaRef, S, DefaultLoc, Lower, Upper, Step, VarType, TestIsStrictOp, | ||||
TestIsStrictOp, /*RoundToStep=*/false, Captures); | /*RoundToStep=*/false, Captures, Capturing); | ||||
if (!Diff.isUsable()) | if (!Diff.isUsable()) | ||||
return std::make_pair(nullptr, nullptr); | return std::make_pair(nullptr, nullptr); | ||||
// ((Upper - Lower [- 1]) / Step) * Step | // ((Upper - Lower [- 1]) / Step) * Step | ||||
// Parentheses (for dumping/debugging purposes only). | // Parentheses (for dumping/debugging purposes only). | ||||
Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); | Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); | ||||
if (!Diff.isUsable()) | if (!Diff.isUsable()) | ||||
return std::make_pair(nullptr, nullptr); | return std::make_pair(nullptr, nullptr); | ||||
ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures); | ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures, Capturing); | ||||
if (!NewStep.isUsable()) | if (!NewStep.isUsable()) | ||||
return std::make_pair(nullptr, nullptr); | return std::make_pair(nullptr, nullptr); | ||||
Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get()); | Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get()); | ||||
if (!Diff.isUsable()) | if (!Diff.isUsable()) | ||||
return std::make_pair(nullptr, nullptr); | return std::make_pair(nullptr, nullptr); | ||||
// Parentheses (for dumping/debugging purposes only). | // Parentheses (for dumping/debugging purposes only). | ||||
Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); | Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | if (CondDependOnLC || InitDependOnLC) | ||||
return SemaRef.PerformImplicitConversion( | return SemaRef.PerformImplicitConversion( | ||||
SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get(), | SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get(), | ||||
SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting, | SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting, | ||||
/*AllowExplicit=*/true).get(); | /*AllowExplicit=*/true).get(); | ||||
// Try to build LB <op> UB, where <op> is <, >, <=, or >=. | // Try to build LB <op> UB, where <op> is <, >, <=, or >=. | ||||
Sema::TentativeAnalysisScope Trap(SemaRef); | Sema::TentativeAnalysisScope Trap(SemaRef); | ||||
ExprResult NewLB = tryBuildCapture(SemaRef, LB, Captures); | ExprResult NewLB = tryBuildCapture(SemaRef, LB, Captures, Capturing); | ||||
ExprResult NewUB = tryBuildCapture(SemaRef, UB, Captures); | ExprResult NewUB = tryBuildCapture(SemaRef, UB, Captures, Capturing); | ||||
if (!NewLB.isUsable() || !NewUB.isUsable()) | if (!NewLB.isUsable() || !NewUB.isUsable()) | ||||
return nullptr; | return nullptr; | ||||
ExprResult CondExpr = | ExprResult CondExpr = | ||||
SemaRef.BuildBinOp(S, DefaultLoc, | SemaRef.BuildBinOp(S, DefaultLoc, | ||||
TestIsLessOp.getValue() ? | TestIsLessOp.getValue() ? | ||||
(TestIsStrictOp ? BO_LT : BO_LE) : | (TestIsStrictOp ? BO_LT : BO_LE) : | ||||
(TestIsStrictOp ? BO_GT : BO_GE), | (TestIsStrictOp ? BO_GT : BO_GE), | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData( | ||||
} | } | ||||
QualType VarType = LCDecl->getType().getNonReferenceType(); | QualType VarType = LCDecl->getType().getNonReferenceType(); | ||||
if (!VarType->isIntegerType() && !VarType->isPointerType() && | if (!VarType->isIntegerType() && !VarType->isPointerType() && | ||||
!SemaRef.getLangOpts().CPlusPlus) | !SemaRef.getLangOpts().CPlusPlus) | ||||
return nullptr; | return nullptr; | ||||
// Upper - Lower | // Upper - Lower | ||||
Expr *Upper = TestIsLessOp.getValue() | Expr *Upper = TestIsLessOp.getValue() | ||||
? Cnt | ? Cnt | ||||
: tryBuildCapture(SemaRef, LB, Captures).get(); | : tryBuildCapture(SemaRef, LB, Captures, Capturing).get(); | ||||
Expr *Lower = TestIsLessOp.getValue() | Expr *Lower = TestIsLessOp.getValue() | ||||
? tryBuildCapture(SemaRef, LB, Captures).get() | ? tryBuildCapture(SemaRef, LB, Captures, Capturing).get() | ||||
: Cnt; | : Cnt; | ||||
if (!Upper || !Lower) | if (!Upper || !Lower) | ||||
return nullptr; | return nullptr; | ||||
ExprResult Diff = calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper, | ExprResult Diff = | ||||
Step, VarType, /*TestIsStrictOp=*/false, | calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper, Step, VarType, | ||||
/*RoundToStep=*/false, Captures); | /*TestIsStrictOp=*/false, | ||||
/*RoundToStep=*/false, Captures, Capturing); | |||||
if (!Diff.isUsable()) | if (!Diff.isUsable()) | ||||
return nullptr; | return nullptr; | ||||
return Diff.get(); | return Diff.get(); | ||||
} | } | ||||
} // namespace | } // namespace | ||||
void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { | void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { | ||||
assert(getLangOpts().OpenMP && "OpenMP is not active."); | assert(getLangOpts().OpenMP && "OpenMP is not active."); | ||||
assert(Init && "Expected loop in canonical form."); | assert(Init && "Expected loop in canonical form."); | ||||
unsigned AssociatedLoops = DSAStack->getAssociatedLoops(); | unsigned AssociatedLoops = DSAStack->getAssociatedLoops(); | ||||
if (AssociatedLoops > 0 && | if (AssociatedLoops > 0 && | ||||
isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { | isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { | ||||
DSAStack->loopStart(); | DSAStack->loopStart(); | ||||
OpenMPIterationSpaceChecker ISC(*this, *DSAStack, ForLoc); | OpenMPIterationSpaceChecker ISC(*this, true, true, *DSAStack, ForLoc); | ||||
if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) { | if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) { | ||||
if (ValueDecl *D = ISC.getLoopDecl()) { | if (ValueDecl *D = ISC.getLoopDecl()) { | ||||
auto *VD = dyn_cast<VarDecl>(D); | auto *VD = dyn_cast<VarDecl>(D); | ||||
DeclRefExpr *PrivateRef = nullptr; | DeclRefExpr *PrivateRef = nullptr; | ||||
if (!VD) { | if (!VD) { | ||||
if (VarDecl *Private = isOpenMPCapturedDecl(D)) { | if (VarDecl *Private = isOpenMPCapturedDecl(D)) { | ||||
VD = Private; | VD = Private; | ||||
} else { | } else { | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | |||||
/// for further processing (such as collapsing). | /// for further processing (such as collapsing). | ||||
static bool checkOpenMPIterationSpace( | static bool checkOpenMPIterationSpace( | ||||
OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA, | OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA, | ||||
unsigned CurrentNestedLoopCount, unsigned NestedLoopCount, | unsigned CurrentNestedLoopCount, unsigned NestedLoopCount, | ||||
unsigned TotalNestedLoopCount, Expr *CollapseLoopCountExpr, | unsigned TotalNestedLoopCount, Expr *CollapseLoopCountExpr, | ||||
Expr *OrderedLoopCountExpr, | Expr *OrderedLoopCountExpr, | ||||
Sema::VarsWithInheritedDSAType &VarsWithImplicitDSA, | Sema::VarsWithInheritedDSAType &VarsWithImplicitDSA, | ||||
llvm::MutableArrayRef<LoopIterationSpace> ResultIterSpaces, | llvm::MutableArrayRef<LoopIterationSpace> ResultIterSpaces, | ||||
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { | llvm::MapVector<const Expr *, DeclRefExpr *> &Captures, bool Capturing, | ||||
bool SupportsNonRectangular, bool EmitDiags) { | |||||
// OpenMP [2.9.1, Canonical Loop Form] | // OpenMP [2.9.1, Canonical Loop Form] | ||||
// for (init-expr; test-expr; incr-expr) structured-block | // for (init-expr; test-expr; incr-expr) structured-block | ||||
// for (range-decl: range-expr) structured-block | // for (range-decl: range-expr) structured-block | ||||
auto *For = dyn_cast_or_null<ForStmt>(S); | auto *For = dyn_cast_or_null<ForStmt>(S); | ||||
auto *CXXFor = dyn_cast_or_null<CXXForRangeStmt>(S); | auto *CXXFor = dyn_cast_or_null<CXXForRangeStmt>(S); | ||||
// Ranged for is supported only in OpenMP 5.0. | // Ranged for is supported only in OpenMP 5.0. | ||||
if (!For && (SemaRef.LangOpts.OpenMP <= 45 || !CXXFor)) { | if (!For && (SemaRef.LangOpts.OpenMP <= 45 || !CXXFor)) { | ||||
SemaRef.Diag(S->getBeginLoc(), diag::err_omp_not_for) | SemaRef.Diag(S->getBeginLoc(), diag::err_omp_not_for) | ||||
<< (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr) | << (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr) | ||||
<< getOpenMPDirectiveName(DKind) << TotalNestedLoopCount | << getOpenMPDirectiveName(DKind) << TotalNestedLoopCount | ||||
<< (CurrentNestedLoopCount > 0) << CurrentNestedLoopCount; | << (CurrentNestedLoopCount > 0) << CurrentNestedLoopCount; | ||||
if (TotalNestedLoopCount > 1) { | if (TotalNestedLoopCount > 1 && | ||||
(CollapseLoopCountExpr || OrderedLoopCountExpr)) { | |||||
if (CollapseLoopCountExpr && OrderedLoopCountExpr) | if (CollapseLoopCountExpr && OrderedLoopCountExpr) | ||||
SemaRef.Diag(DSA.getConstructLoc(), | SemaRef.Diag(DSA.getConstructLoc(), | ||||
diag::note_omp_collapse_ordered_expr) | diag::note_omp_collapse_ordered_expr) | ||||
<< 2 << CollapseLoopCountExpr->getSourceRange() | << 2 << CollapseLoopCountExpr->getSourceRange() | ||||
<< OrderedLoopCountExpr->getSourceRange(); | << OrderedLoopCountExpr->getSourceRange(); | ||||
else if (CollapseLoopCountExpr) | else if (CollapseLoopCountExpr) | ||||
SemaRef.Diag(CollapseLoopCountExpr->getExprLoc(), | SemaRef.Diag(CollapseLoopCountExpr->getExprLoc(), | ||||
diag::note_omp_collapse_ordered_expr) | diag::note_omp_collapse_ordered_expr) | ||||
<< 0 << CollapseLoopCountExpr->getSourceRange(); | << 0 << CollapseLoopCountExpr->getSourceRange(); | ||||
else | else | ||||
SemaRef.Diag(OrderedLoopCountExpr->getExprLoc(), | SemaRef.Diag(OrderedLoopCountExpr->getExprLoc(), | ||||
diag::note_omp_collapse_ordered_expr) | diag::note_omp_collapse_ordered_expr) | ||||
<< 1 << OrderedLoopCountExpr->getSourceRange(); | << 1 << OrderedLoopCountExpr->getSourceRange(); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
assert(((For && For->getBody()) || (CXXFor && CXXFor->getBody())) && | ResultIterSpaces[CurrentNestedLoopCount].Loop = S; | ||||
"No loop body."); | Stmt *&Body = ResultIterSpaces[CurrentNestedLoopCount].Body; | ||||
Body = For ? For->getBody() : CXXFor->getBody(); | |||||
assert(Body && "No loop body."); | |||||
OpenMPIterationSpaceChecker ISC(SemaRef, DSA, | OpenMPIterationSpaceChecker ISC(SemaRef, Capturing, SupportsNonRectangular, | ||||
DSA, | |||||
For ? For->getForLoc() : CXXFor->getForLoc()); | For ? For->getForLoc() : CXXFor->getForLoc()); | ||||
// Check init. | // Check init. | ||||
Stmt *Init = For ? For->getInit() : CXXFor->getBeginStmt(); | Stmt *Init = For ? For->getInit() : CXXFor->getBeginStmt(); | ||||
if (ISC.checkAndSetInit(Init)) | if (ISC.checkAndSetInit(Init, EmitDiags)) | ||||
return true; | return true; | ||||
bool HasErrors = false; | bool HasErrors = false; | ||||
// Check loop variable's type. | // Check loop variable's type. | ||||
if (ValueDecl *LCDecl = ISC.getLoopDecl()) { | if (ValueDecl *LCDecl = ISC.getLoopDecl()) { | ||||
// OpenMP [2.6, Canonical Loop Form] | // OpenMP [2.6, Canonical Loop Form] | ||||
// Var is one of the following: | // Var is one of the following: | ||||
Show All 18 Lines | if (ValueDecl *LCDecl = ISC.getLoopDecl()) { | ||||
// constant-linear-step that is the increment of the associated for-loop. | // constant-linear-step that is the increment of the associated for-loop. | ||||
// Exclude loop var from the list of variables with implicitly defined data | // Exclude loop var from the list of variables with implicitly defined data | ||||
// sharing attributes. | // sharing attributes. | ||||
VarsWithImplicitDSA.erase(LCDecl); | VarsWithImplicitDSA.erase(LCDecl); | ||||
assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); | assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); | ||||
// Check test-expr. | // Check test-expr. | ||||
HasErrors |= ISC.checkAndSetCond(For ? For->getCond() : CXXFor->getCond()); | HasErrors |= ISC.checkAndSetCond(For ? For->getCond() : CXXFor->getCond(), | ||||
EmitDiags); | |||||
// Check incr-expr. | // Check incr-expr. | ||||
HasErrors |= ISC.checkAndSetInc(For ? For->getInc() : CXXFor->getInc()); | HasErrors |= ISC.checkAndSetInc(For ? For->getInc() : CXXFor->getInc()); | ||||
} | } | ||||
if (ISC.dependent() || SemaRef.CurContext->isDependentContext() || HasErrors) | if (ISC.dependent() || SemaRef.CurContext->isDependentContext() || HasErrors) | ||||
return HasErrors; | return HasErrors; | ||||
// Build the loop's iteration space representation. | // Build the loop's iteration space representation. | ||||
ResultIterSpaces[CurrentNestedLoopCount].PreCond = ISC.buildPreCond( | ResultIterSpaces[CurrentNestedLoopCount].PreCond = ISC.buildPreCond( | ||||
DSA.getCurScope(), For ? For->getCond() : CXXFor->getCond(), Captures); | DSA.getCurScope(), For ? For->getCond() : CXXFor->getCond(), Captures); | ||||
ResultIterSpaces[CurrentNestedLoopCount].NumIterations = | ResultIterSpaces[CurrentNestedLoopCount].NumIterations = | ||||
ISC.buildNumIterations(DSA.getCurScope(), ResultIterSpaces, | ISC.buildNumIterations(DSA.getCurScope(), ResultIterSpaces, | ||||
(isOpenMPWorksharingDirective(DKind) || | (isOpenMPWorksharingDirective(DKind) || | ||||
isOpenMPTaskLoopDirective(DKind) || | isOpenMPTaskLoopDirective(DKind) || | ||||
isOpenMPDistributeDirective(DKind)), | isOpenMPDistributeDirective(DKind) || | ||||
isOpenMPLoopTransformationDirective(DKind)), | |||||
Captures); | Captures); | ||||
ResultIterSpaces[CurrentNestedLoopCount].CounterVar = | ResultIterSpaces[CurrentNestedLoopCount].CounterVar = | ||||
ISC.buildCounterVar(Captures, DSA); | ISC.buildCounterVar(Captures, DSA); | ||||
ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar = | ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar = | ||||
ISC.buildPrivateCounterVar(); | ISC.buildPrivateCounterVar(); | ||||
ResultIterSpaces[CurrentNestedLoopCount].CounterInit = ISC.buildCounterInit(); | ResultIterSpaces[CurrentNestedLoopCount].CounterInit = ISC.buildCounterInit(); | ||||
ResultIterSpaces[CurrentNestedLoopCount].CounterStep = ISC.buildCounterStep(); | ResultIterSpaces[CurrentNestedLoopCount].CounterStep = ISC.buildCounterStep(); | ||||
ResultIterSpaces[CurrentNestedLoopCount].InitSrcRange = ISC.getInitSrcRange(); | ResultIterSpaces[CurrentNestedLoopCount].InitSrcRange = ISC.getInitSrcRange(); | ||||
Show All 12 Lines | static bool checkOpenMPIterationSpace( | ||||
ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularLB = | ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularLB = | ||||
ISC.doesInitDependOnLC(); | ISC.doesInitDependOnLC(); | ||||
ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularUB = | ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularUB = | ||||
ISC.doesCondDependOnLC(); | ISC.doesCondDependOnLC(); | ||||
ResultIterSpaces[CurrentNestedLoopCount].LoopDependentIdx = | ResultIterSpaces[CurrentNestedLoopCount].LoopDependentIdx = | ||||
ISC.getLoopDependentIdx(); | ISC.getLoopDependentIdx(); | ||||
HasErrors |= | HasErrors |= | ||||
(ResultIterSpaces[CurrentNestedLoopCount].PreCond == nullptr || | (ResultIterSpaces[CurrentNestedLoopCount].Loop == nullptr || | ||||
ResultIterSpaces[CurrentNestedLoopCount].Body == nullptr || | |||||
ResultIterSpaces[CurrentNestedLoopCount].PreCond == nullptr || | |||||
ResultIterSpaces[CurrentNestedLoopCount].NumIterations == nullptr || | ResultIterSpaces[CurrentNestedLoopCount].NumIterations == nullptr || | ||||
ResultIterSpaces[CurrentNestedLoopCount].CounterVar == nullptr || | ResultIterSpaces[CurrentNestedLoopCount].CounterVar == nullptr || | ||||
ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar == nullptr || | ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar == nullptr || | ||||
ResultIterSpaces[CurrentNestedLoopCount].CounterInit == nullptr || | ResultIterSpaces[CurrentNestedLoopCount].CounterInit == nullptr || | ||||
ResultIterSpaces[CurrentNestedLoopCount].CounterStep == nullptr); | ResultIterSpaces[CurrentNestedLoopCount].CounterStep == nullptr); | ||||
if (!HasErrors && DSA.isOrderedRegion()) { | if (!HasErrors && DSA.isOrderedRegion()) { | ||||
if (DSA.getOrderedRegionParam().second->getNumForLoops()) { | if (DSA.getOrderedRegionParam().second->getNumForLoops()) { | ||||
if (CurrentNestedLoopCount < | if (CurrentNestedLoopCount < | ||||
Show All 36 Lines | static bool checkOpenMPIterationSpace( | ||||
return HasErrors; | return HasErrors; | ||||
} | } | ||||
/// Build 'VarRef = Start. | /// Build 'VarRef = Start. | ||||
static ExprResult | static ExprResult | ||||
buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, | buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, | ||||
ExprResult Start, bool IsNonRectangularLB, | ExprResult Start, bool IsNonRectangularLB, | ||||
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { | llvm::MapVector<const Expr *, DeclRefExpr *> &Captures, | ||||
bool Capturing) { | |||||
// Build 'VarRef = Start. | // Build 'VarRef = Start. | ||||
ExprResult NewStart = IsNonRectangularLB | ExprResult NewStart = | ||||
IsNonRectangularLB | |||||
? Start.get() | ? Start.get() | ||||
: tryBuildCapture(SemaRef, Start.get(), Captures); | : tryBuildCapture(SemaRef, Start.get(), Captures, Capturing); | ||||
if (!NewStart.isUsable()) | if (!NewStart.isUsable()) | ||||
return ExprError(); | return ExprError(); | ||||
if (!SemaRef.Context.hasSameType(NewStart.get()->getType(), | if (!SemaRef.Context.hasSameType(NewStart.get()->getType(), | ||||
VarRef.get()->getType())) { | VarRef.get()->getType())) { | ||||
NewStart = SemaRef.PerformImplicitConversion( | NewStart = SemaRef.PerformImplicitConversion( | ||||
NewStart.get(), VarRef.get()->getType(), Sema::AA_Converting, | NewStart.get(), VarRef.get()->getType(), Sema::AA_Converting, | ||||
/*AllowExplicit=*/true); | /*AllowExplicit=*/true); | ||||
if (!NewStart.isUsable()) | if (!NewStart.isUsable()) | ||||
▲ Show 20 Lines • Show All 154 Lines • ▼ Show 20 Lines | |||||
/// Called on a for stmt to check itself and nested loops (if any). | /// Called on a for stmt to check itself and nested loops (if any). | ||||
/// \return Returns 0 if one of the collapsed stmts is not canonical for loop, | /// \return Returns 0 if one of the collapsed stmts is not canonical for loop, | ||||
/// number of collapsed loops otherwise. | /// number of collapsed loops otherwise. | ||||
static unsigned | static unsigned | ||||
checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, | checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, | ||||
Expr *OrderedLoopCountExpr, Stmt *AStmt, Sema &SemaRef, | Expr *OrderedLoopCountExpr, Stmt *AStmt, Sema &SemaRef, | ||||
DSAStackTy &DSA, | DSAStackTy &DSA, | ||||
Sema::VarsWithInheritedDSAType &VarsWithImplicitDSA, | Sema::VarsWithInheritedDSAType &VarsWithImplicitDSA, | ||||
OMPLoopDirective::HelperExprs &Built) { | OMPLoopDirective::HelperExprs &Built, unsigned MinLoopCount = 1, | ||||
unsigned NestedLoopCount = 1; | bool EmitDiags = true) { | ||||
assert(MinLoopCount == 1 || | |||||
(!CollapseLoopCountExpr && !OrderedLoopCountExpr)); | |||||
unsigned NestedLoopCount = MinLoopCount; | |||||
bool Capturing = !isOpenMPLoopTransformationDirective(DKind); | |||||
bool SupportsNonPerfectlyNested = (SemaRef.LangOpts.OpenMP >= 50) && | |||||
!isOpenMPLoopTransformationDirective(DKind); | |||||
bool SupportsNonRectangular = !isOpenMPLoopTransformationDirective(DKind); | |||||
if (CollapseLoopCountExpr) { | if (CollapseLoopCountExpr) { | ||||
// Found 'collapse' clause - calculate collapse number. | // Found 'collapse' clause - calculate collapse number. | ||||
Expr::EvalResult Result; | Expr::EvalResult Result; | ||||
if (!CollapseLoopCountExpr->isValueDependent() && | if (!CollapseLoopCountExpr->isValueDependent() && | ||||
CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext())) { | CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext())) { | ||||
NestedLoopCount = Result.Val.getInt().getLimitedValue(); | NestedLoopCount = Result.Val.getInt().getLimitedValue(); | ||||
} else { | } else { | ||||
Built.clear(/*Size=*/1); | Built.clear(/*Size=*/1); | ||||
Show All 17 Lines | if (!OrderedLoopCountExpr->isValueDependent() && | ||||
<< CollapseLoopCountExpr->getSourceRange(); | << CollapseLoopCountExpr->getSourceRange(); | ||||
} | } | ||||
OrderedLoopCount = Result.getLimitedValue(); | OrderedLoopCount = Result.getLimitedValue(); | ||||
} else { | } else { | ||||
Built.clear(/*Size=*/1); | Built.clear(/*Size=*/1); | ||||
return 1; | return 1; | ||||
} | } | ||||
} | } | ||||
unsigned NumAssocociatedLoops = std::max(OrderedLoopCount, NestedLoopCount); | |||||
// This is helper routine for loop directives (e.g., 'for', 'simd', | // This is helper routine for loop directives (e.g., 'for', 'simd', | ||||
// 'for simd', etc.). | // 'for simd', etc.). | ||||
llvm::MapVector<const Expr *, DeclRefExpr *> Captures; | llvm::MapVector<const Expr *, DeclRefExpr *> Captures; | ||||
SmallVector<LoopIterationSpace, 4> IterSpaces( | SmallVector<LoopIterationSpace, 4> IterSpaces(NumAssocociatedLoops); | ||||
std::max(OrderedLoopCount, NestedLoopCount)); | Stmt *CurStmt = AStmt; | ||||
Stmt *CurStmt = AStmt->IgnoreContainers(/* IgnoreCaptured */ true); | |||||
for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) { | for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) { | ||||
if (checkOpenMPIterationSpace( | CurStmt = OMPLoopDirective::tryToFindNextInnerLoop( | ||||
DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount, | CurStmt, CurStmt > 0 && SupportsNonPerfectlyNested); | ||||
std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr, | |||||
OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces, Captures)) | if (checkOpenMPIterationSpace(DKind, CurStmt, SemaRef, DSA, Cnt, | ||||
NestedLoopCount, NumAssocociatedLoops, | |||||
CollapseLoopCountExpr, OrderedLoopCountExpr, | |||||
VarsWithImplicitDSA, IterSpaces, Captures, | |||||
Capturing, SupportsNonRectangular, EmitDiags)) | |||||
return 0; | return 0; | ||||
// Move on to the next nested for loop, or to the loop body. | // Move on to the next nested for loop, or to the loop body. | ||||
// OpenMP [2.8.1, simd construct, Restrictions] | // OpenMP [2.8.1, simd construct, Restrictions] | ||||
// All loops associated with the construct must be perfectly nested; that | // All loops associated with the construct must be perfectly nested; that | ||||
// is, there must be no intervening code nor any OpenMP directive between | // is, there must be no intervening code nor any OpenMP directive between | ||||
// any two loops. | // any two loops. | ||||
if (auto *For = dyn_cast<ForStmt>(CurStmt)) { | if (auto *For = dyn_cast<ForStmt>(CurStmt)) { | ||||
CurStmt = For->getBody(); | CurStmt = For->getBody(); | ||||
} else { | } else { | ||||
assert(isa<CXXForRangeStmt>(CurStmt) && | assert(isa<CXXForRangeStmt>(CurStmt) && | ||||
"Expected canonical for or range-based for loops."); | "Expected canonical for or range-based for loops."); | ||||
CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody(); | CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody(); | ||||
} | } | ||||
CurStmt = OMPLoopDirective::tryToFindNextInnerLoop( | |||||
CurStmt, SemaRef.LangOpts.OpenMP >= 50); | |||||
} | } | ||||
for (unsigned Cnt = NestedLoopCount; Cnt < OrderedLoopCount; ++Cnt) { | for (unsigned Cnt = NestedLoopCount; Cnt < OrderedLoopCount; ++Cnt) { | ||||
CurStmt = OMPLoopDirective::tryToFindNextInnerLoop( | |||||
CurStmt, SupportsNonPerfectlyNested); | |||||
if (checkOpenMPIterationSpace( | if (checkOpenMPIterationSpace( | ||||
DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount, | DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount, | ||||
std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr, | std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr, | ||||
OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces, Captures)) | OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces, Captures, | ||||
Capturing, SupportsNonRectangular, EmitDiags)) | |||||
return 0; | return 0; | ||||
if (Cnt > 0 && IterSpaces[Cnt].CounterVar) { | if (Cnt > 0 && IterSpaces[Cnt].CounterVar) { | ||||
// Handle initialization of captured loop iterator variables. | // Handle initialization of captured loop iterator variables. | ||||
auto *DRE = cast<DeclRefExpr>(IterSpaces[Cnt].CounterVar); | auto *DRE = cast<DeclRefExpr>(IterSpaces[Cnt].CounterVar); | ||||
if (isa<OMPCapturedExprDecl>(DRE->getDecl())) { | if (isa<OMPCapturedExprDecl>(DRE->getDecl())) { | ||||
Captures[DRE] = DRE; | Captures[DRE] = DRE; | ||||
} | } | ||||
} | } | ||||
// Move on to the next nested for loop, or to the loop body. | // Move on to the next nested for loop, or to the loop body. | ||||
// OpenMP [2.8.1, simd construct, Restrictions] | // OpenMP [2.8.1, simd construct, Restrictions] | ||||
// All loops associated with the construct must be perfectly nested; that | // All loops associated with the construct must be perfectly nested; that | ||||
// is, there must be no intervening code nor any OpenMP directive between | // is, there must be no intervening code nor any OpenMP directive between | ||||
// any two loops. | // any two loops. | ||||
if (auto *For = dyn_cast<ForStmt>(CurStmt)) { | if (auto *For = dyn_cast<ForStmt>(CurStmt)) { | ||||
CurStmt = For->getBody(); | CurStmt = For->getBody(); | ||||
} else { | } else { | ||||
assert(isa<CXXForRangeStmt>(CurStmt) && | assert(isa<CXXForRangeStmt>(CurStmt) && | ||||
"Expected canonical for or range-based for loops."); | "Expected canonical for or range-based for loops."); | ||||
CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody(); | CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody(); | ||||
} | } | ||||
CurStmt = OMPLoopDirective::tryToFindNextInnerLoop( | |||||
CurStmt, SemaRef.LangOpts.OpenMP >= 50); | |||||
} | } | ||||
Built.clear(/* size */ NestedLoopCount); | Built.clear(/* size */ NestedLoopCount); | ||||
if (SemaRef.CurContext->isDependentContext()) | if (SemaRef.CurContext->isDependentContext()) | ||||
return NestedLoopCount; | return NestedLoopCount; | ||||
// An example of what is generated for the following code: | // An example of what is generated for the following code: | ||||
▲ Show 20 Lines • Show All 118 Lines • ▼ Show 20 Lines | checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, | ||||
// Calculate the last iteration number beforehand instead of doing this on | // Calculate the last iteration number beforehand instead of doing this on | ||||
// each iteration. Do not do this if the number of iterations may be kfold-ed. | // each iteration. Do not do this if the number of iterations may be kfold-ed. | ||||
llvm::APSInt Result; | llvm::APSInt Result; | ||||
bool IsConstant = | bool IsConstant = | ||||
LastIteration.get()->isIntegerConstantExpr(Result, SemaRef.Context); | LastIteration.get()->isIntegerConstantExpr(Result, SemaRef.Context); | ||||
ExprResult CalcLastIteration; | ExprResult CalcLastIteration; | ||||
if (!IsConstant) { | if (!IsConstant) { | ||||
ExprResult SaveRef = | ExprResult SaveRef = | ||||
tryBuildCapture(SemaRef, LastIteration.get(), Captures); | tryBuildCapture(SemaRef, LastIteration.get(), Captures, Capturing); | ||||
LastIteration = SaveRef; | LastIteration = SaveRef; | ||||
// Prepare SaveRef + 1. | // Prepare SaveRef + 1. | ||||
NumIterations = SemaRef.BuildBinOp( | NumIterations = SemaRef.BuildBinOp( | ||||
CurScope, SaveRef.get()->getExprLoc(), BO_Add, SaveRef.get(), | CurScope, SaveRef.get()->getExprLoc(), BO_Add, SaveRef.get(), | ||||
SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); | SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); | ||||
if (!NumIterations.isUsable()) | if (!NumIterations.isUsable()) | ||||
return 0; | return 0; | ||||
} | } | ||||
SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin(); | SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin(); | ||||
// Build variables passed into runtime, necessary for worksharing directives. | // Build variables passed into runtime, necessary for worksharing directives. | ||||
ExprResult LB, UB, IL, ST, EUB, CombLB, CombUB, PrevLB, PrevUB, CombEUB; | ExprResult LB, UB, IL, ST, EUB, CombLB, CombUB, PrevLB, PrevUB, CombEUB; | ||||
if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || | if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || | ||||
isOpenMPDistributeDirective(DKind)) { | isOpenMPDistributeDirective(DKind) || | ||||
isOpenMPLoopTransformationDirective(DKind)) { | |||||
// Lower bound variable, initialized with zero. | // Lower bound variable, initialized with zero. | ||||
VarDecl *LBDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.lb"); | VarDecl *LBDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.lb"); | ||||
LB = buildDeclRefExpr(SemaRef, LBDecl, VType, InitLoc); | LB = buildDeclRefExpr(SemaRef, LBDecl, VType, InitLoc); | ||||
SemaRef.AddInitializerToDecl(LBDecl, | SemaRef.AddInitializerToDecl(LBDecl, | ||||
SemaRef.ActOnIntegerConstant(InitLoc, 0).get(), | SemaRef.ActOnIntegerConstant(InitLoc, 0).get(), | ||||
/*DirectInit*/ false); | /*DirectInit*/ false); | ||||
// Upper bound variable, initialized with last iteration number. | // Upper bound variable, initialized with last iteration number. | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, | ||||
} | } | ||||
// Build the iteration variable and its initialization before loop. | // Build the iteration variable and its initialization before loop. | ||||
ExprResult IV; | ExprResult IV; | ||||
ExprResult Init, CombInit; | ExprResult Init, CombInit; | ||||
{ | { | ||||
VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, RealVType, ".omp.iv"); | VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, RealVType, ".omp.iv"); | ||||
IV = buildDeclRefExpr(SemaRef, IVDecl, RealVType, InitLoc); | IV = buildDeclRefExpr(SemaRef, IVDecl, RealVType, InitLoc); | ||||
Expr *RHS = | Expr *RHS = (isOpenMPWorksharingDirective(DKind) || | ||||
(isOpenMPWorksharingDirective(DKind) || | isOpenMPTaskLoopDirective(DKind) || | ||||
isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) | isOpenMPDistributeDirective(DKind) || | ||||
isOpenMPLoopTransformationDirective(DKind)) | |||||
? LB.get() | ? LB.get() | ||||
: SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get(); | : SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get(); | ||||
Init = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), RHS); | Init = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), RHS); | ||||
Init = SemaRef.ActOnFinishFullExpr(Init.get(), /*DiscardedValue*/ false); | Init = SemaRef.ActOnFinishFullExpr(Init.get(), /*DiscardedValue*/ false); | ||||
if (isOpenMPLoopBoundSharingDirective(DKind)) { | if (isOpenMPLoopBoundSharingDirective(DKind)) { | ||||
Expr *CombRHS = | Expr *CombRHS = | ||||
(isOpenMPWorksharingDirective(DKind) || | (isOpenMPWorksharingDirective(DKind) || | ||||
isOpenMPTaskLoopDirective(DKind) || | isOpenMPTaskLoopDirective(DKind) || | ||||
isOpenMPDistributeDirective(DKind)) | isOpenMPDistributeDirective(DKind)) | ||||
Show All 21 Lines | BoundUB = | ||||
.BuildBinOp(CurScope, CondLoc, BO_Add, BoundUB, | .BuildBinOp(CurScope, CondLoc, BO_Add, BoundUB, | ||||
SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()) | SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()) | ||||
.get(); | .get(); | ||||
BoundUB = | BoundUB = | ||||
SemaRef.ActOnFinishFullExpr(BoundUB, /*DiscardedValue*/ false).get(); | SemaRef.ActOnFinishFullExpr(BoundUB, /*DiscardedValue*/ false).get(); | ||||
} | } | ||||
ExprResult Cond = | ExprResult Cond = | ||||
(isOpenMPWorksharingDirective(DKind) || | (isOpenMPWorksharingDirective(DKind) || | ||||
isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) | isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind) || | ||||
isOpenMPLoopTransformationDirective(DKind)) | |||||
? SemaRef.BuildBinOp(CurScope, CondLoc, | ? SemaRef.BuildBinOp(CurScope, CondLoc, | ||||
UseStrictCompare ? BO_LT : BO_LE, IV.get(), | UseStrictCompare ? BO_LT : BO_LE, IV.get(), | ||||
BoundUB) | BoundUB) | ||||
: SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(), | : SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(), | ||||
NumIterations.get()); | NumIterations.get()); | ||||
ExprResult CombDistCond; | ExprResult CombDistCond; | ||||
if (isOpenMPLoopBoundSharingDirective(DKind)) { | if (isOpenMPLoopBoundSharingDirective(DKind)) { | ||||
CombDistCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(), | CombDistCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(), | ||||
Show All 31 Lines | if (!Inc.isUsable()) | ||||
return 0; | return 0; | ||||
// Increments for worksharing loops (LB = LB + ST; UB = UB + ST). | // Increments for worksharing loops (LB = LB + ST; UB = UB + ST). | ||||
// Used for directives with static scheduling. | // Used for directives with static scheduling. | ||||
// In combined construct, add combined version that use CombLB and CombUB | // In combined construct, add combined version that use CombLB and CombUB | ||||
// base variables for the update | // base variables for the update | ||||
ExprResult NextLB, NextUB, CombNextLB, CombNextUB; | ExprResult NextLB, NextUB, CombNextLB, CombNextUB; | ||||
if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || | if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || | ||||
isOpenMPDistributeDirective(DKind)) { | isOpenMPDistributeDirective(DKind) || | ||||
isOpenMPLoopTransformationDirective(DKind)) { | |||||
// LB + ST | // LB + ST | ||||
NextLB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, LB.get(), ST.get()); | NextLB = SemaRef.BuildBinOp(CurScope, IncLoc, BO_Add, LB.get(), ST.get()); | ||||
if (!NextLB.isUsable()) | if (!NextLB.isUsable()) | ||||
return 0; | return 0; | ||||
// LB = LB + ST | // LB = LB + ST | ||||
NextLB = | NextLB = | ||||
SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, LB.get(), NextLB.get()); | SemaRef.BuildBinOp(CurScope, IncLoc, BO_Assign, LB.get(), NextLB.get()); | ||||
NextLB = | NextLB = | ||||
▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, | ||||
bool HasErrors = false; | bool HasErrors = false; | ||||
Built.Counters.resize(NestedLoopCount); | Built.Counters.resize(NestedLoopCount); | ||||
Built.Inits.resize(NestedLoopCount); | Built.Inits.resize(NestedLoopCount); | ||||
Built.Updates.resize(NestedLoopCount); | Built.Updates.resize(NestedLoopCount); | ||||
Built.Finals.resize(NestedLoopCount); | Built.Finals.resize(NestedLoopCount); | ||||
Built.DependentCounters.resize(NestedLoopCount); | Built.DependentCounters.resize(NestedLoopCount); | ||||
Built.DependentInits.resize(NestedLoopCount); | Built.DependentInits.resize(NestedLoopCount); | ||||
Built.FinalsConditions.resize(NestedLoopCount); | Built.FinalsConditions.resize(NestedLoopCount); | ||||
Built.Loops.resize(NestedLoopCount); | |||||
Built.Bodys.resize(NestedLoopCount); | |||||
{ | { | ||||
// We implement the following algorithm for obtaining the | // We implement the following algorithm for obtaining the | ||||
// original loop iteration variable values based on the | // original loop iteration variable values based on the | ||||
// value of the collapsed loop iteration variable IV. | // value of the collapsed loop iteration variable IV. | ||||
// | // | ||||
// Let n+1 be the number of collapsed loops in the nest. | // Let n+1 be the number of collapsed loops in the nest. | ||||
// Iteration variables (I0, I1, .... In) | // Iteration variables (I0, I1, .... In) | ||||
// Iteration counts (N0, N1, ... Nn) | // Iteration counts (N0, N1, ... Nn) | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | for (unsigned int Cnt = 0; Cnt < NestedLoopCount; ++Cnt) { | ||||
Prod = Iter; | Prod = Iter; | ||||
Acc = SemaRef.BuildBinOp(CurScope, UpdLoc, BO_Sub, | Acc = SemaRef.BuildBinOp(CurScope, UpdLoc, BO_Sub, | ||||
Acc.get(), Prod.get()); | Acc.get(), Prod.get()); | ||||
// Build update: IS.CounterVar(Private) = IS.Start + Iter * IS.Step | // Build update: IS.CounterVar(Private) = IS.Start + Iter * IS.Step | ||||
auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IS.CounterVar)->getDecl()); | auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IS.CounterVar)->getDecl()); | ||||
DeclRefExpr *CounterVar = buildDeclRefExpr( | DeclRefExpr *CounterVar = buildDeclRefExpr( | ||||
SemaRef, VD, IS.CounterVar->getType(), IS.CounterVar->getExprLoc(), | SemaRef, VD, IS.CounterVar->getType(), IS.CounterVar->getExprLoc(), | ||||
/*RefersToCapture=*/true); | /*RefersToCapture=*/Capturing); | ||||
ExprResult Init = | ExprResult Init = buildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar, | ||||
buildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar, | IS.CounterInit, IS.IsNonRectangularLB, | ||||
IS.CounterInit, IS.IsNonRectangularLB, Captures); | Captures, Capturing); | ||||
if (!Init.isUsable()) { | if (!Init.isUsable()) { | ||||
HasErrors = true; | HasErrors = true; | ||||
break; | break; | ||||
} | } | ||||
ExprResult Update = buildCounterUpdate( | ExprResult Update = buildCounterUpdate( | ||||
SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Iter, | SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Iter, | ||||
IS.CounterStep, IS.Subtract, IS.IsNonRectangularLB, &Captures); | IS.CounterStep, IS.Subtract, IS.IsNonRectangularLB, | ||||
Capturing ? &Captures : nullptr); | |||||
if (!Update.isUsable()) { | if (!Update.isUsable()) { | ||||
HasErrors = true; | HasErrors = true; | ||||
break; | break; | ||||
} | } | ||||
// Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step | // Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step | ||||
ExprResult Final = | ExprResult Final = buildCounterUpdate( | ||||
buildCounterUpdate(SemaRef, CurScope, UpdLoc, CounterVar, | SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, | ||||
IS.CounterInit, IS.NumIterations, IS.CounterStep, | IS.NumIterations, IS.CounterStep, IS.Subtract, IS.IsNonRectangularLB, | ||||
IS.Subtract, IS.IsNonRectangularLB, &Captures); | Capturing ? &Captures : nullptr); | ||||
if (!Final.isUsable()) { | if (!Final.isUsable()) { | ||||
HasErrors = true; | HasErrors = true; | ||||
break; | break; | ||||
} | } | ||||
if (!Update.isUsable() || !Final.isUsable()) { | if (!Update.isUsable() || !Final.isUsable()) { | ||||
HasErrors = true; | HasErrors = true; | ||||
break; | break; | ||||
} | } | ||||
// Save results | // Save results | ||||
Built.Loops[Cnt] = IS.Loop; | |||||
Built.Bodys[Cnt] = IS.Body; | |||||
Built.Counters[Cnt] = IS.CounterVar; | Built.Counters[Cnt] = IS.CounterVar; | ||||
Built.PrivateCounters[Cnt] = IS.PrivateCounterVar; | Built.PrivateCounters[Cnt] = IS.PrivateCounterVar; | ||||
Built.Inits[Cnt] = Init.get(); | Built.Inits[Cnt] = Init.get(); | ||||
Built.Updates[Cnt] = Update.get(); | Built.Updates[Cnt] = Update.get(); | ||||
Built.Finals[Cnt] = Final.get(); | Built.Finals[Cnt] = Final.get(); | ||||
Built.DependentCounters[Cnt] = nullptr; | Built.DependentCounters[Cnt] = nullptr; | ||||
Built.DependentInits[Cnt] = nullptr; | Built.DependentInits[Cnt] = nullptr; | ||||
Built.FinalsConditions[Cnt] = nullptr; | Built.FinalsConditions[Cnt] = nullptr; | ||||
Show All 39 Lines | checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, | ||||
Built.DistCombinedFields.EUB = CombEUB.get(); | Built.DistCombinedFields.EUB = CombEUB.get(); | ||||
Built.DistCombinedFields.Init = CombInit.get(); | Built.DistCombinedFields.Init = CombInit.get(); | ||||
Built.DistCombinedFields.Cond = CombCond.get(); | Built.DistCombinedFields.Cond = CombCond.get(); | ||||
Built.DistCombinedFields.NLB = CombNextLB.get(); | Built.DistCombinedFields.NLB = CombNextLB.get(); | ||||
Built.DistCombinedFields.NUB = CombNextUB.get(); | Built.DistCombinedFields.NUB = CombNextUB.get(); | ||||
Built.DistCombinedFields.DistCond = CombDistCond.get(); | Built.DistCombinedFields.DistCond = CombDistCond.get(); | ||||
Built.DistCombinedFields.ParForInDistCond = ParForInDistCond.get(); | Built.DistCombinedFields.ParForInDistCond = ParForInDistCond.get(); | ||||
assert(Capturing || Captures.empty()); | |||||
return NestedLoopCount; | return NestedLoopCount; | ||||
} | } | ||||
static Expr *getCollapseNumberExpr(ArrayRef<OMPClause *> Clauses) { | static Expr *getCollapseNumberExpr(ArrayRef<OMPClause *> Clauses) { | ||||
auto CollapseClauses = | auto CollapseClauses = | ||||
OMPExecutableDirective::getClausesOfKind<OMPCollapseClause>(Clauses); | OMPExecutableDirective::getClausesOfKind<OMPCollapseClause>(Clauses); | ||||
if (CollapseClauses.begin() != CollapseClauses.end()) | if (CollapseClauses.begin() != CollapseClauses.end()) | ||||
return (*CollapseClauses.begin())->getNumForLoops(); | return (*CollapseClauses.begin())->getNumForLoops(); | ||||
▲ Show 20 Lines • Show All 2,906 Lines • ▼ Show 20 Lines | StmtResult Sema::ActOnOpenMPTargetTeamsDistributeSimdDirective( | ||||
if (checkSimdlenSafelenSpecified(*this, Clauses)) | if (checkSimdlenSafelenSpecified(*this, Clauses)) | ||||
return StmtError(); | return StmtError(); | ||||
setFunctionHasBranchProtectedScope(); | setFunctionHasBranchProtectedScope(); | ||||
return OMPTargetTeamsDistributeSimdDirective::Create( | return OMPTargetTeamsDistributeSimdDirective::Create( | ||||
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); | Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); | ||||
} | } | ||||
StmtResult | |||||
Sema::ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, | |||||
SourceLocation StartLoc, SourceLocation EndLoc, | |||||
VarsWithInheritedDSAType &VarsWithImplicitDSA) { | |||||
auto SizesClauses = | |||||
OMPExecutableDirective::getClausesOfKind<OMPSizesClause>(Clauses); | |||||
if (SizesClauses.begin() == SizesClauses.end()) { | |||||
// A missing 'sizes' clause is already reported by the parser. | |||||
return StmtError(); | |||||
} | |||||
const OMPSizesClause *SizesClause = *SizesClauses.begin(); | |||||
unsigned NumLoops = SizesClause->getNumSizes(); | |||||
// Empty statement should only be possible if there already was an error. | |||||
if (!AStmt) | |||||
return StmtError(); | |||||
// Verify and diagnose loop nest. | |||||
OMPLoopDirective::HelperExprs NestHelper; | |||||
unsigned NestedLoopCount = checkOpenMPLoop( | |||||
OMPD_tile, nullptr, nullptr, AStmt, *this, *DSAStack, VarsWithImplicitDSA, | |||||
NestHelper, NumLoops, /*EmitDiags=*/true); | |||||
if (NestedLoopCount != NumLoops) | |||||
return StmtError(); | |||||
// Delay tiling to when template is completely instantiated. | |||||
if (CurContext->isDependentContext()) | |||||
return OMPTileDirective::Create(Context, StartLoc, EndLoc, Clauses, | |||||
NumLoops, AStmt, nullptr); | |||||
// Derive per-loop logical iteration spaces. | |||||
SmallVector<OMPLoopDirective::HelperExprs, 4> LoopHelpers; | |||||
LoopHelpers.resize(NumLoops); | |||||
for (unsigned i = 0; i < NumLoops; ++i) { | |||||
Stmt *LoopStmt = NestHelper.Loops[i]; | |||||
VarsWithInheritedDSAType TmpDSA; | |||||
unsigned SingleNumLoops = | |||||
checkOpenMPLoop(OMPD_tile, nullptr, nullptr, LoopStmt, *this, *DSAStack, | |||||
TmpDSA, LoopHelpers[i], 1, /*EmitDiags=*/false); | |||||
(void)SingleNumLoops; | |||||
assert(SingleNumLoops == 1 && "Expect single loop iteration space"); | |||||
} | |||||
// Collection of generated variable declaration. | |||||
SmallVector<Stmt *, 9> PreInits; | |||||
// Create iteration variables for the generated loops. | |||||
SmallVector<VarDecl *, 4> FloorIndVars; | |||||
SmallVector<VarDecl *, 4> TileIndVars; | |||||
SmallVector<Stmt *, 9> BodyParts; | |||||
FloorIndVars.resize(NumLoops); | |||||
TileIndVars.resize(NumLoops); | |||||
BodyParts.reserve(2 * NumLoops + 1); | |||||
for (unsigned i = 0; i < NumLoops; i += 1) { | |||||
OMPLoopDirective::HelperExprs &LoopHelper = LoopHelpers[i]; | |||||
assert(LoopHelper.Counters.size() == 1 && | |||||
"Expect single-dimensional loop iteration space"); | |||||
auto *OrigCntVar = cast<DeclRefExpr>(LoopHelper.Counters[0]); | |||||
std::string OrigVarName = OrigCntVar->getNameInfo().getAsString(); | |||||
DeclRefExpr *IterVarRef = cast<DeclRefExpr>(LoopHelper.IterationVarRef); | |||||
QualType CntTy = IterVarRef->getType(); | |||||
// Iteration variable for the floor (i.e. outer) loop. | |||||
{ | |||||
std::string FloorCntName = | |||||
(Twine(".floor_") + llvm::utostr(i) + ".iv." + OrigVarName).str(); | |||||
VarDecl *FloorCntDecl = | |||||
buildVarDecl(*this, {}, CntTy, FloorCntName, nullptr, OrigCntVar); | |||||
FloorIndVars[i] = FloorCntDecl; | |||||
// Create a declaration statement for the new iteration variable. | |||||
Decl *D = FloorCntDecl; | |||||
auto *DeclS = | |||||
new (Context) DeclStmt(DeclGroupRef::Create(Context, &D, 1), {}, {}); | |||||
PreInits.push_back(DeclS); | |||||
} | |||||
// Iteration variable for the tile (i.e. inner) loop. | |||||
{ | |||||
std::string TileCntName = | |||||
(Twine(".tile_") + llvm::utostr(i) + ".iv." + OrigVarName).str(); | |||||
// Reuse the iteration variable created by checkOpenMPLoop. It is also | |||||
// used by the expressions to derive the original iteration variable's | |||||
// value from the logical iteration number. | |||||
auto *TileCntDecl = cast<VarDecl>(IterVarRef->getDecl()); | |||||
TileCntDecl->setDeclName(&PP.getIdentifierTable().get(TileCntName)); | |||||
TileIndVars[i] = TileCntDecl; | |||||
// Create a declaration statement for the new iteration variable. | |||||
Decl *D = TileCntDecl; | |||||
auto DeclS = | |||||
new (Context) DeclStmt(DeclGroupRef::Create(Context, &D, 1), {}, {}); | |||||
PreInits.push_back(DeclS); | |||||
} | |||||
// Statements to set the original iteration variable's value from the | |||||
// logical iteration number. | |||||
// FIXME: If the innermost body is an loop itself, inserting these | |||||
// statements stops it being recognized as a perfectly nested loop (e.g. | |||||
// for applying tiling again). If this is the case, sink the expressions | |||||
// further into the inner loop. | |||||
{ | |||||
// Declaration of the original loop iteration variable. | |||||
Decl *CounterDecl = OrigCntVar->getDecl(); | |||||
auto *CounterDeclStmt = new (Context) | |||||
DeclStmt(DeclGroupRef::Create(Context, &CounterDecl, 1), {}, {}); | |||||
// Update expression generated by checkOpenMPLoop. | |||||
Stmt *Upd = LoopHelper.Updates[0]; | |||||
BodyParts.push_back(CounterDeclStmt); | |||||
BodyParts.push_back(Upd); | |||||
} | |||||
} | |||||
// Once the original iteration values are set, append the innermost body. | |||||
BodyParts.push_back(NestHelper.Bodys.back()); | |||||
Stmt *Inner = CompoundStmt::Create(Context, BodyParts, AStmt->getBeginLoc(), | |||||
AStmt->getEndLoc()); | |||||
// Create tile loops from the inside to the outside. | |||||
for (int i = NumLoops - 1; i >= 0; --i) { | |||||
OMPLoopDirective::HelperExprs &LoopHelper = LoopHelpers[i]; | |||||
Expr *NumIterations = LoopHelper.NumIterations; | |||||
auto *OrigCntVar = cast<DeclRefExpr>(LoopHelper.Counters[0]); | |||||
QualType CntTy = OrigCntVar->getType(); | |||||
Expr *DimTileSize = SizesClause->getSizesRefs()[i]; | |||||
Scope *CurScope = getCurScope(); | |||||
// Commonly used variables. | |||||
DeclRefExpr *TileIV = buildDeclRefExpr(*this, TileIndVars[i], CntTy, {}); | |||||
DeclRefExpr *FloorIV = buildDeclRefExpr(*this, FloorIndVars[i], CntTy, {}); | |||||
// For init-statement: .tile.iv = .floor.iv | |||||
ExprResult InitStmt = BuildBinOp(CurScope, {}, BO_Assign, TileIV, FloorIV); | |||||
if (!InitStmt.isUsable()) | |||||
return StmtError(); | |||||
// For cond-expression: .tile.iv < min(.floor.iv + DimTileSize, | |||||
// NumIterations) | |||||
ExprResult EndOfTile = | |||||
BuildBinOp(CurScope, {}, BO_Add, FloorIV, DimTileSize); | |||||
if (!EndOfTile.isUsable()) | |||||
return StmtError(); | |||||
ExprResult IsPartialTile = | |||||
BuildBinOp(CurScope, {}, BO_LT, NumIterations, EndOfTile.get()); | |||||
if (!IsPartialTile.isUsable()) | |||||
return StmtError(); | |||||
ExprResult MinTileAndIterSpace = ActOnConditionalOp( | |||||
{}, {}, IsPartialTile.get(), NumIterations, EndOfTile.get()); | |||||
if (!MinTileAndIterSpace.isUsable()) | |||||
return StmtError(); | |||||
ExprResult CondExpr = | |||||
BuildBinOp(CurScope, {}, BO_LT, TileIV, MinTileAndIterSpace.get()); | |||||
if (!CondExpr.isUsable()) | |||||
return StmtError(); | |||||
// For incr-statement: ++.tile.iv | |||||
ExprResult IncrStmt = BuildUnaryOp(CurScope, {}, UO_PreInc, TileIV); | |||||
if (!IncrStmt.isUsable()) | |||||
return StmtError(); | |||||
Inner = new (Context) ForStmt(Context, InitStmt.get(), CondExpr.get(), | |||||
nullptr, IncrStmt.get(), Inner, {}, {}, {}); | |||||
} | |||||
// Create floor loops from the inside to the outside. | |||||
for (int i = NumLoops - 1; i >= 0; --i) { | |||||
auto &LoopHelper = LoopHelpers[i]; | |||||
Expr *NumIterations = LoopHelper.NumIterations; | |||||
DeclRefExpr *OrigCntVar = cast<DeclRefExpr>(LoopHelper.Counters[0]); | |||||
QualType CntTy = OrigCntVar->getType(); | |||||
Expr *DimTileSize = SizesClause->getSizesRefs()[i]; | |||||
Scope *CurScope = getCurScope(); | |||||
// Commonly used variables. | |||||
DeclRefExpr *FloorIV = buildDeclRefExpr(*this, FloorIndVars[i], CntTy, {}); | |||||
// For init-statement: .floor.iv = 0 | |||||
auto *IVStart = IntegerLiteral::Create( | |||||
Context, llvm::APInt::getNullValue(Context.getTypeSize(CntTy)), CntTy, | |||||
{}); | |||||
ExprResult InitStmt = BuildBinOp(CurScope, {}, BO_Assign, FloorIV, IVStart); | |||||
if (!InitStmt.isUsable()) | |||||
return StmtError(); | |||||
// For cond-expression: .floor.iv < NumIterations | |||||
ExprResult CondExpr = | |||||
BuildBinOp(CurScope, {}, BO_LT, FloorIV, NumIterations); | |||||
if (!CondExpr.isUsable()) | |||||
return StmtError(); | |||||
// For incr-statement: .floor.iv += DimTileSize | |||||
ExprResult IncrStmt = | |||||
BuildBinOp(CurScope, {}, BO_AddAssign, FloorIV, DimTileSize); | |||||
if (!IncrStmt.isUsable()) | |||||
return StmtError(); | |||||
Inner = new (Context) ForStmt(Context, InitStmt.get(), CondExpr.get(), | |||||
nullptr, IncrStmt.get(), Inner, {}, {}, {}); | |||||
} | |||||
// Create the de-sugared tile loop nest including pre-inits. | |||||
PreInits.push_back(Inner); | |||||
auto *TransformedStmt = CompoundStmt::Create(Context, PreInits, {}, {}); | |||||
return OMPTileDirective::Create(Context, StartLoc, EndLoc, Clauses, NumLoops, | |||||
AStmt, TransformedStmt); | |||||
} | |||||
OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, | OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, | ||||
SourceLocation StartLoc, | SourceLocation StartLoc, | ||||
SourceLocation LParenLoc, | SourceLocation LParenLoc, | ||||
SourceLocation EndLoc) { | SourceLocation EndLoc) { | ||||
OMPClause *Res = nullptr; | OMPClause *Res = nullptr; | ||||
switch (Kind) { | switch (Kind) { | ||||
case OMPC_final: | case OMPC_final: | ||||
Res = ActOnOpenMPFinalClause(Expr, StartLoc, LParenLoc, EndLoc); | Res = ActOnOpenMPFinalClause(Expr, StartLoc, LParenLoc, EndLoc); | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, | ||||
case OMPC_linear: | case OMPC_linear: | ||||
case OMPC_aligned: | case OMPC_aligned: | ||||
case OMPC_copyin: | case OMPC_copyin: | ||||
case OMPC_copyprivate: | case OMPC_copyprivate: | ||||
case OMPC_nowait: | case OMPC_nowait: | ||||
case OMPC_untied: | case OMPC_untied: | ||||
case OMPC_mergeable: | case OMPC_mergeable: | ||||
case OMPC_threadprivate: | case OMPC_threadprivate: | ||||
case OMPC_sizes: | |||||
case OMPC_allocate: | case OMPC_allocate: | ||||
case OMPC_flush: | case OMPC_flush: | ||||
case OMPC_read: | case OMPC_read: | ||||
case OMPC_write: | case OMPC_write: | ||||
case OMPC_update: | case OMPC_update: | ||||
case OMPC_capture: | case OMPC_capture: | ||||
case OMPC_seq_cst: | case OMPC_seq_cst: | ||||
case OMPC_acq_rel: | case OMPC_acq_rel: | ||||
▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | case OMPC_if: | ||||
case OMPD_master_taskloop: | case OMPD_master_taskloop: | ||||
case OMPD_target_data: | case OMPD_target_data: | ||||
case OMPD_simd: | case OMPD_simd: | ||||
case OMPD_for_simd: | case OMPD_for_simd: | ||||
case OMPD_distribute_simd: | case OMPD_distribute_simd: | ||||
// Do not capture if-clause expressions. | // Do not capture if-clause expressions. | ||||
break; | break; | ||||
case OMPD_threadprivate: | case OMPD_threadprivate: | ||||
case OMPD_tile: | |||||
case OMPD_allocate: | case OMPD_allocate: | ||||
case OMPD_taskyield: | case OMPD_taskyield: | ||||
case OMPD_barrier: | case OMPD_barrier: | ||||
case OMPD_taskwait: | case OMPD_taskwait: | ||||
case OMPD_cancellation_point: | case OMPD_cancellation_point: | ||||
case OMPD_flush: | case OMPD_flush: | ||||
case OMPD_depobj: | case OMPD_depobj: | ||||
case OMPD_scan: | case OMPD_scan: | ||||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | case OMPC_num_threads: | ||||
case OMPD_declare_simd: | case OMPD_declare_simd: | ||||
case OMPD_declare_variant: | case OMPD_declare_variant: | ||||
case OMPD_begin_declare_variant: | case OMPD_begin_declare_variant: | ||||
case OMPD_end_declare_variant: | case OMPD_end_declare_variant: | ||||
case OMPD_declare_target: | case OMPD_declare_target: | ||||
case OMPD_end_declare_target: | case OMPD_end_declare_target: | ||||
case OMPD_teams: | case OMPD_teams: | ||||
case OMPD_simd: | case OMPD_simd: | ||||
case OMPD_tile: | |||||
case OMPD_for: | case OMPD_for: | ||||
case OMPD_for_simd: | case OMPD_for_simd: | ||||
case OMPD_sections: | case OMPD_sections: | ||||
case OMPD_section: | case OMPD_section: | ||||
case OMPD_single: | case OMPD_single: | ||||
case OMPD_master: | case OMPD_master: | ||||
case OMPD_critical: | case OMPD_critical: | ||||
case OMPD_taskgroup: | case OMPD_taskgroup: | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | case OMPC_num_teams: | ||||
case OMPD_declare_mapper: | case OMPD_declare_mapper: | ||||
case OMPD_declare_simd: | case OMPD_declare_simd: | ||||
case OMPD_declare_variant: | case OMPD_declare_variant: | ||||
case OMPD_begin_declare_variant: | case OMPD_begin_declare_variant: | ||||
case OMPD_end_declare_variant: | case OMPD_end_declare_variant: | ||||
case OMPD_declare_target: | case OMPD_declare_target: | ||||
case OMPD_end_declare_target: | case OMPD_end_declare_target: | ||||
case OMPD_simd: | case OMPD_simd: | ||||
case OMPD_tile: | |||||
case OMPD_for: | case OMPD_for: | ||||
case OMPD_for_simd: | case OMPD_for_simd: | ||||
case OMPD_sections: | case OMPD_sections: | ||||
case OMPD_section: | case OMPD_section: | ||||
case OMPD_single: | case OMPD_single: | ||||
case OMPD_master: | case OMPD_master: | ||||
case OMPD_critical: | case OMPD_critical: | ||||
case OMPD_taskgroup: | case OMPD_taskgroup: | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | case OMPC_thread_limit: | ||||
case OMPD_declare_mapper: | case OMPD_declare_mapper: | ||||
case OMPD_declare_simd: | case OMPD_declare_simd: | ||||
case OMPD_declare_variant: | case OMPD_declare_variant: | ||||
case OMPD_begin_declare_variant: | case OMPD_begin_declare_variant: | ||||
case OMPD_end_declare_variant: | case OMPD_end_declare_variant: | ||||
case OMPD_declare_target: | case OMPD_declare_target: | ||||
case OMPD_end_declare_target: | case OMPD_end_declare_target: | ||||
case OMPD_simd: | case OMPD_simd: | ||||
case OMPD_tile: | |||||
case OMPD_for: | case OMPD_for: | ||||
case OMPD_for_simd: | case OMPD_for_simd: | ||||
case OMPD_sections: | case OMPD_sections: | ||||
case OMPD_section: | case OMPD_section: | ||||
case OMPD_single: | case OMPD_single: | ||||
case OMPD_master: | case OMPD_master: | ||||
case OMPD_critical: | case OMPD_critical: | ||||
case OMPD_taskgroup: | case OMPD_taskgroup: | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | case OMPC_schedule: | ||||
case OMPD_declare_mapper: | case OMPD_declare_mapper: | ||||
case OMPD_declare_simd: | case OMPD_declare_simd: | ||||
case OMPD_declare_variant: | case OMPD_declare_variant: | ||||
case OMPD_begin_declare_variant: | case OMPD_begin_declare_variant: | ||||
case OMPD_end_declare_variant: | case OMPD_end_declare_variant: | ||||
case OMPD_declare_target: | case OMPD_declare_target: | ||||
case OMPD_end_declare_target: | case OMPD_end_declare_target: | ||||
case OMPD_simd: | case OMPD_simd: | ||||
case OMPD_tile: | |||||
case OMPD_sections: | case OMPD_sections: | ||||
case OMPD_section: | case OMPD_section: | ||||
case OMPD_single: | case OMPD_single: | ||||
case OMPD_master: | case OMPD_master: | ||||
case OMPD_critical: | case OMPD_critical: | ||||
case OMPD_taskgroup: | case OMPD_taskgroup: | ||||
case OMPD_distribute: | case OMPD_distribute: | ||||
case OMPD_ordered: | case OMPD_ordered: | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | case OMPC_dist_schedule: | ||||
case OMPD_declare_mapper: | case OMPD_declare_mapper: | ||||
case OMPD_declare_simd: | case OMPD_declare_simd: | ||||
case OMPD_declare_variant: | case OMPD_declare_variant: | ||||
case OMPD_begin_declare_variant: | case OMPD_begin_declare_variant: | ||||
case OMPD_end_declare_variant: | case OMPD_end_declare_variant: | ||||
case OMPD_declare_target: | case OMPD_declare_target: | ||||
case OMPD_end_declare_target: | case OMPD_end_declare_target: | ||||
case OMPD_simd: | case OMPD_simd: | ||||
case OMPD_tile: | |||||
case OMPD_for: | case OMPD_for: | ||||
case OMPD_for_simd: | case OMPD_for_simd: | ||||
case OMPD_sections: | case OMPD_sections: | ||||
case OMPD_section: | case OMPD_section: | ||||
case OMPD_single: | case OMPD_single: | ||||
case OMPD_master: | case OMPD_master: | ||||
case OMPD_critical: | case OMPD_critical: | ||||
case OMPD_taskgroup: | case OMPD_taskgroup: | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | case OMPC_device: | ||||
case OMPD_declare_mapper: | case OMPD_declare_mapper: | ||||
case OMPD_declare_simd: | case OMPD_declare_simd: | ||||
case OMPD_declare_variant: | case OMPD_declare_variant: | ||||
case OMPD_begin_declare_variant: | case OMPD_begin_declare_variant: | ||||
case OMPD_end_declare_variant: | case OMPD_end_declare_variant: | ||||
case OMPD_declare_target: | case OMPD_declare_target: | ||||
case OMPD_end_declare_target: | case OMPD_end_declare_target: | ||||
case OMPD_simd: | case OMPD_simd: | ||||
case OMPD_tile: | |||||
case OMPD_for: | case OMPD_for: | ||||
case OMPD_for_simd: | case OMPD_for_simd: | ||||
case OMPD_sections: | case OMPD_sections: | ||||
case OMPD_section: | case OMPD_section: | ||||
case OMPD_single: | case OMPD_single: | ||||
case OMPD_master: | case OMPD_master: | ||||
case OMPD_critical: | case OMPD_critical: | ||||
case OMPD_taskgroup: | case OMPD_taskgroup: | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | case OMPC_priority: | ||||
case OMPD_declare_mapper: | case OMPD_declare_mapper: | ||||
case OMPD_declare_simd: | case OMPD_declare_simd: | ||||
case OMPD_declare_variant: | case OMPD_declare_variant: | ||||
case OMPD_begin_declare_variant: | case OMPD_begin_declare_variant: | ||||
case OMPD_end_declare_variant: | case OMPD_end_declare_variant: | ||||
case OMPD_declare_target: | case OMPD_declare_target: | ||||
case OMPD_end_declare_target: | case OMPD_end_declare_target: | ||||
case OMPD_simd: | case OMPD_simd: | ||||
case OMPD_tile: | |||||
case OMPD_for: | case OMPD_for: | ||||
case OMPD_for_simd: | case OMPD_for_simd: | ||||
case OMPD_sections: | case OMPD_sections: | ||||
case OMPD_section: | case OMPD_section: | ||||
case OMPD_single: | case OMPD_single: | ||||
case OMPD_master: | case OMPD_master: | ||||
case OMPD_critical: | case OMPD_critical: | ||||
case OMPD_taskgroup: | case OMPD_taskgroup: | ||||
Show All 12 Lines | static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( | ||||
case OMPC_reduction: | case OMPC_reduction: | ||||
case OMPC_task_reduction: | case OMPC_task_reduction: | ||||
case OMPC_in_reduction: | case OMPC_in_reduction: | ||||
case OMPC_linear: | case OMPC_linear: | ||||
case OMPC_default: | case OMPC_default: | ||||
case OMPC_proc_bind: | case OMPC_proc_bind: | ||||
case OMPC_safelen: | case OMPC_safelen: | ||||
case OMPC_simdlen: | case OMPC_simdlen: | ||||
case OMPC_sizes: | |||||
case OMPC_allocator: | case OMPC_allocator: | ||||
case OMPC_collapse: | case OMPC_collapse: | ||||
case OMPC_private: | case OMPC_private: | ||||
case OMPC_shared: | case OMPC_shared: | ||||
case OMPC_aligned: | case OMPC_aligned: | ||||
case OMPC_copyin: | case OMPC_copyin: | ||||
case OMPC_copyprivate: | case OMPC_copyprivate: | ||||
case OMPC_ordered: | case OMPC_ordered: | ||||
▲ Show 20 Lines • Show All 414 Lines • ▼ Show 20 Lines | case OMPC_update: | ||||
Res = ActOnOpenMPUpdateClause(static_cast<OpenMPDependClauseKind>(Argument), | Res = ActOnOpenMPUpdateClause(static_cast<OpenMPDependClauseKind>(Argument), | ||||
ArgumentLoc, StartLoc, LParenLoc, EndLoc); | ArgumentLoc, StartLoc, LParenLoc, EndLoc); | ||||
break; | break; | ||||
case OMPC_if: | case OMPC_if: | ||||
case OMPC_final: | case OMPC_final: | ||||
case OMPC_num_threads: | case OMPC_num_threads: | ||||
case OMPC_safelen: | case OMPC_safelen: | ||||
case OMPC_simdlen: | case OMPC_simdlen: | ||||
case OMPC_sizes: | |||||
case OMPC_allocator: | case OMPC_allocator: | ||||
case OMPC_collapse: | case OMPC_collapse: | ||||
case OMPC_schedule: | case OMPC_schedule: | ||||
case OMPC_private: | case OMPC_private: | ||||
case OMPC_firstprivate: | case OMPC_firstprivate: | ||||
case OMPC_lastprivate: | case OMPC_lastprivate: | ||||
case OMPC_shared: | case OMPC_shared: | ||||
case OMPC_reduction: | case OMPC_reduction: | ||||
▲ Show 20 Lines • Show All 164 Lines • ▼ Show 20 Lines | Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) | ||||
/*Last=*/OMPC_DEPEND_unknown, Except) | /*Last=*/OMPC_DEPEND_unknown, Except) | ||||
<< getOpenMPClauseName(OMPC_update); | << getOpenMPClauseName(OMPC_update); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
return OMPUpdateClause::Create(Context, StartLoc, LParenLoc, KindKwLoc, Kind, | return OMPUpdateClause::Create(Context, StartLoc, LParenLoc, KindKwLoc, Kind, | ||||
EndLoc); | EndLoc); | ||||
} | } | ||||
OMPClause *Sema::ActOnOpenMPSizesClause(ArrayRef<Expr *> SizeExprs, | |||||
SourceLocation StartLoc, | |||||
SourceLocation LParenLoc, | |||||
SourceLocation EndLoc) { | |||||
for (auto SizeExpr : SizeExprs) { | |||||
ExprResult NumForLoopsResult = | |||||
VerifyPositiveIntegerConstantInClause(SizeExpr, OMPC_sizes, true); | |||||
if (!NumForLoopsResult.isUsable()) | |||||
return nullptr; | |||||
} | |||||
DSAStack->setAssociatedLoops(SizeExprs.size()); | |||||
return OMPSizesClause::Create(Context, StartLoc, LParenLoc, EndLoc, | |||||
SizeExprs); | |||||
} | |||||
OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( | OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( | ||||
OpenMPClauseKind Kind, ArrayRef<unsigned> Argument, Expr *Expr, | OpenMPClauseKind Kind, ArrayRef<unsigned> Argument, Expr *Expr, | ||||
SourceLocation StartLoc, SourceLocation LParenLoc, | SourceLocation StartLoc, SourceLocation LParenLoc, | ||||
ArrayRef<SourceLocation> ArgumentLoc, SourceLocation DelimLoc, | ArrayRef<SourceLocation> ArgumentLoc, SourceLocation DelimLoc, | ||||
SourceLocation EndLoc) { | SourceLocation EndLoc) { | ||||
OMPClause *Res = nullptr; | OMPClause *Res = nullptr; | ||||
switch (Kind) { | switch (Kind) { | ||||
case OMPC_schedule: | case OMPC_schedule: | ||||
Show All 31 Lines | case OMPC_device: | ||||
Res = ActOnOpenMPDeviceClause( | Res = ActOnOpenMPDeviceClause( | ||||
static_cast<OpenMPDeviceClauseModifier>(Argument.back()), Expr, | static_cast<OpenMPDeviceClauseModifier>(Argument.back()), Expr, | ||||
StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc); | StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc); | ||||
break; | break; | ||||
case OMPC_final: | case OMPC_final: | ||||
case OMPC_num_threads: | case OMPC_num_threads: | ||||
case OMPC_safelen: | case OMPC_safelen: | ||||
case OMPC_simdlen: | case OMPC_simdlen: | ||||
case OMPC_sizes: | |||||
case OMPC_allocator: | case OMPC_allocator: | ||||
case OMPC_collapse: | case OMPC_collapse: | ||||
case OMPC_default: | case OMPC_default: | ||||
case OMPC_proc_bind: | case OMPC_proc_bind: | ||||
case OMPC_private: | case OMPC_private: | ||||
case OMPC_firstprivate: | case OMPC_firstprivate: | ||||
case OMPC_lastprivate: | case OMPC_lastprivate: | ||||
case OMPC_shared: | case OMPC_shared: | ||||
▲ Show 20 Lines • Show All 238 Lines • ▼ Show 20 Lines | OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, | ||||
case OMPC_destroy: | case OMPC_destroy: | ||||
Res = ActOnOpenMPDestroyClause(StartLoc, EndLoc); | Res = ActOnOpenMPDestroyClause(StartLoc, EndLoc); | ||||
break; | break; | ||||
case OMPC_if: | case OMPC_if: | ||||
case OMPC_final: | case OMPC_final: | ||||
case OMPC_num_threads: | case OMPC_num_threads: | ||||
case OMPC_safelen: | case OMPC_safelen: | ||||
case OMPC_simdlen: | case OMPC_simdlen: | ||||
case OMPC_sizes: | |||||
case OMPC_allocator: | case OMPC_allocator: | ||||
case OMPC_collapse: | case OMPC_collapse: | ||||
case OMPC_schedule: | case OMPC_schedule: | ||||
case OMPC_private: | case OMPC_private: | ||||
case OMPC_firstprivate: | case OMPC_firstprivate: | ||||
case OMPC_lastprivate: | case OMPC_lastprivate: | ||||
case OMPC_shared: | case OMPC_shared: | ||||
case OMPC_reduction: | case OMPC_reduction: | ||||
▲ Show 20 Lines • Show All 261 Lines • ▼ Show 20 Lines | Res = ActOnOpenMPAffinityClause(StartLoc, LParenLoc, ColonLoc, EndLoc, | ||||
DepModOrTailExpr, VarList); | DepModOrTailExpr, VarList); | ||||
break; | break; | ||||
case OMPC_if: | case OMPC_if: | ||||
case OMPC_depobj: | case OMPC_depobj: | ||||
case OMPC_final: | case OMPC_final: | ||||
case OMPC_num_threads: | case OMPC_num_threads: | ||||
case OMPC_safelen: | case OMPC_safelen: | ||||
case OMPC_simdlen: | case OMPC_simdlen: | ||||
case OMPC_sizes: | |||||
case OMPC_allocator: | case OMPC_allocator: | ||||
case OMPC_collapse: | case OMPC_collapse: | ||||
case OMPC_default: | case OMPC_default: | ||||
case OMPC_proc_bind: | case OMPC_proc_bind: | ||||
case OMPC_schedule: | case OMPC_schedule: | ||||
case OMPC_ordered: | case OMPC_ordered: | ||||
case OMPC_nowait: | case OMPC_nowait: | ||||
case OMPC_untied: | case OMPC_untied: | ||||
▲ Show 20 Lines • Show All 5,522 Lines • Show Last 20 Lines |
clang-format not found in user's PATH; not linting file.