[OPENMP] Allow to use global variables as lcv in loop-based directives.
For proper codegen we need to capture variable in the OpenMP region. In loop-based directives loop control variables are private by default and they must be captured in this region. There was a problem with capturing of globals, used as lcv, as they was not marked as private by default.
Differential Revision: http://reviews.llvm.org/D9336
llvm-svn: 236201
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 06b9d56..fb3cd9a 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -82,10 +82,12 @@
};
typedef llvm::SmallDenseMap<VarDecl *, DSAInfo, 64> DeclSAMapTy;
typedef llvm::SmallDenseMap<VarDecl *, DeclRefExpr *, 64> AlignedMapTy;
+ typedef llvm::DenseSet<VarDecl *> LoopControlVariablesSetTy;
struct SharingMapTy {
DeclSAMapTy SharingMap;
AlignedMapTy AlignedMap;
+ LoopControlVariablesSetTy LCVSet;
DefaultDataSharingAttributes DefaultAttr;
SourceLocation DefaultAttrLoc;
OpenMPDirectiveKind Directive;
@@ -93,16 +95,19 @@
Scope *CurScope;
SourceLocation ConstructLoc;
bool OrderedRegion;
+ unsigned CollapseNumber;
SourceLocation InnerTeamsRegionLoc;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope, SourceLocation Loc)
- : SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified),
+ : SharingMap(), AlignedMap(), LCVSet(), DefaultAttr(DSA_unspecified),
Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope),
- ConstructLoc(Loc), OrderedRegion(false), InnerTeamsRegionLoc() {}
+ ConstructLoc(Loc), OrderedRegion(false), CollapseNumber(1),
+ InnerTeamsRegionLoc() {}
SharingMapTy()
- : SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified),
+ : SharingMap(), AlignedMap(), LCVSet(), DefaultAttr(DSA_unspecified),
Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr),
- ConstructLoc(), OrderedRegion(false), InnerTeamsRegionLoc() {}
+ ConstructLoc(), OrderedRegion(false), CollapseNumber(1),
+ InnerTeamsRegionLoc() {}
};
typedef SmallVector<SharingMapTy, 64> StackTy;
@@ -137,6 +142,12 @@
/// for diagnostics.
DeclRefExpr *addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE);
+ /// \brief Register specified variable as loop control variable.
+ void addLoopControlVariable(VarDecl *D);
+ /// \brief Check if the specified variable is a loop control variable for
+ /// current region.
+ bool isLoopControlVariable(VarDecl *D);
+
/// \brief Adds explicit data sharing attribute to the specified declaration.
void addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A);
@@ -209,6 +220,13 @@
return false;
}
+ /// \brief Set collapse value for the region.
+ void setCollapseNumber(unsigned Val) { Stack.back().CollapseNumber = Val; }
+ /// \brief Return collapse value for region.
+ unsigned getCollapseNumber() const {
+ return Stack.back().CollapseNumber;
+ }
+
/// \brief Marks current target region as one with closely nested teams
/// region.
void setParentTeamsRegionLoc(SourceLocation TeamsRegionLoc) {
@@ -356,6 +374,18 @@
return nullptr;
}
+void DSAStackTy::addLoopControlVariable(VarDecl *D) {
+ assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
+ D = D->getCanonicalDecl();
+ Stack.back().LCVSet.insert(D);
+}
+
+bool DSAStackTy::isLoopControlVariable(VarDecl *D) {
+ assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
+ D = D->getCanonicalDecl();
+ return Stack.back().LCVSet.count(D) > 0;
+}
+
void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) {
D = D->getCanonicalDecl();
if (A == OMPC_threadprivate) {
@@ -556,6 +586,8 @@
assert(LangOpts.OpenMP && "OpenMP is not allowed");
VD = VD->getCanonicalDecl();
if (DSAStack->getCurrentDirective() != OMPD_unknown) {
+ if (DSAStack->isLoopControlVariable(VD))
+ return true;
auto DVarPrivate = DSAStack->getTopDSA(VD, /*FromParent=*/false);
if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind))
return true;
@@ -1956,7 +1988,7 @@
TestIsStrictOp(false), SubtractStep(false) {}
/// \brief Check init-expr for canonical loop form and save loop counter
/// variable - #Var and its initialization value - #LB.
- bool CheckInit(Stmt *S);
+ bool CheckInit(Stmt *S, bool EmitDiags = true);
/// \brief Check test-expr for canonical form, save upper-bound (#UB), flags
/// for less/greater and for strict/non-strict comparison.
bool CheckCond(Expr *S);
@@ -2096,7 +2128,7 @@
return false;
}
-bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S) {
+bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) {
// Check init-expr for canonical loop form and save loop counter
// variable - #Var and its initialization value - #LB.
// OpenMP [2.6] Canonical loop form. init-expr may be one of the following:
@@ -2106,7 +2138,9 @@
// pointer-type var = lb
//
if (!S) {
- SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_init);
+ if (EmitDiags) {
+ SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_init);
+ }
return true;
}
InitSrcRange = S->getSourceRange();
@@ -2122,7 +2156,7 @@
if (auto Var = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) {
if (Var->hasInit()) {
// Accept non-canonical init form here but emit ext. warning.
- if (Var->getInitStyle() != VarDecl::CInit)
+ if (Var->getInitStyle() != VarDecl::CInit && EmitDiags)
SemaRef.Diag(S->getLocStart(),
diag::ext_omp_loop_not_canonical_init)
<< S->getSourceRange();
@@ -2136,8 +2170,10 @@
return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), DRE,
CE->getArg(1));
- SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init)
- << S->getSourceRange();
+ if (EmitDiags) {
+ SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init)
+ << S->getSourceRange();
+ }
return true;
}
@@ -2398,7 +2434,8 @@
/// \brief Build reference expression to the counter be used for codegen.
Expr *OpenMPIterationSpaceChecker::BuildCounterVar() const {
return DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(),
- GetIncrementSrcRange().getBegin(), Var, false,
+ GetIncrementSrcRange().getBegin(), Var,
+ /*RefersToEnclosingVariableOrCapture=*/true,
DefaultLoc, Var->getType(), VK_LValue);
}
@@ -2434,6 +2471,20 @@
} // namespace
+void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
+ assert(getLangOpts().OpenMP && "OpenMP is not active.");
+ assert(Init && "Expected loop in canonical form.");
+ unsigned CollapseIteration = DSAStack->getCollapseNumber();
+ if (CollapseIteration > 0 &&
+ isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
+ OpenMPIterationSpaceChecker ISC(*this, ForLoc);
+ if (!ISC.CheckInit(Init, /*EmitDiags=*/false)) {
+ DSAStack->addLoopControlVariable(ISC.GetLoopVar());
+ }
+ DSAStack->setCollapseNumber(CollapseIteration - 1);
+ }
+}
+
/// \brief Called on a for stmt to check and extract its iteration space
/// for further processing (such as collapsing).
static bool CheckOpenMPIterationSpace(
@@ -2526,18 +2577,10 @@
// Make the loop iteration variable private (for worksharing constructs),
// linear (for simd directives with the only one associated loop) or
// lastprivate (for simd directives with several collapsed loops).
- // FIXME: the next check and error message must be removed once the
- // capturing of global variables in loops is fixed.
if (DVar.CKind == OMPC_unknown)
DVar = DSA.hasDSA(Var, isOpenMPPrivate, MatchesAlways(),
/*FromParent=*/false);
- if (!Var->hasLocalStorage() && DVar.CKind == OMPC_unknown) {
- SemaRef.Diag(Init->getLocStart(), diag::err_omp_global_loop_var_dsa)
- << getOpenMPClauseName(PredeterminedCKind)
- << getOpenMPDirectiveName(DKind);
- HasErrors = true;
- } else
- DSA.addDSA(Var, LoopVarRefExpr, PredeterminedCKind);
+ DSA.addDSA(Var, LoopVarRefExpr, PredeterminedCKind);
}
assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars");
@@ -4210,6 +4253,9 @@
<< E->getSourceRange();
return ExprError();
}
+ if (CKind == OMPC_collapse) {
+ DSAStack->setCollapseNumber(Result.getExtValue());
+ }
return ICE;
}