aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/SemaOpenACC.cpp173
-rw-r--r--clang/lib/Sema/SemaOpenACCClause.cpp4
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp27
-rw-r--r--clang/lib/Sema/TreeTransform.h25
4 files changed, 216 insertions, 13 deletions
diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index f3969a9..ca99834 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -2883,12 +2883,12 @@ SemaOpenACC::CreateFirstPrivateInitRecipe(const Expr *VarExpr) {
return OpenACCFirstPrivateRecipe(AllocaDecl, Temporary);
}
-OpenACCReductionRecipe SemaOpenACC::CreateReductionInitRecipe(
+OpenACCReductionRecipeWithStorage SemaOpenACC::CreateReductionInitRecipe(
OpenACCReductionOperator ReductionOperator, const Expr *VarExpr) {
// We don't strip bounds here, so that we are doing our recipe init at the
// 'lowest' possible level. Codegen is going to have to do its own 'looping'.
if (!VarExpr || VarExpr->getType()->isDependentType())
- return OpenACCReductionRecipe::Empty();
+ return OpenACCReductionRecipeWithStorage::Empty();
QualType VarTy =
VarExpr->getType().getNonReferenceType().getUnqualifiedType();
@@ -2898,6 +2898,15 @@ OpenACCReductionRecipe SemaOpenACC::CreateReductionInitRecipe(
dyn_cast<ArraySectionExpr>(VarExpr->IgnoreParenImpCasts()))
VarTy = ASE->getElementType();
+ llvm::SmallVector<OpenACCReductionRecipe::CombinerRecipe, 1> CombinerRecipes;
+
+ // We use the 'set-ness' of the alloca-decl to determine whether the combiner
+ // is 'set' or not, so we can skip any attempts at it if we're going to fail
+ // at any of the combiners.
+ if (CreateReductionCombinerRecipe(VarExpr->getBeginLoc(), ReductionOperator,
+ VarTy, CombinerRecipes))
+ return OpenACCReductionRecipeWithStorage::Empty();
+
VarDecl *AllocaDecl = CreateAllocaDecl(
getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),
&getASTContext().Idents.get("openacc.reduction.init"), VarTy);
@@ -2946,5 +2955,163 @@ OpenACCReductionRecipe SemaOpenACC::CreateReductionInitRecipe(
AllocaDecl->setInit(Init.get());
AllocaDecl->setInitStyle(VarDecl::CallInit);
}
- return OpenACCReductionRecipe(AllocaDecl, {});
+
+ return OpenACCReductionRecipeWithStorage(AllocaDecl, CombinerRecipes);
+}
+
+bool SemaOpenACC::CreateReductionCombinerRecipe(
+ SourceLocation Loc, OpenACCReductionOperator ReductionOperator,
+ QualType VarTy,
+ llvm::SmallVectorImpl<OpenACCReductionRecipe::CombinerRecipe>
+ &CombinerRecipes) {
+ // Now we can try to generate the 'combiner' recipe. This is a little
+ // complicated in that if the 'VarTy' is an array type, we want to take its
+ // element type so we can generate that. Additionally, if this is a struct,
+ // we have two options: If there is overloaded operators, we want to take
+ // THOSE, else we want to do the individual elements.
+
+ BinaryOperatorKind BinOp;
+ switch (ReductionOperator) {
+ case OpenACCReductionOperator::Invalid:
+ // This can only happen when there is an error, and since these inits
+ // are used for code generation, we can just ignore/not bother doing any
+ // initialization here.
+ CombinerRecipes.push_back({nullptr, nullptr, nullptr});
+ return false;
+ case OpenACCReductionOperator::Addition:
+ BinOp = BinaryOperatorKind::BO_AddAssign;
+ break;
+ case OpenACCReductionOperator::Multiplication:
+ BinOp = BinaryOperatorKind::BO_MulAssign;
+ break;
+ case OpenACCReductionOperator::BitwiseAnd:
+ BinOp = BinaryOperatorKind::BO_AndAssign;
+ break;
+ case OpenACCReductionOperator::BitwiseOr:
+ BinOp = BinaryOperatorKind::BO_OrAssign;
+ break;
+ case OpenACCReductionOperator::BitwiseXOr:
+ BinOp = BinaryOperatorKind::BO_XorAssign;
+ break;
+
+ case OpenACCReductionOperator::Max:
+ case OpenACCReductionOperator::Min:
+ case OpenACCReductionOperator::And:
+ case OpenACCReductionOperator::Or:
+ // We just want a 'NYI' error in the backend, so leave an empty combiner
+ // recipe, and claim success.
+ CombinerRecipes.push_back({nullptr, nullptr, nullptr});
+ return false;
+ }
+
+ // If VarTy is an array type, at the top level only, we want to do our
+ // compares/decomp/etc at the element level.
+ if (auto *AT = getASTContext().getAsArrayType(VarTy))
+ VarTy = AT->getElementType();
+
+ assert(!VarTy->isArrayType() && "Only 1 level of array allowed");
+
+ auto tryCombiner = [&, this](DeclRefExpr *LHSDRE, DeclRefExpr *RHSDRE,
+ bool IncludeTrap) {
+ // TODO: OpenACC: we have to figure out based on the bin-op how to do the
+ // ones that we can't just use compound operators for. So &&, ||, max, and
+ // min aren't really clear what we could do here.
+ if (IncludeTrap) {
+ // Trap all of the errors here, we'll emit our own at the end.
+ Sema::TentativeAnalysisScope Trap{SemaRef};
+
+ return SemaRef.BuildBinOp(SemaRef.getCurScope(), Loc, BinOp, LHSDRE,
+ RHSDRE,
+ /*ForFoldExpr=*/false);
+ } else {
+ return SemaRef.BuildBinOp(SemaRef.getCurScope(), Loc, BinOp, LHSDRE,
+ RHSDRE,
+ /*ForFoldExpr=*/false);
+ }
+ };
+
+ struct CombinerAttemptTy {
+ VarDecl *LHS;
+ DeclRefExpr *LHSDRE;
+ VarDecl *RHS;
+ DeclRefExpr *RHSDRE;
+ Expr *Op;
+ };
+
+ auto formCombiner = [&, this](QualType Ty) -> CombinerAttemptTy {
+ VarDecl *LHSDecl = CreateAllocaDecl(
+ getASTContext(), SemaRef.getCurContext(), Loc,
+ &getASTContext().Idents.get("openacc.reduction.combiner.lhs"), Ty);
+ auto *LHSDRE = DeclRefExpr::Create(
+ getASTContext(), NestedNameSpecifierLoc{}, SourceLocation{}, LHSDecl,
+ /*ReferstoEnclosingVariableOrCapture=*/false,
+ DeclarationNameInfo{DeclarationName{LHSDecl->getDeclName()},
+ LHSDecl->getBeginLoc()},
+ Ty, clang::VK_LValue, LHSDecl, nullptr, NOUR_None);
+ VarDecl *RHSDecl = CreateAllocaDecl(
+ getASTContext(), SemaRef.getCurContext(), Loc,
+ &getASTContext().Idents.get("openacc.reduction.combiner.lhs"), Ty);
+ auto *RHSDRE = DeclRefExpr::Create(
+ getASTContext(), NestedNameSpecifierLoc{}, SourceLocation{}, RHSDecl,
+ /*ReferstoEnclosingVariableOrCapture=*/false,
+ DeclarationNameInfo{DeclarationName{RHSDecl->getDeclName()},
+ RHSDecl->getBeginLoc()},
+ Ty, clang::VK_LValue, RHSDecl, nullptr, NOUR_None);
+
+ ExprResult BinOpResult = tryCombiner(LHSDRE, RHSDRE, /*IncludeTrap=*/true);
+
+ return {LHSDecl, LHSDRE, RHSDecl, RHSDRE, BinOpResult.get()};
+ };
+
+ CombinerAttemptTy TopLevelCombinerInfo = formCombiner(VarTy);
+
+ if (TopLevelCombinerInfo.Op) {
+ if (!TopLevelCombinerInfo.Op->containsErrors() &&
+ TopLevelCombinerInfo.Op->isInstantiationDependent()) {
+ // If this is instantiation dependent, we're just going to 'give up' here
+ // and count on us to get it right during instantaition.
+ CombinerRecipes.push_back({nullptr, nullptr, nullptr});
+ return false;
+ } else if (!TopLevelCombinerInfo.Op->containsErrors()) {
+ // Else, we succeeded, we can just return this combiner.
+ CombinerRecipes.push_back({TopLevelCombinerInfo.LHS,
+ TopLevelCombinerInfo.RHS,
+ TopLevelCombinerInfo.Op});
+ return false;
+ }
+ }
+
+ // Since the 'root' level didn't fail, the only thing that could be successful
+ // is a struct that we decompose on its individual fields.
+
+ RecordDecl *RD = VarTy->getAsRecordDecl();
+ if (!RD) {
+ Diag(Loc, diag::err_acc_reduction_recipe_no_op) << VarTy;
+ tryCombiner(TopLevelCombinerInfo.LHSDRE, TopLevelCombinerInfo.RHSDRE,
+ /*IncludeTrap=*/false);
+ return true;
+ }
+
+ for (const FieldDecl *FD : RD->fields()) {
+ CombinerAttemptTy FieldCombinerInfo = formCombiner(FD->getType());
+
+ if (!FieldCombinerInfo.Op || FieldCombinerInfo.Op->containsErrors()) {
+ Diag(Loc, diag::err_acc_reduction_recipe_no_op) << FD->getType();
+ Diag(FD->getBeginLoc(), diag::note_acc_reduction_recipe_noop_field) << RD;
+ tryCombiner(FieldCombinerInfo.LHSDRE, FieldCombinerInfo.RHSDRE,
+ /*IncludeTrap=*/false);
+ return true;
+ }
+
+ if (FieldCombinerInfo.Op->isInstantiationDependent()) {
+ // If this is instantiation dependent, we're just going to 'give up' here
+ // and count on us to get it right during instantaition.
+ CombinerRecipes.push_back({nullptr, nullptr, nullptr});
+ } else {
+ CombinerRecipes.push_back(
+ {FieldCombinerInfo.LHS, FieldCombinerInfo.RHS, FieldCombinerInfo.Op});
+ }
+ }
+
+ return false;
}
diff --git a/clang/lib/Sema/SemaOpenACCClause.cpp b/clang/lib/Sema/SemaOpenACCClause.cpp
index 881e960..ead9781 100644
--- a/clang/lib/Sema/SemaOpenACCClause.cpp
+++ b/clang/lib/Sema/SemaOpenACCClause.cpp
@@ -1772,7 +1772,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitReductionClause(
}
SmallVector<Expr *> ValidVars;
- SmallVector<OpenACCReductionRecipe> Recipes;
+ SmallVector<OpenACCReductionRecipeWithStorage> Recipes;
for (Expr *Var : Clause.getVarList()) {
ExprResult Res = SemaRef.CheckReductionVar(Clause.getDirectiveKind(),
@@ -2196,7 +2196,7 @@ OpenACCClause *SemaOpenACC::CheckReductionClause(
ArrayRef<const OpenACCClause *> ExistingClauses,
OpenACCDirectiveKind DirectiveKind, SourceLocation BeginLoc,
SourceLocation LParenLoc, OpenACCReductionOperator ReductionOp,
- ArrayRef<Expr *> Vars, ArrayRef<OpenACCReductionRecipe> Recipes,
+ ArrayRef<Expr *> Vars, ArrayRef<OpenACCReductionRecipeWithStorage> Recipes,
SourceLocation EndLoc) {
if (DirectiveKind == OpenACCDirectiveKind::Loop ||
isOpenACCCombinedDirectiveKind(DirectiveKind)) {
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 0fa21e8..5b5b1b6 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -16491,6 +16491,9 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
case OMPC_ordered:
Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc, LParenLoc, Expr);
break;
+ case OMPC_nowait:
+ Res = ActOnOpenMPNowaitClause(StartLoc, EndLoc, LParenLoc, Expr);
+ break;
case OMPC_priority:
Res = ActOnOpenMPPriorityClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
@@ -16546,7 +16549,6 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
case OMPC_aligned:
case OMPC_copyin:
case OMPC_copyprivate:
- case OMPC_nowait:
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
@@ -17955,7 +17957,9 @@ OMPClause *SemaOpenMP::ActOnOpenMPClause(OpenMPClauseKind Kind,
Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc);
break;
case OMPC_nowait:
- Res = ActOnOpenMPNowaitClause(StartLoc, EndLoc);
+ Res = ActOnOpenMPNowaitClause(StartLoc, EndLoc,
+ /*LParenLoc=*/SourceLocation(),
+ /*Condition=*/nullptr);
break;
case OMPC_untied:
Res = ActOnOpenMPUntiedClause(StartLoc, EndLoc);
@@ -18107,9 +18111,24 @@ OMPClause *SemaOpenMP::ActOnOpenMPClause(OpenMPClauseKind Kind,
}
OMPClause *SemaOpenMP::ActOnOpenMPNowaitClause(SourceLocation StartLoc,
- SourceLocation EndLoc) {
+ SourceLocation EndLoc,
+ SourceLocation LParenLoc,
+ Expr *Condition) {
+ Expr *ValExpr = Condition;
+ if (Condition && LParenLoc.isValid()) {
+ if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
+ !Condition->isInstantiationDependent() &&
+ !Condition->containsUnexpandedParameterPack()) {
+ ExprResult Val = SemaRef.CheckBooleanCondition(StartLoc, Condition);
+ if (Val.isInvalid())
+ return nullptr;
+
+ ValExpr = Val.get();
+ }
+ }
DSAStack->setNowaitRegion();
- return new (getASTContext()) OMPNowaitClause(StartLoc, EndLoc);
+ return new (getASTContext())
+ OMPNowaitClause(ValExpr, StartLoc, LParenLoc, EndLoc);
}
OMPClause *SemaOpenMP::ActOnOpenMPUntiedClause(SourceLocation StartLoc,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 940324b..04a5e4b 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -1865,6 +1865,17 @@ public:
LParenLoc, Num);
}
+ /// Build a new OpenMP 'nowait' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPNowaitClause(Expr *Condition, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().OpenMP().ActOnOpenMPNowaitClause(StartLoc, EndLoc,
+ LParenLoc, Condition);
+ }
+
/// Build a new OpenMP 'private' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
@@ -10612,8 +10623,14 @@ TreeTransform<Derived>::TransformOMPDetachClause(OMPDetachClause *C) {
template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPNowaitClause(OMPNowaitClause *C) {
- // No need to rebuild this clause, no template-dependent parameters.
- return C;
+ ExprResult Cond;
+ if (auto *Condition = C->getCondition()) {
+ Cond = getDerived().TransformExpr(Condition);
+ if (Cond.isInvalid())
+ return nullptr;
+ }
+ return getDerived().RebuildOMPNowaitClause(Cond.get(), C->getBeginLoc(),
+ C->getLParenLoc(), C->getEndLoc());
}
template <typename Derived>
@@ -12374,7 +12391,7 @@ void OpenACCClauseTransform<Derived>::VisitReductionClause(
const OpenACCReductionClause &C) {
SmallVector<Expr *> TransformedVars = VisitVarList(C.getVarList());
SmallVector<Expr *> ValidVars;
- llvm::SmallVector<OpenACCReductionRecipe> Recipes;
+ llvm::SmallVector<OpenACCReductionRecipeWithStorage> Recipes;
for (const auto [Var, OrigRecipe] :
llvm::zip(TransformedVars, C.getRecipes())) {
@@ -12384,7 +12401,7 @@ void OpenACCClauseTransform<Derived>::VisitReductionClause(
ValidVars.push_back(Res.get());
if (OrigRecipe.isSet())
- Recipes.push_back(OrigRecipe);
+ Recipes.emplace_back(OrigRecipe.AllocaDecl, OrigRecipe.CombinerRecipes);
else
Recipes.push_back(Self.getSema().OpenACC().CreateReductionInitRecipe(
C.getReductionOp(), Res.get()));